go/docs/lifecycle.md

112 lines
2.8 KiB
Markdown
Raw Permalink Normal View History

---
title: Lifecycle
description: Startup, shutdown, context ownership, and background task draining.
---
# Lifecycle
CoreGO manages lifecycle through `core.Service` callbacks, not through reflection or implicit interfaces.
## Service Hooks
```go
c.Service("cache", core.Service{
OnStart: func() core.Result {
return core.Result{OK: true}
},
OnStop: func() core.Result {
return core.Result{OK: true}
},
})
```
Only services with `OnStart` appear in `Startables()`. Only services with `OnStop` appear in `Stoppables()`.
## `ServiceStartup`
```go
r := c.ServiceStartup(context.Background(), nil)
```
### What It Does
1. clears the shutdown flag
2. stores a new cancellable context on `c.Context()`
3. runs each `OnStart`
4. broadcasts `ActionServiceStartup{}`
### Failure Behavior
- if the input context is already cancelled, startup returns that error
- if any `OnStart` returns `OK:false`, startup stops immediately and returns that result
## `ServiceShutdown`
```go
r := c.ServiceShutdown(context.Background())
```
### What It Does
1. sets the shutdown flag
2. cancels `c.Context()`
3. broadcasts `ActionServiceShutdown{}`
4. waits for background tasks created by `PerformAsync`
5. runs each `OnStop`
### Failure Behavior
- if draining background tasks hits the shutdown context deadline, shutdown returns that context error
- when service stop hooks fail, CoreGO returns the first error it sees
## Ordering
The current implementation builds `Startables()` and `Stoppables()` by iterating over a map-backed registry.
That means lifecycle order is not guaranteed today.
If your application needs strict startup or shutdown ordering, orchestrate it explicitly inside a smaller number of service callbacks instead of relying on registry order.
## `c.Context()`
`ServiceStartup` creates the context returned by `c.Context()`.
Use it for background work that should stop when the application shuts down:
```go
c.Service("watcher", core.Service{
OnStart: func() core.Result {
go func(ctx context.Context) {
<-ctx.Done()
}(c.Context())
return core.Result{OK: true}
},
})
```
## Built-In Lifecycle Actions
You can listen for lifecycle state changes through the action bus.
```go
c.RegisterAction(func(_ *core.Core, msg core.Message) core.Result {
switch msg.(type) {
case core.ActionServiceStartup:
core.Info("core startup completed")
case core.ActionServiceShutdown:
core.Info("core shutdown started")
}
return core.Result{OK: true}
})
```
## Background Task Draining
`ServiceShutdown` waits for the internal task waitgroup to finish before calling stop hooks.
This is what makes `PerformAsync` safe for long-running work that should complete before teardown.
## `OnReload`
`Service` includes an `OnReload` callback field, but CoreGO does not currently expose a top-level lifecycle runner for reload operations.