https://github.com/einride/supervisor-go
A service that starts and supervises other services and restarts them in case of failure.
https://github.com/einride/supervisor-go
actors go golang supervision supervisor
Last synced: 5 months ago
JSON representation
A service that starts and supervises other services and restarts them in case of failure.
- Host: GitHub
- URL: https://github.com/einride/supervisor-go
- Owner: einride
- License: mit
- Created: 2019-07-26T13:12:17.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2024-10-29T07:04:42.000Z (6 months ago)
- Last Synced: 2024-10-29T08:17:45.077Z (6 months ago)
- Topics: actors, go, golang, supervision, supervisor
- Language: Go
- Homepage:
- Size: 165 KB
- Stars: 21
- Watchers: 20
- Forks: 4
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Codeowners: .github/CODEOWNERS
- Security: SECURITY.md
Awesome Lists containing this project
README
# go.einride.tech/supervisor
A service that manages service lifetimes.
A supervisor is essentially a more capable errgroup. It monitors a set of
running services, and restarts them if they fail. The supervisor keeps track of
the status of each service and reports any status changes to listeners via a
callback.## Examples
### Supervising multiple services
Just as with errgroups, a supervisor can manage multiple services.
```go
func ExampleSupervisor() {
// Restart stopped services every 10ms.
cfg := supervisor.Config{
RestartInterval: 10 * time.Millisecond,
// No specified clock returns system clock
// No specified logger returns a nop-logger
}
// Create a context which can be canceled.
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
// Create pingpong table
table := make(chan int)
roundsToPlay := 2
// Create player services.
pingService := supervisor.NewService("ping", func(ctx context.Context) error {
i := roundsToPlay
for {
select {
case <-ctx.Done():
return fmt.Errorf("timeout")
case table <- i:
fmt.Println("ping")
i = <-table
if i == 0 {
close(table)
cancel()
return nil
}
}
}
})
pongService := supervisor.NewService("pong", func(ctx context.Context) error {
for {
select {
case <-ctx.Done():
return fmt.Errorf("timeout")
case i := <-table:
if i == 0 {
return nil
}
table <- i - 1
fmt.Println("pong")
}
}
})
// Add service to the supervised services.
cfg.Services = append(cfg.Services, pingService, pongService)
// Create the supervisor from the config.
s := supervisor.New(&cfg)
// Run the supervisor (blocking call).
err := s.Run(ctx)
if err != nil {
// handle error
panic(err)
}
defer cancel()
// Output:
// ping
// pong
// ping
// pong
}
```### Restarting crashed services
The main difference from errgroups is that a supervisor will restart a crashed
service.```go
func ExampleRestartOnError() {
// Restart stopped services every 10ms.
cfg := supervisor.Config{
RestartInterval: 10 * time.Millisecond,
}
ctx, cancel := context.WithCancel(context.Background())
starts := 0
svc := supervisor.NewService("example", func(ctx context.Context) error {
starts++
if starts > 3 {
cancel()
return nil
}
return fmt.Errorf("oops")
})
cfg.Services = append(cfg.Services, svc)
s := supervisor.New(&cfg)
if err := s.Run(ctx); err != nil {
// no error currently returned
}
fmt.Println("service restarted", starts, "times")
// Output:
// service restarted 3 times
}
```