You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There are a bunch of issues related to how just handles signals. I've been trying to figure out what they are, so I created this issue to collect all the information in one place, and summarize what's going on.
Way back in 2018, in #302, @bheisler opened an issue that just was not waiting for child processes to exit on CTRL-C (which sends SIGINT). This would cause them to be orphaned, and continue writing output to the terminal, and have to be cleaned up manually.
In response to #302, I merged #345, which made just ignore SIGINT, SIGHUP, and SIGTERM while running commands. SIGINT is CTRL-C, SIGHUP is sent when you close the terminal ("hup" is for "hangup"), and SIGTERM is the signal which the kill command sends by default.
This gave just the behavior it has now. When running a long-running command, for example sleep 60, if you hit CTRL-C, just will ignore the generated SIGINT signal, but, depending on your terminal or setup, hitting CTRL-C sends SIGINT to all processes in the foreground process group, so sleep 60 will receive SIGINT which will terminate it, just will see it was terminated with a signal, and just will return with an error reporting that it terminated with a signal.
There appear to be a number of issues with this behavior, reported in:
I'm not entirely sure what's going on here. When you do sleep 60 under just, CTRL-C gets sent to just, which ignores it, but also gets sent to sleep 60, which terminates it.
What's going on in this case? Why isn't CTRL-C getting sent to the gcloud command? When CTRL-C is hit, it is the system (some combination of the kernel, shell, terminal) which arranges to send SIGINT to the relevant processes, so I'm not sure what just could be doing to interfere with this.
Trap signals? #1560 by @OJFord. I'm not sure what's going on here, because the signals mentioned are SIGUSR1, and SIGINFO (generated by CTRL-T), which I don't think just touches at all. However, @stefanchrobot mentions that his app terminates when it receives SIGTERM, but nothing happens if the same command is run under just.
SIGHUP seems to not be propagated to inner child processes #1781 by @davoclavo. Here, just is not responding to SIGHUP. This is expected, because just ignores these signals while running child processes. This isn't necessarily bad, because in the normal case, SIGHUP is sent to all members of the process group, which should terminate the child and cause it to exit.
Improve signal/interrupt handling #1803 PR by @davoclavo. Reworks the signal handler to actively poll for new signals, and terminate the child when it receives one. Never got merged, I think due it being hard to implement/test on Windows.
I'll also summarize what I know about signals, which may be wildly off.
The relevant signals are:
SIGHUP Sent when the terminal is closed.
SIGINT Sent on CTRL-C.
SIGTERM Sent by default by the kill command.
Currently, just running sleep 60, will close when you hit CTRL-C or close the terminal. This is, I believe, because CTRL-C and closing the terminal not only send the signal to the foreground process, but also to members of the foreground process group. So just ignores the SIGHUP or SIGINT signal, but sleep receives it and terminates, so just, which is waiting for it, sees that it has stopped and terminates it as well.
If you generate SIGHUP, SIGINT, or SIGTERM manually, with kill -s HUP/INT/TERM and send it to just, nothing will happen, because only just is receiving the signal, not the child sleep process.
I think the fact that in some cases, a signal is sent to a single process, and in some cases, all members of a process group, causes confusion, since it means that a SIGINT generated by a CTRL-C will have a different effect from one generated by the kill command, even though it's the same signal.
As far as I know, a parent process is not responsible for "forwarding" signals to child processes, it's the terminal / system which does this, so I don't think just is interfering with that. (The only possible exception to this is the process signal mask, which indicates some signals that should be ignored, and which is inherited by child processes. However, just does not set the signal mask, so this should not be an issue.)
Also, I don't know how this varies between different setups, because there are a lot of variables.
Do different terminals handle this differently?
What even happens on Windows? Can you CTRL-C just at all on Windows?
What about shell background jobs? I.e., just &?
What about tmux, zellij, dtach, etc?
Here are my current questions:
When is ignoring SIGINT and SIGHUP, just's current behavior, desirable? If SIGINT and SIGHUP are sent with CTRL-C or closing the terminal, they should be sent to all children, and thus everything should get cleaned up. I think it would only be in the case of child processes which don't handle these signals that anything doesn't get cleaned up, so a reasonable argument might be that just shouldn't try to handle this, and it's the fault of the child processes that they aren't responding to these signals.
When is ignoring SIGTERM, just's current behavior, desirable? This is a bit different from SIGINT and SIGHUP, since SIGTERM, when sent with kill $JUST_PID, is not sent to child processes, so if just exited, it would leave behind child processes.
How can I reproduce examples of just processes not terminating when they should? An example from SIGHUP seems to not be propagated to inner child processes #1781 is with zellij, but I wasn't able to reproduce this. If I create a zellij session, open two tabs, run just with a recipe that calls just sleep, and then close the tab, just sleep is not left running in the background.
just ignores SIGINT and SIGHUP. As far as I can tell, this is fine, since SIGINT and SIGHUP should be sent to child processes on CTRL-C and terminal close, so just can just ignore them and wait for children to exit. Are there cases when this is problematic?
just ignores SIGTERM, which is sent by kill. As far as I know, this signal only gets sent to just, so it may be surprising that it doesn't stop just. Should we change just to forward SIGTERM to child processes, so that kill $JUST_PID will cause just to exit? (Assuming that child processes respond to SIGTERM by exiting.)
My current thoughts are:
I think that just should probably not ignore SIGINT and SIGHUP. These signals are generated by CTRL-C and closing the terminal, respectively, and should be sent to children of just as well. So, unless something is wrong, just and all children should exit, which is what the user wants.
I think that just should probably either ignore SIGTERM, or forward it to any running child processes. If the user runs kill $JUST_PID, this only sends SIGTERM to just, so if it exits, it will leave child processes behind.
I think the original reason for ignoring SIGINT was not necessarily a good one. In that particular use-case, just was being used to run a test runner which would interpret CTRL-C as a failed test, but continue with further tests. So if just ignored CTRL-C, you could hold it down and it would eventually run out of tests to run and exit. However, most programs exit immediately on CTRL-C, so I don't think it makes sense to optimize for the case that CTRL-C doesn't terminate child processes.
(Sorry for tagging a bunch of people! I wanted to make sure people were aware of the new issue. Feel free to unsubscribe!)
There are a bunch of issues related to how
justhandles signals. I've been trying to figure out what they are, so I created this issue to collect all the information in one place, and summarize what's going on.Way back in 2018, in #302, @bheisler opened an issue that
justwas not waiting for child processes to exit on CTRL-C (which sendsSIGINT). This would cause them to be orphaned, and continue writing output to the terminal, and have to be cleaned up manually.In response to #302, I merged #345, which made just ignore
SIGINT,SIGHUP, andSIGTERMwhile running commands.SIGINTis CTRL-C,SIGHUPis sent when you close the terminal ("hup" is for "hangup"), andSIGTERMis the signal which thekillcommand sends by default.This gave
justthe behavior it has now. When running a long-running command, for examplesleep 60, if you hitCTRL-C,justwill ignore the generatedSIGINTsignal, but, depending on your terminal or setup, hittingCTRL-CsendsSIGINTto all processes in the foreground process group, sosleep 60will receiveSIGINTwhich will terminate it,justwill see it was terminated with a signal, andjustwill return with an error reporting that it terminated with a signal.There appear to be a number of issues with this behavior, reported in:
Running Firestore Emulator From Just Prevents Control C #1558 by @LLBlumire. Here,
justis used to rungcloud emulators firestore start. Whengcloud emulators firestore startis run on its own,CTRL-Cstops it, but when run underjust,CTRL-Cdoes nothing.I'm not entirely sure what's going on here. When you do
sleep 60underjust,CTRL-Cgets sent tojust, which ignores it, but also gets sent tosleep 60, which terminates it.What's going on in this case? Why isn't
CTRL-Cgetting sent to thegcloudcommand? WhenCTRL-Cis hit, it is the system (some combination of the kernel, shell, terminal) which arranges to sendSIGINTto the relevant processes, so I'm not sure whatjustcould be doing to interfere with this.Trap signals? #1560 by @OJFord. I'm not sure what's going on here, because the signals mentioned are
SIGUSR1, andSIGINFO(generated byCTRL-T), which I don't thinkjusttouches at all. However, @stefanchrobot mentions that his app terminates when it receivesSIGTERM, but nothing happens if the same command is run underjust.SIGHUP seems to not be propagated to inner child processes #1781 by @davoclavo. Here,
justis not responding toSIGHUP. This is expected, becausejustignores these signals while running child processes. This isn't necessarily bad, because in the normal case,SIGHUPis sent to all members of the process group, which should terminate the child and cause it to exit.Improve signal/interrupt handling #1803 PR by @davoclavo. Reworks the signal handler to actively poll for new signals, and terminate the child when it receives one. Never got merged, I think due it being hard to implement/test on Windows.
I'll also summarize what I know about signals, which may be wildly off.
The relevant signals are:
SIGHUPSent when the terminal is closed.SIGINTSent on CTRL-C.SIGTERMSent by default by thekillcommand.Currently,
justrunningsleep 60, will close when you hit CTRL-C or close the terminal. This is, I believe, because CTRL-C and closing the terminal not only send the signal to the foreground process, but also to members of the foreground process group. So just ignores theSIGHUPorSIGINTsignal, butsleepreceives it and terminates, sojust, which is waiting for it, sees that it has stopped and terminates it as well.If you generate
SIGHUP,SIGINT, orSIGTERMmanually, withkill -s HUP/INT/TERMand send it tojust, nothing will happen, because onlyjustis receiving the signal, not the childsleepprocess.I think the fact that in some cases, a signal is sent to a single process, and in some cases, all members of a process group, causes confusion, since it means that a
SIGINTgenerated by a CTRL-C will have a different effect from one generated by thekillcommand, even though it's the same signal.As far as I know, a parent process is not responsible for "forwarding" signals to child processes, it's the terminal / system which does this, so I don't think
justis interfering with that. (The only possible exception to this is the process signal mask, which indicates some signals that should be ignored, and which is inherited by child processes. However,justdoes not set the signal mask, so this should not be an issue.)Also, I don't know how this varies between different setups, because there are a lot of variables.
justat all on Windows?just &?tmux,zellij,dtach, etc?Here are my current questions:
When is ignoring
SIGINTandSIGHUP,just's current behavior, desirable? IfSIGINTandSIGHUPare sent withCTRL-Cor closing the terminal, they should be sent to all children, and thus everything should get cleaned up. I think it would only be in the case of child processes which don't handle these signals that anything doesn't get cleaned up, so a reasonable argument might be thatjustshouldn't try to handle this, and it's the fault of the child processes that they aren't responding to these signals.When is ignoring
SIGTERM,just's current behavior, desirable? This is a bit different fromSIGINTandSIGHUP, sinceSIGTERM, when sent withkill $JUST_PID, is not sent to child processes, so ifjustexited, it would leave behind child processes.How can I reproduce examples of
justprocesses not terminating when they should? An example from SIGHUP seems to not be propagated to inner child processes #1781 is withzellij, but I wasn't able to reproduce this. If I create azellijsession, open two tabs, runjustwith a recipe that callsjust sleep, and then close the tab,just sleepis not left running in the background.justignoresSIGINTandSIGHUP. As far as I can tell, this is fine, sinceSIGINTandSIGHUPshould be sent to child processes onCTRL-Cand terminal close, sojustcan just ignore them and wait for children to exit. Are there cases when this is problematic?justignoresSIGTERM, which is sent bykill. As far as I know, this signal only gets sent tojust, so it may be surprising that it doesn't stopjust. Should we changejustto forwardSIGTERMto child processes, so thatkill $JUST_PIDwill causejustto exit? (Assuming that child processes respond toSIGTERMby exiting.)My current thoughts are:
I think that
justshould probably not ignoreSIGINTandSIGHUP. These signals are generated byCTRL-Cand closing the terminal, respectively, and should be sent to children ofjustas well. So, unless something is wrong,justand all children should exit, which is what the user wants.I think that
justshould probably either ignoreSIGTERM, or forward it to any running child processes. If the user runskill $JUST_PID, this only sendsSIGTERMtojust, so if it exits, it will leave child processes behind.I think the original reason for ignoring
SIGINTwas not necessarily a good one. In that particular use-case,justwas being used to run a test runner which would interpretCTRL-Cas a failed test, but continue with further tests. So ifjustignoredCTRL-C, you could hold it down and it would eventually run out of tests to run and exit. However, most programs exit immediately onCTRL-C, so I don't think it makes sense to optimize for the case thatCTRL-Cdoesn't terminate child processes.(Sorry for tagging a bunch of people! I wanted to make sure people were aware of the new issue. Feel free to unsubscribe!)