Files
go/lifecycle/example_test.go
T

103 lines
2.6 KiB
Go

package lifecycle_test
import (
"context"
"errors"
"fmt"
"io"
"log/slog"
"os"
"syscall"
"testing"
"time"
"go.auvem.com/corestack/lifecycle"
)
func TestRealFlow(t *testing.T) {
for _, failure := range []bool{false, true} {
t.Run(fmt.Sprint(failure), func(t *testing.T) {
signals := make(chan os.Signal, 2)
app, err := lifecycle.New(lifecycle.Config{Logger: slog.New(slog.NewTextHandler(io.Discard, nil)), Signals: signals, ShutdownTimeout: time.Second})
if err != nil {
t.Fatal(err)
}
ready := make(chan struct{}, 3)
release := make(chan struct{})
t.Cleanup(func() {
select {
case <-release:
default:
close(release)
}
})
failed := errors.New("service failed")
for _, name := range []string{"daemon", "muxer"} {
err = app.Register(lifecycle.Module{Name: name, Setup: func(ctx context.Context) error {
if name == "daemon" {
return app.Go(ctx, "queue", func(ctx context.Context) error { ready <- struct{}{}; <-ctx.Done(); <-release; return ctx.Err() })
}
return nil
}, Run: func(ctx context.Context) error {
ready <- struct{}{}
if name == "muxer" && failure {
<-release
return failed
}
<-ctx.Done()
return ctx.Err()
}, Teardown: func(context.Context) error { return nil }})
if err != nil {
t.Fatal(err)
}
}
done := make(chan error, 1)
go func() { done <- app.Run(context.Background()) }()
for range 3 {
select {
case <-ready:
case <-time.After(3 * time.Second):
t.Fatal("services did not start")
}
}
if !failure {
signals <- syscall.SIGTERM
}
close(release)
select {
case err = <-done:
if failure && !errors.Is(err, failed) || !failure && err != nil {
t.Fatalf("Run: %v", err)
}
case <-time.After(2 * time.Second):
t.Fatal("Run blocked")
}
})
}
}
func Example() {
signals := make(chan os.Signal, 2)
app, err := lifecycle.New(lifecycle.Config{Logger: slog.New(slog.NewTextHandler(io.Discard, nil)), Signals: signals})
if err != nil {
panic(err)
}
ready := make(chan struct{}, 2)
for _, name := range []string{"daemon", "muxer"} {
err := app.Register(lifecycle.Module{
Name: name,
Setup: func(ctx context.Context) error {
return app.Go(ctx, name+" worker", func(ctx context.Context) error { <-ctx.Done(); return ctx.Err() })
},
Run: func(ctx context.Context) error { ready <- struct{}{}; <-ctx.Done(); return ctx.Err() },
Teardown: func(context.Context) error { return nil },
})
if err != nil {
panic(err)
}
}
go func() { <-ready; <-ready; signals <- syscall.SIGTERM }()
fmt.Println(app.Run(context.Background()))
// Output: <nil>
}