1
Fork 0

Initial commit

This commit is contained in:
Jan-Lukas Else 2021-06-17 16:26:09 +02:00
parent 4e78a4cf3c
commit b824b89965
6 changed files with 141 additions and 2 deletions

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) <year> <copyright holders>
Copyright (c) 2021 Jan-Lukas Else
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View File

@ -1,3 +1,5 @@
# go-shutdowner
Simple library for graceful shutdowns
A simple library for graceful shutdowns
100% covered with unit tests.

9
go.mod Normal file
View File

@ -0,0 +1,9 @@
module git.jlel.se/jlelse/go-shutdowner
go 1.16
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/stretchr/testify v1.7.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)

13
go.sum Normal file
View File

@ -0,0 +1,13 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

80
shutdown.go Normal file
View File

@ -0,0 +1,80 @@
package goshutdowner
import (
"os"
"os/signal"
"sync"
"syscall"
)
// Simple struct, use like a sync.Mutex
//
// var s goshutdowner.Shutdowner
// s.Add(func() {
// log.Println("Shutting down")
// })
type Shutdowner struct {
initialized bool
quit chan os.Signal
funcs []ShutdownFunc
wg sync.WaitGroup
mutex sync.RWMutex
}
type ShutdownFunc func()
// Internal method
func (s *Shutdowner) init() {
if s.initialized {
return
}
s.quit = make(chan os.Signal, 1)
signal.Notify(s.quit,
os.Interrupt,
syscall.SIGINT,
syscall.SIGTERM, // e.g. Docker stop
)
go func() {
<-s.quit
s.Shutdown()
}()
s.initialized = true
}
// Add a func, that should be called with s.Shutdown() or when receiving a shutdown signal
func (s *Shutdowner) Add(f ShutdownFunc) {
s.init()
s.mutex.Lock()
s.wg.Add(1)
s.funcs = append(s.funcs, f)
s.mutex.Unlock()
}
// Trigger shutdown directly
func (s *Shutdowner) Shutdown() {
s.init()
s.mutex.RLock()
for _, f := range s.funcs {
go func(f func()) {
defer s.wg.Done()
f()
}(f)
}
s.mutex.RUnlock()
s.wg.Wait()
}
// Wait till all functions finished
func (s *Shutdowner) Wait() {
s.init()
s.wg.Wait()
}
// Shutdown and wait till shutdown finished. Shorthand for:
//
// s.Shutdown()
// s.Wait()
func (s *Shutdowner) ShutdownAndWait() {
s.Shutdown()
s.Wait()
}

35
shutdown_test.go Normal file
View File

@ -0,0 +1,35 @@
package goshutdowner
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
)
func Test_shutdowner(t *testing.T) {
t.Run("Simple test", func(t *testing.T) {
var s Shutdowner
var testBool1, testBool2, testBool3 bool
s.Add(func() {
testBool1 = true
})
s.Add(func() {
testBool2 = true
})
s.ShutdownAndWait()
assert.True(t, testBool1)
assert.True(t, testBool2)
assert.False(t, testBool3)
})
t.Run("Signal test", func(t *testing.T) {
var s Shutdowner
var testBool1 bool
s.Add(func() {
testBool1 = true
})
s.quit <- os.Interrupt
s.Wait()
assert.True(t, testBool1)
})
}