@@ -15,27 +15,40 @@ import (
1515)
1616
1717// ContextualMain calls a main entry point function with a cancellable
18- // context via SIGTERM. This should be called once per process so as
18+ // context via SIGTERM and ignores SIGPIPEs . This should be called once per process so as
1919// to not clobber the signals from Notify.
2020func ContextualMain [L ILogger ](main func (ctx context.Context , args []string , logger L ) error , logger L ) {
21- contextualMain (main , false , logger )
21+ // RSDK-11244: SIGPIPE errors happen when a program writes to a pipe that has no readers. This
22+ // can, for example, happen when:
23+ // - Piping a program (e.g: viam-server) to `tee` and hitting Ctrl-C.
24+ // - Writing a gRPC request over a unix socket to a program that has crashed.
25+ //
26+ // We want to ignore SIGPIPE errors such that, in the SIGINT case, clean shutdown can proceed.
27+ contextualMain (main , false , logger , syscall .SIGPIPE )
2228}
2329
2430// ContextualMainQuit is the same as ContextualMain but catches quit signals into the provided
2531// context accessed via ContextMainQuitSignal.
2632func ContextualMainQuit [L ILogger ](main func (ctx context.Context , args []string , logger L ) error , logger L ) {
27- contextualMain (main , true , logger )
33+ contextualMain (main , true , logger , syscall .SIGPIPE )
34+ }
35+
36+ // ContextualMainWithSIGPIPE calls a main entry point function with a cancellable
37+ // context via SIGTERM and does not ignore SIGPIPEs. This should be called once per process so as
38+ // to not clobber the signals from Notify.
39+ // This should be used with processes where SIGPIPEs indicate that it should stop (e.g. child processes which should
40+ // not live beyond its parent's lifetime).
41+ func ContextualMainWithSIGPIPE [L ILogger ](main func (ctx context.Context , args []string , logger L ) error , logger L ) {
42+ contextualMain (main , false , logger )
2843}
2944
30- func contextualMain [L ILogger ](main func (ctx context.Context , args []string , logger L ) error , quitSignal bool , logger L ) {
45+ func contextualMain [L ILogger ](
46+ main func (ctx context.Context , args []string , logger L ) error , quitSignal bool , logger L , ignoreSignals ... os.Signal ,
47+ ) {
3148 ctx , stop := signal .NotifyContext (context .Background (), os .Interrupt , syscall .SIGTERM )
32- // RSDK-11244: SIGPIPE errors happen when a program writes to a pipe that has no readers. This
33- // can, for example, happen when:
34- // - Piping a program (e.g: viam-server) to `tee` and hitting Ctrl-C.
35- // - Writing a gRPC request over a unix socket to a program that has crashed.
36- //
37- // We want to ignore SIGPIPE errors such that, in the SIGINT case, clean shutdown can proceed.
38- signal .Ignore (syscall .SIGPIPE )
49+ if len (ignoreSignals ) > 0 {
50+ signal .Ignore (ignoreSignals ... )
51+ }
3952 if quitSignal {
4053 quitC := make (chan os.Signal , 1 )
4154 signal .Notify (quitC , syscall .SIGQUIT )
0 commit comments