Files
CHORUS/pkg/shutdown/components.go
anthonyrawlins 543ab216f9 Complete BZZZ functionality port to CHORUS
🎭 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>
2025-09-02 20:02:37 +10:00

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()
}
}