Skip to content

Commit ed355a2

Browse files
committed
Tweak shutdown behavior
1 parent 3226535 commit ed355a2

File tree

3 files changed

+36
-7
lines changed

3 files changed

+36
-7
lines changed

cmd/cog/main.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,14 @@ func serverCommand() *ff.Command {
9797
go func() {
9898
ch := make(chan os.Signal, 1)
9999
signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
100-
sig := <-ch
101-
if cfg.AwaitExplicitShutdown {
102-
log.Warnw("ignoring signal to stop", "signal", sig)
103-
} else {
104-
log.Infow("stopping Cog HTTP server", "signal", sig)
105-
must.Do(h.Stop())
100+
for {
101+
sig := <-ch
102+
if sig == syscall.SIGTERM && cfg.AwaitExplicitShutdown {
103+
log.Warnw("ignoring signal to stop", "signal", sig)
104+
} else {
105+
log.Infow("stopping Cog HTTP server", "signal", sig)
106+
must.Do(h.Stop())
107+
}
106108
}
107109
}()
108110
if err := s.ListenAndServe(); errors.Is(err, http.ErrServerClosed) {

internal/tests/shutdown_test.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@ import (
1010
"github.com/replicate/cog-runtime/internal/server"
1111
)
1212

13+
func TestShutdownByServerSigInt(t *testing.T) {
14+
if *legacyCog {
15+
// Compat: legacy Cog doesn't handle SIGINT properly without a TTY
16+
t.SkipNow()
17+
}
18+
ct := NewCogTest(t, "sleep")
19+
assert.NoError(t, ct.Start())
20+
21+
hc := ct.WaitForSetup()
22+
assert.Equal(t, server.StatusReady.String(), hc.Status)
23+
assert.Equal(t, server.SetupSucceeded, hc.Setup.Status)
24+
25+
must.Do(syscall.Kill(ct.ServerPid(), syscall.SIGINT))
26+
assert.NoError(t, ct.Cleanup())
27+
assert.Equal(t, 0, ct.cmd.ProcessState.ExitCode())
28+
}
29+
1330
func TestShutdownByServerSigTerm(t *testing.T) {
1431
ct := NewCogTest(t, "sleep")
1532
assert.NoError(t, ct.Start())
@@ -32,11 +49,18 @@ func TestShutdownIgnoreSignal(t *testing.T) {
3249
assert.Equal(t, server.StatusReady.String(), hc.Status)
3350
assert.Equal(t, server.SetupSucceeded, hc.Setup.Status)
3451

52+
// Ignore SIGTERM
3553
must.Do(syscall.Kill(ct.ServerPid(), syscall.SIGTERM))
3654
assert.Nil(t, ct.cmd.ProcessState)
3755
assert.Equal(t, server.StatusReady.String(), ct.HealthCheck().Status)
3856

39-
ct.Shutdown()
57+
if *legacyCog {
58+
// Compat: legacy Cog doesn't handle SIGINT properly without a TTY
59+
ct.Shutdown()
60+
} else {
61+
// Handle SIGINT
62+
must.Do(syscall.Kill(ct.ServerPid(), syscall.SIGINT))
63+
}
4064
assert.NoError(t, ct.Cleanup())
4165
assert.Equal(t, 0, ct.cmd.ProcessState.ExitCode())
4266
}

python/coglet/file_runner.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ def _cancel_handler(signum, _) -> None:
108108
else:
109109
# Blocking predict, use SIGUSR1 to cancel
110110
signal.signal(signal.SIGUSR1, _cancel_handler)
111+
# When running in a shell, Ctrl-C sends SIGINT to all processes in the process group
112+
# Ignore it here and require shutdown from parent Go server
113+
signal.signal(signal.SIGINT, signal.SIG_IGN)
111114

112115
ready = True
113116
self._send_ipc(FileRunner.IPC_READY)

0 commit comments

Comments
 (0)