This repository was archived by the owner on Aug 14, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlifecycle.go
More file actions
114 lines (95 loc) · 3.09 KB
/
lifecycle.go
File metadata and controls
114 lines (95 loc) · 3.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package pluginfx
import (
"context"
"fmt"
"plugin"
"reflect"
"go.uber.org/fx"
)
// InvalidLifecycleError indicates that a symbol was not usable
// as an uber/fx lifecycle callback via fx.Hook.
type InvalidLifecycleError struct {
Name string
Type reflect.Type
}
func (ile *InvalidLifecycleError) Error() string {
return fmt.Sprintf("Symbol %s of type %T is not a valid lifecycle callback", ile.Name, ile.Type)
}
func lookupLifecycle(s Plugin, name string) (callback func(context.Context) error, err error) {
var symbol plugin.Symbol
symbol, err = Lookup(s, name)
if err == nil {
switch f := symbol.(type) {
case func():
callback = func(context.Context) error { f(); return nil }
case func() error:
callback = func(context.Context) error { return f() }
case func(context.Context):
callback = func(ctx context.Context) error { f(ctx); return nil }
case func(context.Context) error:
callback = f
default:
err = &InvalidLifecycleError{
Name: name,
Type: reflect.TypeOf(symbol),
}
}
}
return
}
// Lifecycle describes how to bind a plugin to an enclosing application's lifecycle.
type Lifecycle struct {
// OnStart is the optional symbol name of a function that can be invoked on application startup.
//
// This field must refer to an exported function in the plugin that has any of the following
// signatures:
//
// - func()
// - func() error
// - func(context.Context)
// - func(context.Context) error
//
// A function with any of those signatures will be registered as an fx.Hook and will run
// on application startup. Any other signature or non-function type will shortcircuit
// the application with an error.
OnStart string
// OnStop is the optional symbol name of a function that can be invoked on application shutdown.
// The symbol referred to by this field may have any of the same function signatures as OnStart.
OnStop string
// IgnoreMissing defines what happens when either OnStart or OnStop are set and not present.
// If this field is true, a missing OnStart or OnStop is silently ignored. If this field is false,
// then a missing OnStart or OnStop from a plugin will shortcircuit application startup with an error.
IgnoreMissing bool
}
// Bind binds the given plugin to the enclosing application's lifecycle, using
// the symbol information configured in OnStart and OnStop.
func (lc Lifecycle) Bind(p Plugin) fx.Option {
var (
hook fx.Hook
options []fx.Option
)
if len(lc.OnStart) > 0 {
var err error
hook.OnStart, err = lookupLifecycle(p, lc.OnStart)
missing := IsMissingSymbolError(err)
if (missing && !lc.IgnoreMissing) || (!missing && err != nil) {
options = append(options, fx.Error(err))
}
}
if len(lc.OnStop) > 0 {
var err error
hook.OnStop, err = lookupLifecycle(p, lc.OnStop)
missing := IsMissingSymbolError(err)
if (missing && !lc.IgnoreMissing) || (!missing && err != nil) {
options = append(options, fx.Error(err))
}
}
if len(options) == 0 && (hook.OnStart != nil || hook.OnStop != nil) {
return fx.Invoke(
func(l fx.Lifecycle) {
l.Append(hook)
},
)
}
return fx.Options(options...)
}