From 8c034e8426e33dc25341872adefec6d802416904 Mon Sep 17 00:00:00 2001 From: ymmt2005 Date: Wed, 26 Apr 2017 10:41:49 +0900 Subject: [PATCH] Fix SIGPIPE handling, take 2. Closes #15. Please see #15 and comments in the code. --- default.go | 2 +- sigpipe.go | 43 +++++++++++++++++++++++++++++++++++++------ sigpipe_windows.go | 2 +- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/default.go b/default.go index 51eecaa..11ba295 100644 --- a/default.go +++ b/default.go @@ -9,7 +9,7 @@ var ( func init() { defaultEnv = NewEnvironment(context.Background()) handleSignal(defaultEnv) - ignoreSigPipe() + handleSigPipe() } // Stop just declares no further Go will be called. diff --git a/sigpipe.go b/sigpipe.go index 65b41fc..c8885f6 100644 --- a/sigpipe.go +++ b/sigpipe.go @@ -8,12 +8,43 @@ import ( "syscall" ) -func ignoreSigPipe() { - // signal.Ignore does NOT ignore signals; instead, it just stop - // relaying signals to the channel. - //signal.Ignore(syscall.SIGPIPE) +const ( + sigPipeExit = 2 +) - // unbuffered channel will effectively ignore the signal - c := make(chan os.Signal) +// handleSigPipe catches SIGPIPE and exit abnormally with status code 2. +// +// Background: +// +// systemd interprets programs exited with SIGPIPE as +// "successfully exited" because its default SuccessExitStatus= +// includes SIGPIPE. +// https://www.freedesktop.org/software/systemd/man/systemd.service.html +// +// Normal Go programs ignore SIGPIPE for file descriptors other than +// stdout(1) and stderr(2). If SIGPIPE is raised from stdout or stderr, +// Go programs exit with a SIGPIPE signal. +// https://golang.org/pkg/os/signal/#hdr-SIGPIPE +// +// journald is a service tightly integrated in systemd. Go programs +// running as a systemd service will normally connect its stdout and +// stderr pipes to journald. Unfortunately though, journald often +// dies and restarts due to bugs, and once it restarts, programs +// whose stdout and stderr was connected to journald will receive +// SIGPIPE at their next writes to stdout or stderr. +// +// Combined these specifications and problems all together, Go programs +// running as systemd services often die with SIGPIPE, but systemd will +// not restarts them as they "successfully exited" except when the service +// is configured with SuccessExitStatus= without SIGPIPE or Restart=always. +// +// Handling SIGPIPE manually and exiting with abnormal status code 2 +// can work around the problem. +func handleSigPipe() { + c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGPIPE) + go func() { + <-c + os.Exit(sigPipeExit) + }() } diff --git a/sigpipe_windows.go b/sigpipe_windows.go index e630a90..db6d163 100644 --- a/sigpipe_windows.go +++ b/sigpipe_windows.go @@ -1,3 +1,3 @@ package cmd -func ignoreSigPipe() {} +func handleSigPipe() {}