Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass SIGINT to spawned process #387

Closed
raphCode opened this issue Sep 5, 2022 · 8 comments
Closed

Pass SIGINT to spawned process #387

raphCode opened this issue Sep 5, 2022 · 8 comments
Labels
new feature Requests or requires a new feature

Comments

@raphCode
Copy link

raphCode commented Sep 5, 2022

Right now, it seems watchexec exits on receiving SIGINT / Ctrl-C.
It would be nice to include an Option to pass SIGINT to the running process.
My usecase is restarting a debugger (pudb3, python debugger) upon code changes. When running the application in a debugger, it is not uncommon to press Ctrl-C to interrupt it and get back into the debugger. With watchexec this is no longer possible since it kills the whole debugger.

OS: Arch Linux
watchexec 1.20.5

@raphCode raphCode added the bug Something's not right! label Sep 5, 2022
@passcod passcod added bug Something's not right! new feature Requests or requires a new feature and removed bug Something's not right! labels Sep 5, 2022
@matu3ba
Copy link

matu3ba commented Sep 19, 2022

Signaling + restarting processess sounds more like a job for a process supervision framework, which sounds out of scope for a file watcher.

If you need something like this, try either systemd or more leightweight alternatives (both alpha status): dinit and s6.

Think about the case of SIGINT not being successful, which needs to be handled with logic.

@raphCode
Copy link
Author

raphCode commented Oct 5, 2022

Is the idea to nest them like so:
Process supervision > watchexec > application
And then have the Process supervision framework forwarding signals either to watchexec or the application?

Do you have any experience with this / can you elaborate how this would be done?

@matu3ba
Copy link

matu3ba commented Oct 6, 2022

And then have the Process supervision framework forwarding signals either to watchexec or the application?

Yes.

Do you have any experience with this / can you elaborate how this would be done?

All of those projects have a friendly mailing lists or IRC. As far as I remember, dinit and s6 also support user-space execution.
However, so far I did not have a use case for them other than messing around a bit with Artix Linux.

@passcod
Copy link
Member

passcod commented Oct 7, 2022

Just going to say that this is entirely possible at the watchexec level and in fact rather trivial to implement, I'm just not actively working on it. If you want to contribute it, you'd need to:

  1. think about how to exit watchexec without having Ctrl-C
  2. add an option to opt into the behaviour
  3. use that option to change the behaviour when a sigint is received, here:

https://github.com/watchexec/watchexec/blob/main/crates/cli/src/config/runtime.rs#L118-L121

happy to review a PR that does this

@raphCode
Copy link
Author

raphCode commented Oct 7, 2022

  1. think about how to exit watchexec without having Ctrl-C

Would it be an acceptable way to accomplish this utilizing the shell's job control? Like suspending the process group with Ctrl-Z and then killing it?
This would need to address #386 as well, so maybe we can kill two birds with one stone?

@passcod
Copy link
Member

passcod commented Oct 7, 2022

#386 is a little more complicated to do (need to add handling for the signal in the library crate, and then handle it properly). It's important to note watchexec deliberately creates process groups for the spawned commands, which is why Ctrl-Z doesn't suspend the child processes.

Probably a better way of handling this would be to track if a Ctrl-C has been seen before without another event intervening, and exit watchexec if a second one is seen. That way hitting Ctrl-C once would interrupt the inner process, and hitting it twice in close succession would end watchexec itself. This is similar to how some specialised shells work, like Node.js.

@unphased
Copy link

unphased commented May 26, 2023

I just tried this and it's really very straightforward.

You set up two loops to make this work. The first loop is something like while sleep 0.1; do gdb & echo $! > gdb_pid; fg %1; done, I tested it and it does work, it gives you a fully interactive gdb. Exiting in here interactively just starts it over. You can just hit ctrl+d, ctrl+c to quit (and make the sleep slower if it's too hard).

In a second terminal (trying to unify this approach into a single terminal is an exercise for the reader, good luck) run something like watchexec -- 'make && kill -TERM $(cat gdb_pid)'

I thought it was going to involve a lot more hackery than this. The only wrinkle I have is %1 doesn't expand properly for zsh but that's easily rectified by running the first loop under bash -c.

You will have two terminals, one that has the watchexec running in which you can see compilation output, and the other one runs your debugger which only gets rudely interrupted if the automatically triggered build succeeds.


I actually came here looking for something similar but not the same: the software I'm building now does not have a process management test runner yet and involves IPC and one long-running process. This is coordinated by a shell script and uses a pid file to clean up the long running process when the script is triggered by watchexec, but when watchexec is terminated there is no way to make the long running process quit also because the script that launched it already exited. The simple solution to this is just to make the wrapper script wait on the long running script so that signals get propagated down. I think. Still have to figure out how to make it work, but in the worst case it is no more complex than the scheme described above.

Update: I tried for way too long to make it work. I was trying to run the build and run a long running process all as part of the thing that watchexec runs, which works in theory but It seems like it's often impossible to convince watchexec to honor gitignore content in the right way (so that it doesn't interrupt the thing launching the build by catching something changing due to a build happening), and besides, there are often ephemeral randomly named temp files which will potentially also trigger it to run. The scheme of trying to keep it all working inside a single terminal involves using --on-busy-update signal but in practice it's very difficult to use because you do not have the benefit of controlling whether to actually trigger the signal or not, so the script will be getting interrupted too early to work properly (or not at all). Hence the above described dual terminal scheme where you control whether to fire the signal into a second independent loop is definitely the ticket.

@passcod
Copy link
Member

passcod commented Dec 9, 2023

The OP request is now possible with --map-signal INT:INT.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature Requests or requires a new feature
Projects
None yet
Development

No branches or pull requests

4 participants