mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 15:09:42 +00:00
signaler: improve cross-platform signal compatibility (#1952)
* signaler: improve cross-platform signal compatibility - Add runtime-based platform detection for signal handling - Include os.Kill only on Windows (cannot be caught/ignored on Unix) - Refactor signal initialization into separate getPlatformSignals function * signaler: add dependency injection and improve docs - Introduce SignalNotifier interface for testability - Add osSignalNotifier implementation and factory function - Enhance package and function documentation - Maintain backward compatibility with existing API * [signaler] simplify shutdown handling; drop SIGABRT/os.Kill * skip signaler tests on windows * support signaler interrupt tests and improve signal handling tests * removing getPlatformSignal function * remove signaler readme * Signaler: Return a channel from WaitForInterrupt * Signaler: fix comment Co-authored-by: Ryan O'Hara-Reid <oharareid.ryan@gmail.com> * Signaler: require NoError to NoErrorf Co-authored-by: Ryan O'Hara-Reid <oharareid.ryan@gmail.com> --------- Co-authored-by: Ryan O'Hara-Reid <oharareid.ryan@gmail.com>
This commit is contained in:
@@ -125,7 +125,7 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
// Capture cancel for interrupt
|
||||
signaler.WaitForInterrupt()
|
||||
<-signaler.WaitForInterrupt()
|
||||
cancel()
|
||||
fmt.Println("rpc process interrupted")
|
||||
os.Exit(1)
|
||||
|
||||
@@ -195,7 +195,7 @@ func main() {
|
||||
fmt.Printf("Could not stop task %v %v. Error: %v\n", bt.MetaData.ID, bt.MetaData.Strategy, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
interrupt := signaler.WaitForInterrupt()
|
||||
interrupt := <-signaler.WaitForInterrupt()
|
||||
log.Infof(log.Global, "Captured %v, shutdown requested\n", interrupt)
|
||||
log.Infoln(log.Global, "Exiting.")
|
||||
err = bt.Stop()
|
||||
@@ -230,7 +230,7 @@ func main() {
|
||||
}
|
||||
log.Infoln(log.GRPCSys, "Ready to receive commands")
|
||||
}(btCfg)
|
||||
interrupt := signaler.WaitForInterrupt()
|
||||
interrupt := <-signaler.WaitForInterrupt()
|
||||
log.Infof(log.Global, "Captured %v, shutdown requested\n", interrupt)
|
||||
if btCfg.StopAllTasksOnClose {
|
||||
log.Infoln(log.Global, "Stopping all running tasks on close")
|
||||
|
||||
@@ -225,7 +225,7 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
// Capture cancel for interrupt
|
||||
signaler.WaitForInterrupt()
|
||||
<-signaler.WaitForInterrupt()
|
||||
cancel()
|
||||
fmt.Println("rpc process interrupted")
|
||||
os.Exit(1)
|
||||
|
||||
2
main.go
2
main.go
@@ -157,7 +157,7 @@ func main() {
|
||||
}
|
||||
|
||||
func waitForInterrupt(waiter chan<- struct{}) {
|
||||
interrupt := signaler.WaitForInterrupt()
|
||||
interrupt := <-signaler.WaitForInterrupt()
|
||||
gctlog.Infof(gctlog.Global, "Captured %v, shutdown requested.\n", interrupt)
|
||||
waiter <- struct{}{}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package signaler provides cross-platform signal handling for graceful application shutdown
|
||||
package signaler
|
||||
|
||||
import (
|
||||
@@ -6,20 +7,9 @@ import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var s = make(chan os.Signal, 1)
|
||||
|
||||
func init() {
|
||||
sigs := []os.Signal{
|
||||
os.Interrupt,
|
||||
os.Kill,
|
||||
syscall.SIGTERM,
|
||||
syscall.SIGABRT,
|
||||
}
|
||||
signal.Notify(s, sigs...)
|
||||
}
|
||||
|
||||
// WaitForInterrupt waits until a os.Signal is
|
||||
// received and returns the result
|
||||
func WaitForInterrupt() os.Signal {
|
||||
return <-s
|
||||
// WaitForInterrupt returns a channel to receive termination signals
|
||||
func WaitForInterrupt() chan os.Signal {
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
return c
|
||||
}
|
||||
|
||||
37
signaler/signaler_test.go
Normal file
37
signaler/signaler_test.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package signaler
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestWaitForInterrupt(t *testing.T) {
|
||||
t.Parallel()
|
||||
for _, sig := range []os.Signal{syscall.SIGTERM, os.Interrupt} {
|
||||
sigC := WaitForInterrupt()
|
||||
proc, err := os.FindProcess(os.Getpid())
|
||||
require.NoError(t, err, "os.FindProcess must not error")
|
||||
|
||||
if err := proc.Signal(sig); err != nil {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skipf("proc.Signal(%s) not supported on Windows: %v", sig, err)
|
||||
}
|
||||
require.NoErrorf(t, err, "proc.Signal(%s) must not error", sig)
|
||||
}
|
||||
|
||||
assert.Eventuallyf(t, func() bool {
|
||||
select {
|
||||
case got := <-sigC:
|
||||
return got == sig
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}, 2*time.Second, 10*time.Millisecond, "Signal %s should be received within timeout", sig)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user