-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontroller.go
More file actions
68 lines (58 loc) · 2.48 KB
/
controller.go
File metadata and controls
68 lines (58 loc) · 2.48 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
// Package launch provides a way to launch and monitor components within an application.
//
// If any component exits, or if [RequestStop] is called, then the application shuts down so that it can be replaced
// by another instance. (App instance replacement is assumed to be provided externally -- e.g. k8s, systemd, etc.)
//
// Shutdown order is the reverse of the [Launch] order, as one would commonly expect.
package launch
import (
"context"
"fmt"
"github.com/spikesdivzero/launch-control/internal/controller"
)
// The bulk of the controller is implemented internally.
// We expose a documented struct here, as opposed to an interface, primarily for easier reading and godoc's sake.
// A Controller is the heart of the package. Components are Launched inside of the Controller, and the Controller
// provides a minimal interface to manage the application's lifecycle.
type Controller struct {
impl *controller.Controller
}
func NewController(ctx context.Context, opts ...ControllerOption) Controller {
c := Controller{impl: controller.New(ctx)}
for _, opt := range opts {
opt(c.impl)
}
return c
}
// Launch builds a component from the provided name and options, then launches it inside of the controller.
// This blocks until the component launch has finished (regardless of success or failure).
//
// Required options: Nearly every option is, as the name suggests, optional. However you must provide exactly
// one of [WithRun] or [WithStartStop] as one of the options, as this defines how the component should execute.
//
// If a Launch request comes in after the controller has started shutting down, the request will be silently
// discarded.
func (c *Controller) Launch(name string, opts ...ComponentOption) {
comp, err := buildComponent(name, opts...)
if err != nil {
panic(fmt.Sprintf("component build failed: %v", err))
}
c.impl.Launch(name, comp)
}
// RequestStop signals to the controller that it's time to exit, with an optional error explaining why.
//
// It's safe to call as multiple times. Only the first non-nil error is recorded.
func (c *Controller) RequestStop(reason error) {
c.impl.RequestStop(reason)
}
// Wait blocks until the controller's internals exit, and then returns the result of [Err].
func (c *Controller) Wait() error {
return c.impl.Wait()
}
// Err returns the first non-nil error recorded by the controller (including calls to [RequestStop]).
func (c *Controller) Err() error {
return c.impl.Err()
}
func (c *Controller) AllErrors() []error {
return c.impl.AllErrors()
}