Skip to content

Commit

Permalink
Refactored termination hook type to make it public (#50)
Browse files Browse the repository at this point in the history
* Renamed `TerminationOrder`->`Order`

* Renamed `terminationHook`->`Hook`

* Moved `defaultTimeout` const into hook.go

* Fix for the godoc

* Fixed test name

* Godoc for Hook internal fields
  • Loading branch information
skovtunenko authored Jul 9, 2022
1 parent df1b366 commit c922347
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 41 deletions.
37 changes: 22 additions & 15 deletions hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,37 @@ import (
"time"
)

// TerminationOrder is an application components termination order.
const (
// defaultTimeout is a default timeout for a registered hook.
defaultTimeout = time.Minute
)

// Order is an application components termination order.
//
// Lower order - higher priority.
type TerminationOrder int
type Order int

// terminationHook is a registered termination hook.
type terminationHook struct {
terminator *Terminator

order TerminationOrder
name string
timeout time.Duration
hookFunc func(ctx context.Context)
// Hook is a registered termination hook.
//
// Do not create a Hook instance manually, use Terminator.WithOrder() method instead to get a Hook instance.
type Hook struct {
terminator *Terminator // terminator is a pointer to Terminator instance that holds registered Hooks.

order Order // order is Hook order.
name string // name is an optional component name for pretty-printing in logs.
timeout time.Duration // timeout is max hookFunc execution timeout.
hookFunc func(ctx context.Context) // hookFunc is a user-defined termination hook function.
}

// WithName sets (optional) human-readable name of the registered termination hook.
func (tf *terminationHook) WithName(name string) *terminationHook {
func (tf *Hook) WithName(name string) *Hook {
tf.name = name
return tf
}

// Register registers termination hook that should finish execution in less than given timeout.
// Timeout duration must be greater than zero; if not, timeout of 1 min will be used.
func (tf *terminationHook) Register(timeout time.Duration, hookFunc func(ctx context.Context)) {
func (tf *Hook) Register(timeout time.Duration, hookFunc func(ctx context.Context)) {
if timeout <= 0 {
timeout = defaultTimeout
}
Expand All @@ -42,8 +49,8 @@ func (tf *terminationHook) Register(timeout time.Duration, hookFunc func(ctx con
tf.terminator.hooks[tf.order] = append(tf.terminator.hooks[tf.order], *tf)
}

// String returns string representation of terminationFunc.
func (tf *terminationHook) String() string {
// String returns string representation of a Hook.
func (tf *Hook) String() string {
if tf == nil {
return "<nil>"
}
Expand All @@ -53,4 +60,4 @@ func (tf *terminationHook) String() string {
return fmt.Sprintf("component: %q (order: %d)", tf.name, tf.order)
}

var _ fmt.Stringer = &terminationHook{}
var _ fmt.Stringer = &Hook{}
10 changes: 5 additions & 5 deletions hook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (
"testing"
)

func Test_terminationFunc_String(t *testing.T) {
func Test_Hook_String(t *testing.T) {
type fields struct {
tf *terminationHook
tf *Hook
}
tests := []struct {
name string
Expand All @@ -24,14 +24,14 @@ func Test_terminationFunc_String(t *testing.T) {
{
name: "empty_non-nil_struct",
fields: fields{
tf: &terminationHook{},
tf: &Hook{},
},
want: `nameless component (order: 0)`,
},
{
name: "nameless_termination_func",
fields: fields{
tf: &terminationHook{
tf: &Hook{
order: 3,
name: " ",
},
Expand All @@ -41,7 +41,7 @@ func Test_terminationFunc_String(t *testing.T) {
{
name: "termination_function_with_a_name",
fields: fields{
tf: &terminationHook{
tf: &Hook{
order: 777,
name: "some random name",
},
Expand Down
8 changes: 4 additions & 4 deletions internal/example/example.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ const (
)

const (
HTTPServerOrder graterm.TerminationOrder = 0
MessagingOrder graterm.TerminationOrder = 1
FastDBOrder graterm.TerminationOrder = 2
SlowDBOrder graterm.TerminationOrder = 2
HTTPServerOrder graterm.Order = 0
MessagingOrder graterm.Order = 1
FastDBOrder graterm.Order = 2
SlowDBOrder graterm.Order = 2
)

func main() {
Expand Down
3 changes: 3 additions & 0 deletions logger.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package graterm

// Logger specifies the interface for internal Terminator log operations.
//
// By default, graterm library will not log anything.
// To set the logger, use Terminator.SetLogger() method.
type Logger interface {
Printf(format string, v ...interface{})
}
Expand Down
19 changes: 7 additions & 12 deletions terminator.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,10 @@ import (
"time"
)

const (
// defaultTimeout is a default timeout for a registered hook.
defaultTimeout = time.Minute
)

// Terminator is a component terminator that executes registered termination hooks in a specified order.
type Terminator struct {
hooksMx *sync.Mutex
hooks map[TerminationOrder][]terminationHook
hooks map[Order][]Hook

wg *sync.WaitGroup

Expand All @@ -38,7 +33,7 @@ func NewWithSignals(appCtx context.Context, sig ...os.Signal) (*Terminator, cont
ctx, cancel := withSignals(appCtx, chSignals, sig...)
return &Terminator{
hooksMx: &sync.Mutex{},
hooks: make(map[TerminationOrder][]terminationHook),
hooks: make(map[Order][]Hook),
wg: &sync.WaitGroup{},
cancelFunc: cancel,
log: noopLogger{},
Expand Down Expand Up @@ -81,13 +76,13 @@ func (s *Terminator) SetLogger(log Logger) {
s.log = log
}

// WithOrder sets the TerminationOrder for the termination hook.
// WithOrder sets the Order for the termination hook.
// It starts registration chain to register termination hook with priority.
//
// The lower the order the higher the execution priority, the earlier it will be executed.
// If there are multiple hooks with the same order they will be executed in parallel.
func (s *Terminator) WithOrder(order TerminationOrder) *terminationHook {
return &terminationHook{
func (s *Terminator) WithOrder(order Order) *Hook {
return &Hook{
terminator: s,
order: order,
}
Expand Down Expand Up @@ -136,10 +131,10 @@ func (s *Terminator) waitShutdown(appCtx context.Context) {

runWg := sync.WaitGroup{}

for _, c := range s.hooks[TerminationOrder(o)] {
for _, c := range s.hooks[Order(o)] {
runWg.Add(1)

go func(f terminationHook) {
go func(f Hook) {
defer runWg.Done()

ctx, cancel := context.WithTimeout(context.Background(), f.timeout)
Expand Down
10 changes: 5 additions & 5 deletions terminator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func TestTerminator_Register(t *testing.T) {
terminator.WithOrder(777).Register(-1, func(_ context.Context) {}) // negative timeout

require.Equal(t, 1, len(terminator.hooks))
got, ok := terminator.hooks[TerminationOrder(777)]
got, ok := terminator.hooks[Order(777)]
require.True(t, ok)
require.Equal(t, 1, len(got))

Expand All @@ -61,7 +61,7 @@ func TestTerminator_Register(t *testing.T) {
Register(1*time.Second, func(_ context.Context) {})

require.Equal(t, 1, len(terminator.hooks))
got, ok := terminator.hooks[TerminationOrder(1)]
got, ok := terminator.hooks[Order(1)]
require.True(t, ok)
require.Equal(t, 1, len(got))
})
Expand All @@ -81,11 +81,11 @@ func TestTerminator_Register(t *testing.T) {
Register(1*time.Second, func(_ context.Context) {})

require.Equal(t, 2, len(terminator.hooks))
got, ok := terminator.hooks[TerminationOrder(1)]
got, ok := terminator.hooks[Order(1)]
require.True(t, ok)
require.Equal(t, 1, len(got))

got2, ok2 := terminator.hooks[TerminationOrder(2)]
got2, ok2 := terminator.hooks[Order(2)]
require.True(t, ok2)
require.Equal(t, 1, len(got2))
})
Expand All @@ -105,7 +105,7 @@ func TestTerminator_Register(t *testing.T) {
Register(1*time.Second, func(_ context.Context) {})

require.Equal(t, 1, len(terminator.hooks))
got, ok := terminator.hooks[TerminationOrder(1)]
got, ok := terminator.hooks[Order(1)]
require.True(t, ok)
require.Equal(t, 2, len(got))
})
Expand Down

0 comments on commit c922347

Please sign in to comment.