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

Gradle does not propagate SIGINT to the docker run started by an exec task #8025

Closed
troshko111 opened this issue Dec 12, 2018 · 6 comments
Closed

Comments

@troshko111
Copy link

troshko111 commented Dec 12, 2018

SIGINT normally triggered by Ctrl+C stops the Gradle task execution but any docker run started by the task are left dangling and have to be cleaned up manually.

Expected Behavior

The signal is propagated to all child processes.

Current Behavior

The signal is not propagated to docker run causing the processes to dangle unintentionally.

Context

For my use case, I define a Gradle task which starts a Dockerized proxy server for local development. It is expected that the users run this task manually, as part of the local dev flow. The users should be able to see the proxy stdout and once they're done with it, stop it. The users commonly stop foreground processes by sending a SIGINT via Ctrl-C in the terminal emulator of their choice.

So it goes like this:

  • Work on the code base
  • Run the Gradle task to start the proxy and monitor its logs
    ...
  • Stop the proxy (this is the real intention) via Ctrl-C in the terminal emulator. This does not stop the proxy but only the Gradle execution.

Steps to Reproduce (for bugs)

Define an exec task to spawn a long-running process

task runContainer(type: Exec) {
  description "Minimal repro for dangling processes."

  commandLine = ["docker", "run", "-t", "python:3.7.1-alpine"]
}

./gradlew runContainer
Ctrl+C
docker container list

CONTAINER ID        IMAGE                 COMMAND             CREATED             STATUS              PORTS               NAMES
9f5cd56fcb69        python:3.7.1-alpine   "python3"           55 seconds ago      Up 55 seconds                           goofy_kare

./gradlew runContainer --no-daemon
(same as the above)

Your Environment

./gradlew --version

------------------------------------------------------------
Gradle 4.10.2
------------------------------------------------------------

Build time:   2018-09-19 18:10:15 UTC
Revision:     b4d8d5d170bb4ba516e88d7fe5647e2323d791dd

Kotlin DSL:   1.0-rc-6
Kotlin:       1.2.61
Groovy:       2.4.15
Ant:          Apache Ant(TM) version 1.9.11 compiled on March 23 2018
JVM:          1.8.0_181 (Oracle Corporation 25.181-b15)
OS:           Linux 4.18.5-200.fc28.x86_64 amd64

Additional context

I've tried to repro this with a simple program like sleep

task runProcess(type: Exec) {
  description "Minimal repro for dangling processes."

  commandLine = ["sleep", "600"]
}

But it won't repro. Right now I can only repro this with docker run -t.

@troshko111 troshko111 changed the title Gradle does not propagate SIGINT to the process spawned by an exec task Gradle does not propagate SIGINT to the docker run started by an exec task Dec 12, 2018
@troshko111
Copy link
Author

troshko111 commented Dec 12, 2018

I've done some further investigation and even though imo it's unexpected, this is what Docker is doing:

If you attach a pseudo-TTY (-t) when running a container, Ctrl-C detaches from the container, but does not terminate it.

If you also open stdin, (-i) in addition to attaching a pseudo-TTY, Ctrl-C terminates the container.

The problem is, that when running from a Gradle task, Gradle does not allocate a pseudo-TTY for the spawned processes (and it's not a problem per se), so Docker gives you

the input device is not a TTY

All in all this is entirely Docker specific behavior, that's why it did not repro with any other program handling signals. Closing this, I'll try to comment providing a work around if I come up with something semi-decent.

Background: moby/moby#2838

@troshko111
Copy link
Author

I've spent a bit more time with this problem and actually there seems to be some issue with signal propagation when Gradle daemon is involved, consider this minimal repro:

task repro() {
  doLast {
    def cmd  = '''trap 'docker stop \$(docker ps -a -q)' TERM INT EXIT && docker run -t --rm --init python:3.7.1-alpine & wait'''

    def p = ["/bin/bash", "-c", cmd].execute()
    p.consumeProcessOutput(System.out, System.err)
    p.waitFor()
  }
}

The task starts a sub-shell and defines a trap for TERM/INT/EXIT signals so that it can stop the Docker container on any of these signals. This works around the original problem of not being able to terminate the container started via a Gradle task by Ctrl-C. Now if you run this task without the daemon (--no-daemon) , it traps the signal and stops Docker containers, if you run with the daemon, the task seems to be running.

@stale
Copy link

stale bot commented Aug 6, 2020

This issue has been automatically marked as stale because it has not had recent activity. Given the limited bandwidth of the team, it will be automatically closed if no further activity occurs. If you're interested in how we try to keep the backlog in a healthy state, please read our blog post on how we refine our backlog. If you feel this is something you could contribute, please have a look at our Contributor Guide. Thank you for your contribution.

@stale stale bot added the stale label Aug 6, 2020
@stale
Copy link

stale bot commented Aug 27, 2020

This issue has been automatically closed due to inactivity. If you can reproduce this on a recent version of Gradle or if you have a good use case for this feature, please feel free to reopen the issue with steps to reproduce, a quick explanation of your use case or a high-quality pull request.

@stale stale bot closed this as completed Aug 27, 2020
@rsampaths16
Copy link

Have same problem that Gradle isn't propagating SIGINT to sub-process: Shutdownhook isn't being triggered because of this.

https://stackoverflow.com/questions/64195246/how-to-send-ctrlc-sigint-signal-to-gradle-javaexec-task-type-forked-jvm

@infvie
Copy link

infvie commented Jan 7, 2022

A simple and crappy work around is that I still used gradle to build my jar, but I still execute my process using java cli instead of gradle. This propagated my sigterm with no issue for my queue for my ec2 instances.

@wolfs wolfs closed this as not planned Won't fix, can't repro, duplicate, stale Sep 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants