🎭 CHORUS now contains full BZZZ functionality adapted for containers Core systems ported: - P2P networking (libp2p with DHT and PubSub) - Task coordination (COOEE protocol) - HMMM collaborative reasoning - SHHH encryption and security - SLURP admin election system - UCXL content addressing - UCXI server integration - Hypercore logging system - Health monitoring and graceful shutdown - License validation with KACHING Container adaptations: - Environment variable configuration (no YAML files) - Container-optimized logging to stdout/stderr - Auto-generated agent IDs for container deployments - Docker-first architecture All proven BZZZ P2P protocols, AI integration, and collaboration features are now available in containerized form. Next: Build and test container deployment. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
369 lines
7.6 KiB
Go
369 lines
7.6 KiB
Go
package shutdown
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// HTTPServerComponent wraps an HTTP server for graceful shutdown
|
|
type HTTPServerComponent struct {
|
|
name string
|
|
server *http.Server
|
|
priority int
|
|
}
|
|
|
|
// NewHTTPServerComponent creates a new HTTP server component
|
|
func NewHTTPServerComponent(name string, server *http.Server, priority int) *HTTPServerComponent {
|
|
return &HTTPServerComponent{
|
|
name: name,
|
|
server: server,
|
|
priority: priority,
|
|
}
|
|
}
|
|
|
|
func (h *HTTPServerComponent) Name() string {
|
|
return h.name
|
|
}
|
|
|
|
func (h *HTTPServerComponent) Priority() int {
|
|
return h.priority
|
|
}
|
|
|
|
func (h *HTTPServerComponent) CanForceStop() bool {
|
|
return true
|
|
}
|
|
|
|
func (h *HTTPServerComponent) Shutdown(ctx context.Context) error {
|
|
if h.server == nil {
|
|
return nil
|
|
}
|
|
|
|
return h.server.Shutdown(ctx)
|
|
}
|
|
|
|
// P2PNodeComponent wraps a P2P node for graceful shutdown
|
|
type P2PNodeComponent struct {
|
|
name string
|
|
closer func() error
|
|
priority int
|
|
}
|
|
|
|
// NewP2PNodeComponent creates a new P2P node component
|
|
func NewP2PNodeComponent(name string, closer func() error, priority int) *P2PNodeComponent {
|
|
return &P2PNodeComponent{
|
|
name: name,
|
|
closer: closer,
|
|
priority: priority,
|
|
}
|
|
}
|
|
|
|
func (p *P2PNodeComponent) Name() string {
|
|
return p.name
|
|
}
|
|
|
|
func (p *P2PNodeComponent) Priority() int {
|
|
return p.priority
|
|
}
|
|
|
|
func (p *P2PNodeComponent) CanForceStop() bool {
|
|
return true
|
|
}
|
|
|
|
func (p *P2PNodeComponent) Shutdown(ctx context.Context) error {
|
|
if p.closer == nil {
|
|
return nil
|
|
}
|
|
|
|
// P2P nodes typically need time to disconnect gracefully
|
|
done := make(chan error, 1)
|
|
go func() {
|
|
done <- p.closer()
|
|
}()
|
|
|
|
select {
|
|
case err := <-done:
|
|
return err
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
}
|
|
}
|
|
|
|
// DatabaseComponent wraps a database connection for graceful shutdown
|
|
type DatabaseComponent struct {
|
|
name string
|
|
closer func() error
|
|
priority int
|
|
}
|
|
|
|
// NewDatabaseComponent creates a new database component
|
|
func NewDatabaseComponent(name string, closer func() error, priority int) *DatabaseComponent {
|
|
return &DatabaseComponent{
|
|
name: name,
|
|
closer: closer,
|
|
priority: priority,
|
|
}
|
|
}
|
|
|
|
func (d *DatabaseComponent) Name() string {
|
|
return d.name
|
|
}
|
|
|
|
func (d *DatabaseComponent) Priority() int {
|
|
return d.priority
|
|
}
|
|
|
|
func (d *DatabaseComponent) CanForceStop() bool {
|
|
return false // Databases shouldn't be force-stopped
|
|
}
|
|
|
|
func (d *DatabaseComponent) Shutdown(ctx context.Context) error {
|
|
if d.closer == nil {
|
|
return nil
|
|
}
|
|
|
|
return d.closer()
|
|
}
|
|
|
|
// ElectionManagerComponent wraps an election manager for graceful shutdown
|
|
type ElectionManagerComponent struct {
|
|
name string
|
|
stopper func()
|
|
priority int
|
|
}
|
|
|
|
// NewElectionManagerComponent creates a new election manager component
|
|
func NewElectionManagerComponent(name string, stopper func(), priority int) *ElectionManagerComponent {
|
|
return &ElectionManagerComponent{
|
|
name: name,
|
|
stopper: stopper,
|
|
priority: priority,
|
|
}
|
|
}
|
|
|
|
func (e *ElectionManagerComponent) Name() string {
|
|
return e.name
|
|
}
|
|
|
|
func (e *ElectionManagerComponent) Priority() int {
|
|
return e.priority
|
|
}
|
|
|
|
func (e *ElectionManagerComponent) CanForceStop() bool {
|
|
return true
|
|
}
|
|
|
|
func (e *ElectionManagerComponent) Shutdown(ctx context.Context) error {
|
|
if e.stopper == nil {
|
|
return nil
|
|
}
|
|
|
|
// Election managers need special handling to transfer leadership
|
|
done := make(chan struct{})
|
|
go func() {
|
|
e.stopper()
|
|
close(done)
|
|
}()
|
|
|
|
select {
|
|
case <-done:
|
|
return nil
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
}
|
|
}
|
|
|
|
// PubSubComponent wraps a PubSub system for graceful shutdown
|
|
type PubSubComponent struct {
|
|
name string
|
|
closer func() error
|
|
priority int
|
|
}
|
|
|
|
// NewPubSubComponent creates a new PubSub component
|
|
func NewPubSubComponent(name string, closer func() error, priority int) *PubSubComponent {
|
|
return &PubSubComponent{
|
|
name: name,
|
|
closer: closer,
|
|
priority: priority,
|
|
}
|
|
}
|
|
|
|
func (p *PubSubComponent) Name() string {
|
|
return p.name
|
|
}
|
|
|
|
func (p *PubSubComponent) Priority() int {
|
|
return p.priority
|
|
}
|
|
|
|
func (p *PubSubComponent) CanForceStop() bool {
|
|
return true
|
|
}
|
|
|
|
func (p *PubSubComponent) Shutdown(ctx context.Context) error {
|
|
if p.closer == nil {
|
|
return nil
|
|
}
|
|
|
|
return p.closer()
|
|
}
|
|
|
|
// MonitoringComponent wraps a monitoring system for graceful shutdown
|
|
type MonitoringComponent struct {
|
|
name string
|
|
closer func() error
|
|
priority int
|
|
}
|
|
|
|
// NewMonitoringComponent creates a new monitoring component
|
|
func NewMonitoringComponent(name string, closer func() error, priority int) *MonitoringComponent {
|
|
return &MonitoringComponent{
|
|
name: name,
|
|
closer: closer,
|
|
priority: priority,
|
|
}
|
|
}
|
|
|
|
func (m *MonitoringComponent) Name() string {
|
|
return m.name
|
|
}
|
|
|
|
func (m *MonitoringComponent) Priority() int {
|
|
return m.priority
|
|
}
|
|
|
|
func (m *MonitoringComponent) CanForceStop() bool {
|
|
return true
|
|
}
|
|
|
|
func (m *MonitoringComponent) Shutdown(ctx context.Context) error {
|
|
if m.closer == nil {
|
|
return nil
|
|
}
|
|
|
|
return m.closer()
|
|
}
|
|
|
|
// GenericComponent provides a generic wrapper for any component with a close function
|
|
type GenericComponent struct {
|
|
name string
|
|
closer func() error
|
|
priority int
|
|
canForceStop bool
|
|
shutdownFunc func(ctx context.Context) error
|
|
}
|
|
|
|
// NewGenericComponent creates a new generic component
|
|
func NewGenericComponent(name string, priority int, canForceStop bool) *GenericComponent {
|
|
return &GenericComponent{
|
|
name: name,
|
|
priority: priority,
|
|
canForceStop: canForceStop,
|
|
}
|
|
}
|
|
|
|
// SetCloser sets a simple closer function
|
|
func (g *GenericComponent) SetCloser(closer func() error) *GenericComponent {
|
|
g.closer = closer
|
|
return g
|
|
}
|
|
|
|
// SetShutdownFunc sets a context-aware shutdown function
|
|
func (g *GenericComponent) SetShutdownFunc(shutdownFunc func(ctx context.Context) error) *GenericComponent {
|
|
g.shutdownFunc = shutdownFunc
|
|
return g
|
|
}
|
|
|
|
func (g *GenericComponent) Name() string {
|
|
return g.name
|
|
}
|
|
|
|
func (g *GenericComponent) Priority() int {
|
|
return g.priority
|
|
}
|
|
|
|
func (g *GenericComponent) CanForceStop() bool {
|
|
return g.canForceStop
|
|
}
|
|
|
|
func (g *GenericComponent) Shutdown(ctx context.Context) error {
|
|
if g.shutdownFunc != nil {
|
|
return g.shutdownFunc(ctx)
|
|
}
|
|
|
|
if g.closer != nil {
|
|
// Wrap simple closer in context-aware function
|
|
done := make(chan error, 1)
|
|
go func() {
|
|
done <- g.closer()
|
|
}()
|
|
|
|
select {
|
|
case err := <-done:
|
|
return err
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// WorkerPoolComponent manages a pool of workers for graceful shutdown
|
|
type WorkerPoolComponent struct {
|
|
name string
|
|
stopCh chan struct{}
|
|
workers int
|
|
priority int
|
|
shutdownTime time.Duration
|
|
}
|
|
|
|
// NewWorkerPoolComponent creates a new worker pool component
|
|
func NewWorkerPoolComponent(name string, stopCh chan struct{}, workers int, priority int) *WorkerPoolComponent {
|
|
return &WorkerPoolComponent{
|
|
name: name,
|
|
stopCh: stopCh,
|
|
workers: workers,
|
|
priority: priority,
|
|
shutdownTime: 10 * time.Second,
|
|
}
|
|
}
|
|
|
|
func (w *WorkerPoolComponent) Name() string {
|
|
return fmt.Sprintf("%s (workers: %d)", w.name, w.workers)
|
|
}
|
|
|
|
func (w *WorkerPoolComponent) Priority() int {
|
|
return w.priority
|
|
}
|
|
|
|
func (w *WorkerPoolComponent) CanForceStop() bool {
|
|
return true
|
|
}
|
|
|
|
func (w *WorkerPoolComponent) Shutdown(ctx context.Context) error {
|
|
if w.stopCh == nil {
|
|
return nil
|
|
}
|
|
|
|
// Signal workers to stop
|
|
close(w.stopCh)
|
|
|
|
// Wait for workers to finish with timeout
|
|
timeout := w.shutdownTime
|
|
if deadline, ok := ctx.Deadline(); ok {
|
|
if remaining := time.Until(deadline); remaining < timeout {
|
|
timeout = remaining
|
|
}
|
|
}
|
|
|
|
// In a real implementation, you would wait for workers to signal completion
|
|
select {
|
|
case <-time.After(timeout):
|
|
return fmt.Errorf("workers did not shut down within %v", timeout)
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
}
|
|
} |