obelisk icon indicating copy to clipboard operation
obelisk copied to clipboard

ob run: Child processes are orphaned on SIGHUP

Open plt-amy opened this issue 3 years ago • 2 comments

(On Linux,) when terminating ob run with SIGHUP - e.g. because your terminal is being closed - the child ghcid process stays alive, and keeps the port occupied. Repro is essentially:

$ ob run # in basically any obelisk project
[...]
Frontend running on http://localhost:8000/

Then pkill -SIGHUP ob and verify that ghcid is still running, e.g. with pgrep or simply by causing a reload and verifying that the frontend is still running/updating:

$ pgrep ghcid
257475
$ pkill -SIGHUP ob
$ pgrep ghcid
257475

I think it'd be more natural for the ghcid process to be terminated when ob run is killed with SIGHUP, just like it's terminated when ob run is killed with SIGTERM.

plt-amy avatar Jan 25 '22 16:01 plt-amy

Similar issue: #633

mankyKitty avatar Jul 01 '22 14:07 mankyKitty

Looking into this some more. (Caveat: I don't know much about process handling.)

Something interesting I noticed in that SIGHUP'ing the ghcid process rather than the Obelisk process leads to the same behavior, leaving behind a ghc process like above. Does that mean could be a ghcid problem?

The runGhcid' function uses Obelisk.Command.Project.nixShellWithoutPkgs. Inlining runProcess_` there looks like this:

nixShellWithoutPkgs
  :: MonadObelisk m
  => FilePath -- ^ Path to project root
  -> Bool -- ^ Should this be a pure shell?
  -> Bool -- ^ Should we chdir to the package root in the shell?
  -> Map Text FilePath -- ^ Package names mapped to their paths
  -> String -- ^ Shell attribute to use (e.g. @"ghc"@, @"ghcjs"@, etc.)
  -> Maybe String -- ^ If 'Just' run the given command; otherwise just open the interactive shell
  -> m ()
nixShellWithoutPkgs root isPure chdirToRoot packageNamesAndPaths shellAttr command = do
  pc <- mkObNixShellProc root isPure chdirToRoot packageNamesAndPaths shellAttr command
  bracketOnError
    (createProcess pc)
    (liftIO . Proc.cleanupProcess)
    (\((_, _, _, ph)) -> throwExitCode pc =<< waitForProcess ph)

Changing cleanupProcess to terminateProcess or terminating the process in a SIGHUP handler doesn't change the fact that the ghc process is left:


This is as far as I got before running out of ideas. 
     (\((_, _, _, ph)) -> do
        liftIO $ installHandler 1 (CatchInfo (\_ -> Proc.terminateProcess ph)) Nothing
        throwExitCode pc =<< waitForProcess ph)

parenthetical avatar Feb 10 '23 21:02 parenthetical