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

In 1.24.0, ctrl+c no longer interrupts the child process #716

Open
kentonv opened this issue Dec 10, 2023 · 12 comments · Fixed by #721
Open

In 1.24.0, ctrl+c no longer interrupts the child process #716

kentonv opened this issue Dec 10, 2023 · 12 comments · Fixed by #721
Labels
bug Something's not right! need repro Needs a reproduction and some investigation

Comments

@kentonv
Copy link

kentonv commented Dec 10, 2023

watchexec v1.24.0 on Linux

Prior to this version, when I pressed ctrl+c, both watchexec and the program running under it would be termintaed.

As of 1.24, only watchexec is terminated. The inner program continues to run, including writing text to the terminal even though the shell has already presented me with a prompt.

If I use the new feature --map-signal INT:INT, then the problem is the opposite: ctrl+c interrupts the inner program, but does not terminate watchexec, and indeed it's unclear how watchexec can be terminated in this case without killing it from a separate terminal.

I think the right default is for both watchexec and the inner program to be terminated on ctrl+c. This is normally what I want.

@kentonv kentonv added the bug Something's not right! label Dec 10, 2023
@passcod
Copy link
Member

passcod commented Dec 10, 2023

Hmm. Yeah, that is a regression; I'm surprised I didn't catch it during testing. Maybe I introduced it late. I'll have a look.

The --map-signal INT:INT behaviour is expected, indeed I call that (making it hard to exit Watchexec) out in the help text for it.

passcod added a commit that referenced this issue Dec 11, 2023
Fixes #716 by also waiting for processes to quit
@passcod
Copy link
Member

passcod commented Dec 11, 2023

Got a fix up, will release later today with your other regression.

@kentonv
Copy link
Author

kentonv commented Dec 21, 2023

I got a chance to test out this version and it's better but not quite right.

Specifically, if the inner command catches the ctrl+c and does not exit immediately, watchexec still does exit immediately, once again creating the awkward situation where I'm at my shell prompt but the command I had run is still writing to the terminal. In particular, Bazel interprets ctrl+c as a request to stop the build, but in some cases waits for in-flight jobs to finish before it actually exits.

I think watchexec needs to wait for the inner command to exit before exiting itself.

(Thanks for the partial fix though! The severity of the problem is definitely much reduced.)

@passcod
Copy link
Member

passcod commented Dec 21, 2023

Hmm is that with latest watchexec? It should sigterm, print [Waiting 60s for processes to finish...] and do that before sigkilling, does that not happen?

@kentonv
Copy link
Author

kentonv commented Dec 22, 2023

It's with 1.24.2, which is what cargo install watchexec-cli gave me as of yesterday.

@passcod
Copy link
Member

passcod commented Dec 22, 2023

Can you provide a log? I can't replicate that

@passcod passcod added the need repro Needs a reproduction and some investigation label Dec 22, 2023
@passcod passcod reopened this Dec 22, 2023
@kentonv
Copy link
Author

kentonv commented Dec 22, 2023

Hmm, the log looks like it legitimately waited for the subprocess (see below).

But in this test, bazel's final output definitely landed on the terminal after the shell wrote the prompt. (Only an instant after, but I can tell because the cursor is in the wrong place.)

I guess it's possible that this is bazel's fault, maybe it has a background process running still that writes that final output. However, I don't see the same behavior when running bazel without watchexec -- in that case bazel's output finishes before the prompt is written.

One thought: When you forward the signal to the child process, do you deliver it to the child's entire process group, or only to the direct child process? The shell would normally deliver to the whole group.

{"timestamp":"2023-12-22T22:02:30.075674Z","level":"DEBUG","fields":{"message":"received unix signal","sig":"Interrupt"},"target":"watchexec::sources::signal"}
{"timestamp":"2023-12-22T22:02:30.075740Z","level":"DEBUG","fields":{"message":"running action handler"},"target":"watchexec::action::worker"}
{"timestamp":"2023-12-22T22:02:30.075758Z","level":"DEBUG","fields":{"message":"unmapped terminate or interrupt signal, quit"},"target":"watchexec_cli::config"}
{"timestamp":"2023-12-22T22:02:30.075778Z","level":"DEBUG","fields":{"message":"take control of new tasks"},"target":"watchexec::action::worker"}
{"timestamp":"2023-12-22T22:02:30.075783Z","level":"DEBUG","fields":{"message":"quitting worker","manner":"Graceful { signal: Terminate, grace: 60s }"},"target":"watchexec::action::worker"}
{"timestamp":"2023-12-22T22:02:30.075791Z","level":"DEBUG","fields":{"message":"quitting worker gracefully","signal":"Terminate","grace":"60s"},"target":"watchexec::action::worker"}
{"timestamp":"2023-12-22T22:02:30.075813Z","level":"DEBUG","fields":{"message":"waiting for graceful shutdown tasks"},"target":"watchexec::action::worker"}
{"timestamp":"2023-12-22T22:02:30.078864Z","level":"DEBUG","fields":{"message":"waiting for job tasks to end"},"target":"watchexec::action::worker"}
{"timestamp":"2023-12-22T22:02:30.078909Z","level":"DEBUG","fields":{"message":"action worker finished"},"target":"watchexec::action::worker"}
{"timestamp":"2023-12-22T22:02:30.078929Z","level":"DEBUG","fields":{"message":"action worker exited, ending watchexec"},"target":"watchexec::watchexec"}
{"timestamp":"2023-12-22T22:02:30.078934Z","level":"DEBUG","fields":{"message":"main task graceful exit"},"target":"watchexec::watchexec"}
{"timestamp":"2023-12-22T22:02:30.079138Z","level":"INFO","fields":{"message":"done with main loop"},"target":"watchexec_cli"}

@passcod
Copy link
Member

passcod commented Dec 23, 2023

On unix it calls killpg(3)

@passcod
Copy link
Member

passcod commented Dec 23, 2023

If you call with -vvvv does it provide more of a hint as to what's happening?

Another thing might be that it runs with sh and bazel may behave better without (with -n)?

@3rd
Copy link

3rd commented Jan 26, 2024

just a note if someone else hits this: --no-process-group fixes it and another issue where it doesn't actually run the command and it doesn't output anything

@thomasf
Copy link

thomasf commented Feb 15, 2024

just a note if someone else hits this: --no-process-group fixes it and another issue where it doesn't actually run the command and it doesn't output anything

thanks for this, running docker exec ... didn't output anything for me after upgrading watchexec until I ran it with that flag.

@cpick
Copy link

cpick commented Feb 27, 2024

just a note if someone else hits this: --no-process-group fixes it and another issue where it doesn't actually run the command and it doesn't output anything

thanks for this, running docker exec ... didn't output anything for me after upgrading watchexec until I ran it with that flag.

I believe the root cause of this issue is described here: #743 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something's not right! need repro Needs a reproduction and some investigation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants