iop/apps/node/internal/adapters/registry.go
toki 1176ed844f fix(cli): add START_MARKER assertion and fix Stop comment (REVIEW_REVIEW_API_FOLLOWUP_4)
- Add START_MARKER verification in TestCLIStartPartialRollbackWithMarkers
- Add requireEventually and readMarker helper functions
- Update CLI.Stop comment to match actual implementation
- Fix all gofmt issues
- SIGKILL cannot trigger trap EXIT, so verify START_MARKER instead
2026-05-03 16:02:37 +09:00

104 lines
2.7 KiB
Go

package adapters
import (
"context"
"fmt"
"iop/apps/node/internal/runtime"
)
// LifecycleAdapter is an optional interface for adapters that need start/stop lifecycle management.
type LifecycleAdapter interface {
Start(ctx context.Context) error
Stop(ctx context.Context) error
}
// Registry holds all registered adapters by name.
type Registry struct {
adapters map[string]runtime.Adapter
order []string // insertion order — first registered is the default
}
func NewRegistry() *Registry {
return &Registry{adapters: make(map[string]runtime.Adapter)}
}
// Register adds an adapter. The first registered adapter becomes the default.
func (r *Registry) Register(a runtime.Adapter) {
name := a.Name()
if _, exists := r.adapters[name]; !exists {
r.order = append(r.order, name)
}
r.adapters[name] = a
}
func (r *Registry) Get(name string) (runtime.Adapter, bool) {
a, ok := r.adapters[name]
return a, ok
}
func (r *Registry) Default() string {
if len(r.order) == 0 {
return ""
}
return r.order[0]
}
// All returns all registered adapters in registration order.
func (r *Registry) All() []runtime.Adapter {
out := make([]runtime.Adapter, 0, len(r.order))
for _, name := range r.order {
out = append(out, r.adapters[name])
}
return out
}
// MustGet returns the adapter or panics — useful during bootstrap validation.
func (r *Registry) MustGet(name string) runtime.Adapter {
a, ok := r.Get(name)
if !ok {
panic(fmt.Sprintf("adapter %q not registered", name))
}
return a
}
// Start calls Start on all registered LifecycleAdapters in registration order.
// On failure, already-started adapters are stopped in reverse order before returning.
func (r *Registry) Start(ctx context.Context) error {
started := make([]string, 0, len(r.order))
for _, name := range r.order {
lc, ok := r.adapters[name].(LifecycleAdapter)
if !ok {
continue
}
if err := lc.Start(ctx); err != nil {
for i := len(started) - 1; i >= 0; i-- {
if startedLC, ok := r.adapters[started[i]].(LifecycleAdapter); ok {
_ = startedLC.Stop(context.Background())
}
}
return fmt.Errorf("adapter %q start: %w", name, err)
}
started = append(started, name)
}
return nil
}
// Stop calls Stop on all registered LifecycleAdapters in reverse registration order.
// All adapters are stopped even if some fail; the first error is returned.
func (r *Registry) Stop(ctx context.Context) error {
var firstErr error
for i := len(r.order) - 1; i >= 0; i-- {
name := r.order[i]
lc, ok := r.adapters[name].(LifecycleAdapter)
if !ok {
continue
}
if err := lc.Stop(ctx); err != nil {
if firstErr == nil {
firstErr = fmt.Errorf("adapter %q stop: %w", name, err)
}
}
}
return firstErr
}