Hi - I recently discovered go-task. Overall this is pretty impressive! I am utilizing go-task as a makefile replacement on a repository that builds packer (another great go project) images. In the process I have discovered that go-task does not proxy unix signals to child processes. This presents an issue when the task that go-task is running needs to do clean up. For example, when the packer process receives SIGINT (ctrl+c) it will stop what is it doing and execute its cleanup actions so as not to leave random artifacts of half build VMs. Having go-task handle signals in the following way would help to address this issue:
As a bonus, if go-task receives SIGINT or SIGTERM more than once, it should exit immediately.
How do you handle the case where multiple child-processes are run concurrently through dependenceies?
@smyrman That is an interesting question. I have not thought about this deeply nor have I had the need to deal with parallel termination. Assuming that the parallel processes are not dependent on each other (i.e. they are not doing some sort of IPC or being run as daemons of sorts for use by other processes in the parallel stack) it might be reasonable to do the following:
4a. Be like go, Exit with 1. When go traps either SIGINT or SIGTERM it's exit code will always be 1 to indicate abnormal termination.
4.b Be like bash, gnu parallel and the like: Exit with 128 + the signal number. SIGINT = 130, SIGTERM = 143.
IMHO 4b is probably the right choice.
I don't suppose you would be interesting in trying a PR? There might be need for some clean-up of the code to get to the stage where it's easy to add. This is a good file to start looking at:
/cc @mvdan
Sorry for pinging you again. Do you have any idea if it's possible to send a SIGINT to a process run by the interp?
Today Task only cancels the context and forget about it. I think this will just kill the process.
I haven't thought about signals at all, and nothing is done about them at the moment. But I knew it would become an issue at some point.
At the moment, interp itself just fires goroutines, it of course can't and doesn't fork any processes directly. The only child processes come from os/exec. So the first question to answer would be - what happens when a simple Go program forks a process via os/exec and receives SIGINT? Does the child also receive it? Is there any way to pass the signals on?
If it is possible in a simple program, it is also likely possible in interp somehow. Perhaps it should be configurable in some way.
Thanks @mvdan
Seems that the context cancelation calls os.Process.Kill which kills the process.
There's os.Process.Signal. I think it's possible to hook the Context to call that instead of passing the context to os/exec.
I don't know if it's worth the complexity, or if it's a good fit for the rest of the code base, but if you think _global exit handler_ would be the right abstraction, you may look at:
@andreynering if you would like to give that a try and submit a patch, I'd be happy to review. It would be best for the solution to not be global, although I'm not sure if that is possible given that signals are per-process and not per-goroutine.
Now merged - thanks! Will release 2.1 soon, but you can vendor an updated master as you've been doing.
@pmorton Let us know if the recent changes improved this use case for you.