I need to run a process, do something while it is running, and finally terminate it. The
process in question writes things to standard output that I would like to retain. Unfortunately,
it seems that the process dies before I can connect and extract its last words. Having scarce
experience with asynchronous programming, I am having a difficulty finding a nice solution. It
would be fortunate if I can accomplish this task within the framework of RIO.Process
, although I
am prepared to step outside of it if it cannot be avoided. (Note that RIO
employs an unusual
way of invoking external processes via a callback system.)
Below is a highly simplified runnable example of what I am trying to achieve.
Here is an emulation of the program to be run:
(Put it in a file called x.sh
and say chmod +x x.sh
to make it executable.)
#!/bin/sh
trap 'echo "Terminating..."; exit 0' TERM
echo "Initialization complete."
while true; do sleep 1; done
Here is my code:
(Put it in a file called X.hs
and compile with ghc -package rio X.hs
.)
{-# language NoImplicitPrelude #-}
{-# language BlockArguments #-}
{-# language OverloadedStrings #-}
module Main where
import RIO
import RIO.Process
import Data.Text.IO (hGetContents, hGetLine)
main :: IO ()
main = runSimpleApp do
proc "./x.sh" [ ]
\processConfig -> withProcessWait_ (setStdout createPipe processConfig)
\processHandle -> bracket_
(initialize processHandle)
(terminate processHandle)
(return ())
initialize :: (HasProcessContext env, HasLogFunc env) => Process () Handle () -> RIO env ()
initialize processHandle = do
x <- liftIO $ hGetLine (getStdout processHandle)
if x == "Initialization complete." then return () else error "This should not happen."
terminate :: HasLogFunc env => Process () Handle () -> RIO env ()
terminate processHandle = do
log' <- async $ liftIO $ hGetContents (getStdout processHandle)
stopProcess processHandle
log <- wait log'
logInfo $ display log
Here is what happens:
% ./X
X: fd:3: hGetBuffering: illegal operation (handle is closed)
— x.sh
is saying something, but I cannot hear.
What is the right way to manage this?