Skip to content

Commit

Permalink
forward signals in restart wrapper (tilt-dev#586)
Browse files Browse the repository at this point in the history
* Forward signals in restart wrapper

Signed-off-by: Jared A. Scheel <[email protected]>

* restart_process: Prevent race, add additional room to buffered channel

* restart_process: update image

Signed-off-by: Nick Santos <[email protected]>

---------

Signed-off-by: Jared A. Scheel <[email protected]>
Signed-off-by: Nick Santos <[email protected]>
Co-authored-by: Jared A. Scheel <[email protected]>
Co-authored-by: Travis Cline <[email protected]>
  • Loading branch information
3 people authored Jun 6, 2024
1 parent 96da676 commit e8cb91c
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 10 deletions.
7 changes: 7 additions & 0 deletions restart_process/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Contributing

## Releasing

If you have push access to the `tiltdev` repository on DockerHub, you can release a new version of the binaries used by this extension like so:
1. run `release.sh` (builds `tilt-restart-wrapper` from source, builds and pushes a Docker image with the new binary and a fresh binary of `entr` also installed from source)
2. update the image tag in the [Tiltfile](/restart_process/Tiltfile) with the tag you just pushed (you'll find the image referenced in the Dockerfile contents of the child image--look for "FROM tiltdev/restart-helper")
9 changes: 4 additions & 5 deletions restart_process/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,10 @@ When specified as a `command` in Kubernetes or Docker Compose YAML (this is how
```
Any `args` specified in Kubernetes/Docker Compose are attached to the end of this call, and therefore in this case would apply TO THE `/bin/sh -c` CALL, rather than to the actual command run by `entr`; that is, any `args` specified by the user would be effectively ignored.

In order to make `entr` usable without a shell, this extension uses [a simple binary](/restart_process/tilt-restart-wrapper.go) that invokes `entr` and writes to its stdin.
In order to make `entr` usable without a shell, this extension uses [a simple binary](tilt-restart-wrapper.go) that invokes `entr` and writes to its stdin.

Note: ideally `entr` could accept files-to-watch via flag instead of stdin, but (for a number of good reasons) this feature isn't likely to be added any time soon (see [entr#33](https://github.com/eradman/entr/issues/33)).

## For Maintainers: Releasing
If you have push access to the `tiltdev` repository on DockerHub, you can release a new version of the binaries used by this extension like so:
1. run `release.sh` (builds `tilt-restart-wrapper` from source, builds and pushes a Docker image with the new binary and a fresh binary of `entr` also installed from source)
2. update the image tag in the [Tiltfile](/restart_process/Tiltfile) with the tag you just pushed (you'll find the image referenced in the Dockerfile contents of the child image--look for "FROM tiltdev/restart-helper")
## Contributing

[Update instructions](CONTRIBUTING.md)
2 changes: 1 addition & 1 deletion restart_process/Tiltfile
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def _helper(base_ref, ref, entrypoint, live_update, restart_file=RESTART_FILE, t
# (which makes use of `entr` to watch files and restart processes) to the user's image
# we also set the image's entrypoint to give k8s_custom_deploy a chance of working: https://github.com/tilt-dev/tilt-extensions/issues/391
df = '''
FROM tiltdev/restart-helper:2021-11-03 as restart-helper
FROM tiltdev/restart-helper:2024-06-06 as restart-helper
FROM {ref}
RUN ["touch", "{file}"]
Expand Down
7 changes: 6 additions & 1 deletion restart_process/test/Tiltfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
load('../Tiltfile', 'docker_build_with_restart')

k8s_yaml('job.yaml')
k8s_yaml('test-job.yaml')
k8s_yaml('failing-job.yaml')

docker_build_with_restart('test_job', '.', dockerfile='Dockerfile.test', entrypoint='/start.sh',
live_update=[sync('./start.sh', '/start.sh')])

docker_build_with_restart('failing_job', '.', dockerfile='Dockerfile.failing', entrypoint='/fail.sh',
live_update=[sync('./fail.sh', '/fail.sh')])
11 changes: 10 additions & 1 deletion restart_process/test/custom.Tiltfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
load('../Tiltfile', 'custom_build_with_restart')

k8s_yaml('job.yaml')
k8s_yaml('failing-job.yaml')
custom_build_with_restart(
'failing_job',
command='docker build -t $EXPECTED_REF -f Dockerfile.failing .',
deps=['fail.sh'],
entrypoint='/fail.sh',
live_update=[sync('./fail.sh', '/fail.sh')])


k8s_yaml('test-job.yaml')
custom_build_with_restart(
'test_job',
command='docker build -t $EXPECTED_REF -f Dockerfile.test .',
deps=['start.sh'],
entrypoint='/start.sh',
live_update=[sync('./start.sh', '/start.sh')])
File renamed without changes.
8 changes: 8 additions & 0 deletions restart_process/test/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ RESTART_COUNT="$(cat restart_count.txt)"
echo "RESTART_COUNT: $RESTART_COUNT"
RESTART_COUNT=$((RESTART_COUNT+1))
echo $RESTART_COUNT > restart_count.txt

handle_sigterm() {
echo "SIGTERM received"
sleep 1
}

trap handle_sigterm SIGTERM

while true
do
echo running
Expand Down
12 changes: 12 additions & 0 deletions restart_process/test/test-job.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: batch/v1
kind: Job
metadata:
name: test-job
spec:
template:
spec:
containers:
- name: test-job
image: test_job
restartPolicy: Never
backoffLimit: 4
3 changes: 2 additions & 1 deletion restart_process/test/trigger_custom_deploy_live_update.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ set -u

touch start.sh
# seconds
TIMEOUT=5
TIMEOUT=10
for ((i=0;i<=$TIMEOUT;++i)) do
tilt logs | grep -v test_update | grep -q "RESTART_COUNT: 1"
if [[ $? -eq 0 ]]; then
echo restart detected
exit 0
fi
echo no restart detected
touch start.sh
sleep 1
done
exit 1
22 changes: 21 additions & 1 deletion restart_process/tilt-restart-wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ import (
"log"
"os"
"os/exec"
"os/signal"
"strings"
"syscall"
)

var watchFile = flag.String("watch_file", "/.restart-proc", "File that entr will watch for changes; changes to this file trigger `entr` to rerun the command(s) passed")
var entrPath = flag.String("entr_path", "/entr", "Path to `entr` executable")
var entrFlags = flag.String("entr_flags", "-rz", "Command line flags to pass to `entr` executable")
var verboseSignals = flag.Bool("verbose_signals", false, "Print signals received by `tilt-restart-wrapper`")

func main() {
flag.Parse()
Expand All @@ -52,7 +54,25 @@ func main() {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

if err := cmd.Run(); err != nil {
if err := cmd.Start(); err != nil {
log.Fatalf("error starting command: %v", err)
}

// Set up a signal forwarding handler
sigs := make(chan os.Signal, 10)
signal.Notify(sigs)
go func() {
for sig := range sigs {
if *verboseSignals {
log.Printf("Received signal: %s (%d), forwarding to pid %d", sig, sig.(syscall.Signal), cmd.Process.Pid)
}
if err := cmd.Process.Signal(sig); err != nil {
log.Println("Error forwarding signal:", err)
}
}
}()

if err := cmd.Wait(); err != nil {
if exiterr, ok := err.(*exec.ExitError); ok {
// The program has exited with an exit code != 0
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
Expand Down

0 comments on commit e8cb91c

Please sign in to comment.