### Create Simple Supervisor with Default Configuration (Go) Source: https://context7.com/thejerf/suture/llms.txt Demonstrates creating a supervisor with sensible defaults for basic use cases. It initializes a supervisor, adds a service, and then serves the supervisor. The service implements a simple Serve method that logs start and stop messages. ```go package main import ( "context" "fmt" "github.com/thejerf/suture/v4" ) type MyService struct { name string } func (s *MyService) Serve(ctx context.Context) error { fmt.Printf("Service %s started\n", s.name) <-ctx.Done() fmt.Printf("Service %s stopping\n", s.name) return nil } func main() { supervisor := suture.NewSimple("main") service1 := &MyService{name: "service1"} supervisor.Add(service1) ctx := context.Background() if err := supervisor.Serve(ctx); err != nil { fmt.Printf("Supervisor error: %v\n", err) } } ``` -------------------------------- ### Create Supervisor with Custom Configuration (Go) Source: https://context7.com/thejerf/suture/llms.txt Illustrates configuring a supervisor with custom failure thresholds, backoff timing, and event hooks. This example defines a `suture.Spec` to control failure decay, restart backoff, timeouts, and panic handling, then starts the supervisor in the background. ```go package main import ( "context" "fmt" "log" "time" "github.com/thejerf/suture/v4" ) func main() { spec := suture.Spec{ EventHook: func(e suture.Event) { log.Printf("Supervisor event: %s", e.String()) }, FailureDecay: 60, FailureThreshold: 3, FailureBackoff: 30 * time.Second, Timeout: 15 * time.Second, PassThroughPanics: false, } supervisor := suture.New("custom-supervisor", spec) service := &MyService{name: "worker"} token := supervisor.Add(service) ctx, cancel := context.WithCancel(context.Background()) defer cancel() errChan := supervisor.ServeBackground(ctx) time.Sleep(5 * time.Second) if err := supervisor.Remove(token); err != nil { log.Printf("Error removing service: %v", err) } cancel() if err := <-errChan; err != nil && err != context.Canceled { log.Printf("Supervisor terminated with error: %v", err) } } type MyService struct { name string } func (s *MyService) Serve(ctx context.Context) error { for { select { case <-ctx.Done(): return nil case <-time.After(1 * time.Second): fmt.Printf("%s working...\n", s.name) } } } ``` -------------------------------- ### Supervisor Stack Trace Example in synctest Source: https://github.com/thejerf/suture/blob/master/README.md This Go code snippet illustrates a typical stack trace observed when a service within a Suture supervisor tree fails to shut down correctly during a `synctest`. It helps diagnose deadlocks by showing the blocked goroutines related to the supervisor and the service. ```go github.com/thejerf/suture/v4.(*Supervisor).runService.func1() /home/jbowers/go/pkg/mod/github.com/thejerf/suture/v4@v4.0.6/supervisor.go:541 +0x2e github.com/thejerf/suture/v4.(*Supervisor).stopSupervisor.func1(0x0) /home/jbowers/go/pkg/mod/github.com/thejerf/suture/v4@v4.0.6/supervisor.go:618 +0x27 ``` ```go github.com/thejerf/suture/v4.(*Supervisor).stopSupervisor(0xc00016c8c0) /home/jbowers/go/pkg/mod/github.com/thejerf/suture/v4@v4.0.6/supervisor.go:627 +0x373 github.com/thejerf/suture/v4.(*Supervisor).Serve(0xc00016c8c0, {0xa4d4f8?, 0xc0001505a0?}) /home/jbowers/go/pkg/mod/github.com/thejerf/suture/v4@v4.0.6/supervisor.go:356 +0xd3b ``` -------------------------------- ### Creating a Simple Supervisor (v4) Source: https://context7.com/thejerf/suture/llms.txt This endpoint demonstrates how to create a supervisor with sensible defaults for basic use cases using `suture.NewSimple`. ```APIDOC ## Creating a Simple Supervisor (v4) ### Description Creates a supervisor with sensible defaults for basic use cases. ### Method N/A (Code Example) ### Endpoint N/A (Code Example) ### Parameters N/A ### Request Example ```go package main import ( "context" "fmt" "github.com/thejerf/suture/v4" ) type MyService struct { name string } func (s *MyService) Serve(ctx context.Context) error { fmt.Printf("Service %s started\n", s.name) <-ctx.Done() fmt.Printf("Service %s stopping\n", s.name) return nil } func main() { supervisor := suture.NewSimple("main") service1 := &MyService{name: "service1"} supervisor.Add(service1) ctx := context.Background() if err := supervisor.Serve(ctx); err != nil { fmt.Printf("Supervisor error: %v\n", err) } } ``` ### Response #### Success Response (200) N/A (Code Example) #### Response Example N/A (Code Example) ``` -------------------------------- ### Import Suture v3 Package (No Contexts) Source: https://github.com/thejerf/suture/blob/master/README.md This Go code snippet demonstrates how to import the older v3 version of the Suture library, which predates Go's context package. This version is still supported and receives backported fixes. ```go import "gopkg.in/thejerf/suture.v3" ``` -------------------------------- ### Creating a Supervisor with Custom Configuration (v4) Source: https://context7.com/thejerf/suture/llms.txt This endpoint shows how to configure a supervisor with custom failure thresholds, backoff timing, and event hooks using `suture.New` and `suture.Spec`. ```APIDOC ## Creating a Supervisor with Custom Configuration (v4) ### Description Configures a supervisor with custom failure thresholds, backoff timing, and event hooks. ### Method N/A (Code Example) ### Endpoint N/A (Code Example) ### Parameters #### Request Body - **spec** (suture.Spec) - Required - Configuration for the supervisor. - **EventHook** (func(suture.Event)) - Optional - Callback for supervisor events. - **FailureDecay** (time.Duration) - Optional - Duration for failure decay. - **FailureThreshold** (int) - Optional - Number of failures before entering backoff. - **FailureBackoff** (time.Duration) - Optional - Duration to wait in backoff mode. - **Timeout** (time.Duration) - Optional - Timeout for service shutdown. - **PassThroughPanics** (bool) - Optional - Whether to propagate panics. ### Request Example ```go package main import ( "context" "fmt" "log" "time" "github.com/thejerf/suture/v4" ) func main() { spec := suture.Spec{ EventHook: func(e suture.Event) { log.Printf("Supervisor event: %s", e.String()) }, FailureDecay: 60 * time.Second, // failures decay over 60 seconds FailureThreshold: 3, // enter backoff after 3 failures FailureBackoff: 30 * time.Second, // wait 30s in backoff mode Timeout: 15 * time.Second, // wait 15s for service shutdown PassThroughPanics: false, // catch panics, don't propagate } supervisor := suture.New("custom-supervisor", spec) service := &MyService{name: "worker"} token := supervisor.Add(service) ctx, cancel := context.WithCancel(context.Background()) defer cancel() errChan := supervisor.ServeBackground(ctx) time.Sleep(5 * time.Second) if err := supervisor.Remove(token); err != nil { log.Printf("Error removing service: %v", err) } cancel() if err := <-errChan; err != nil && err != context.Canceled { log.Printf("Supervisor terminated with error: %v", err) } } type MyService struct { name string } func (s *MyService) Serve(ctx context.Context) error { for { select { case <-ctx.Done(): return nil case <-time.After(1 * time.Second): fmt.Printf("%s working...\n", s.name) } } } ``` ### Response #### Success Response (200) N/A (Code Example) #### Response Example N/A (Code Example) ``` -------------------------------- ### Create Nested Supervisor Trees with Suture v4 (Go) Source: https://context7.com/thejerf/suture/llms.txt Illustrates how to build hierarchical supervisor structures by nesting supervisors within other supervisors. This allows for modular management of related services and sub-supervisors, improving application organization. ```go package main import ( "context" "fmt" "time" "github.com/thejerf/suture/v4" ) type WorkerService struct { name string } func (s *WorkerService) Serve(ctx context.Context) error { ticker := time.NewTicker(1 * time.Second) defer ticker.Stop() for { select { case <-ctx.Done(): fmt.Printf("%s shutting down\n", s.name) return nil case <-ticker.C: fmt.Printf("%s tick\n", s.name) } } } func main() { // Create top-level supervisor mainSupervisor := suture.NewSimple("main") // Create database services supervisor dbSupervisor := suture.NewSimple("database") dbSupervisor.Add(&WorkerService{name: "db-reader"}) dbSupervisor.Add(&WorkerService{name: "db-writer"}) // Create API services supervisor apiSupervisor := suture.NewSimple("api") apiSupervisor.Add(&WorkerService{name: "api-server"}) apiSupervisor.Add(&WorkerService{name: "websocket-server"}) // Add sub-supervisors to main supervisor mainSupervisor.Add(dbSupervisor) mainSupervisor.Add(apiSupervisor) // Add standalone services mainSupervisor.Add(&WorkerService{name: "metrics-collector"}) ctx, cancel := context.WithCancel(context.Background()) go func() { time.Sleep(5 * time.Second) fmt.Println("\nShutting down entire tree...") cancel() }() if err := mainSupervisor.Serve(ctx); err != nil && err != context.Canceled { fmt.Printf("Supervisor error: %v\n", err) } fmt.Println("All services stopped gracefully") } ``` -------------------------------- ### Import Suture v4 Package Source: https://github.com/thejerf/suture/blob/master/README.md This snippet shows how to import the main Suture supervisor package for use in Go projects. It is the primary entry point for utilizing the library's functionalities. ```go import "github.com/thejerf/suture/v4" ``` -------------------------------- ### Import Sutureslog Package for Suture Logging Source: https://github.com/thejerf/suture/blob/master/README.md This snippet shows how to import the `sutureslog` package, a separate Go module that provides a default slog-based logger for Suture. This separation avoids forcing the main Suture module to require Go 1.21. ```go import "github.com/thejerf/sutureslog" ``` -------------------------------- ### Dynamically Add and Remove Services with Suture v4 (Go) Source: https://context7.com/thejerf/suture/llms.txt Demonstrates how to add new services to a Suture supervisor while it's running and how to remove them, including handling timeouts for removal. This is useful for applications requiring flexible service management. ```go package main import ( "context" "fmt" "time" "github.com/thejerf/suture/v4" ) type DynamicService struct { name string } func (s *DynamicService) Serve(ctx context.Context) error { fmt.Printf("Service %s starting\n", s.name) <-ctx.Done() time.Sleep(100 * time.Millisecond) // simulate cleanup fmt.Printf("Service %s stopped\n", s.name) return nil } func main() { supervisor := suture.NewSimple("dynamic-supervisor") ctx, cancel := context.WithCancel(context.Background()) defer cancel() supervisor.ServeBackground(ctx) // Add services while supervisor is running token1 := supervisor.Add(&DynamicService{name: "svc1"}) token2 := supervisor.Add(&DynamicService{name: "svc2"}) token3 := supervisor.Add(&DynamicService{name: "svc3"}) time.Sleep(2 * time.Second) // Remove service with wait timeout fmt.Println("Removing svc2...") if err := supervisor.RemoveAndWait(token2, 5*time.Second); err != nil { if err == suture.ErrTimeout { fmt.Println("Service removal timed out") } else { fmt.Printf("Error removing service: %v\n", err) } } // List remaining services services := supervisor.Services() fmt.Printf("Active services: %d\n", len(services)) // Remove without waiting supervisor.Remove(token1) supervisor.Remove(token3) time.Sleep(500 * time.Millisecond) cancel() } ``` -------------------------------- ### Service with Controlled Restart Behavior (v4) Source: https://context7.com/thejerf/suture/llms.txt This endpoint demonstrates implementing services that can signal controlled termination or critical failures, influencing supervisor restart behavior. ```APIDOC ## Service with Controlled Restart Behavior (v4) ### Description Implements a service that can signal it should not be restarted or should terminate the entire supervisor tree. ### Method N/A (Code Example) ### Endpoint N/A (Code Example) ### Parameters N/A ### Request Example ```go package main import ( "context" "errors" "fmt" "time" "github.com/thejerf/suture/v4" ) type SmartService struct { name string workCount int maxWork int } func (s *SmartService) Serve(ctx context.Context) error { for s.workCount < s.maxWork { select { case <-ctx.Done(): return ctx.Err() case <-time.After(1 * time.Second): s.workCount++ fmt.Printf("%s completed work %d/%d\n", s.name, s.workCount, s.maxWork) } } // Signal that this service completed normally and should not restart return suture.ErrDoNotRestart } type CriticalService struct { name string } func (s *CriticalService) Serve(ctx context.Context) error { select { case <-ctx.Done(): return ctx.Err() case <-time.After(2 * time.Second): // Critical error - terminate entire supervisor tree return fmt.Errorf("critical failure: %w", suture.ErrTerminateSupervisorTree) } } func main() { supervisor := suture.NewSimple("smart-supervisor") smartService := &SmartService{name: "worker", maxWork: 5} supervisor.Add(smartService) ctx := context.Background() if err := supervisor.Serve(ctx); err != nil { if errors.Is(err, suture.ErrDoNotRestart) { fmt.Println("Service completed successfully") } else { fmt.Printf("Supervisor error: %v\n", err) } } } ``` ### Response #### Success Response (200) N/A (Code Example) #### Response Example N/A (Code Example) ``` -------------------------------- ### Service with Controlled Restart Behavior (Go) Source: https://context7.com/thejerf/suture/llms.txt Shows how to implement services that signal completion or critical failure. `SmartService` completes its work and returns `suture.ErrDoNotRestart` to prevent restarts, while `CriticalService` returns an error wrapping `suture.ErrTerminateSupervisorTree` to stop the entire supervisor. ```go package main import ( "context" "errors" "fmt" "time" "github.com/thejerf/suture/v4" ) type SmartService struct { name string workCount int maxWork int } func (s *SmartService) Serve(ctx context.Context) error { for s.workCount < s.maxWork { select { case <-ctx.Done(): return ctx.Err() case <-time.After(1 * time.Second): s.workCount++ fmt.Printf("%s completed work %d/%d\n", s.name, s.workCount, s.maxWork) } } return suture.ErrDoNotRestart } type CriticalService struct { name string } func (s *CriticalService) Serve(ctx context.Context) error { select { case <-ctx.Done(): return ctx.Err() case <-time.After(2 * time.Second): return fmt.Errorf("critical failure: %w", suture.ErrTerminateSupervisorTree) } } func main() { supervisor := suture.NewSimple("smart-supervisor") smartService := &SmartService{name: "worker", maxWork: 5} supervisor.Add(smartService) ctx := context.Background() if err := supervisor.Serve(ctx); err != nil { if errors.Is(err, suture.ErrDoNotRestart) { fmt.Println("Service completed successfully") } else { fmt.Printf("Supervisor error: %v\n", err) } } } ``` -------------------------------- ### Event Monitoring with Custom Hooks (Go) Source: https://context7.com/thejerf/suture/llms.txt Implements custom event hooks for Suture v4 to monitor service lifecycle events like terminations, panics, backoffs, and resumes. It allows for structured logging and debugging in production environments. The `EventHook` function is called for each Suture event. ```go package main import ( "context" "fmt" "log" "time" "github.com/thejerf/suture/v4" ) type UnstableService struct { name string failures int } func (s *UnstableService) Serve(ctx context.Context) error { s.failures++ if s.failures <= 3 { fmt.Printf("%s failing (attempt %d)\n", s.name, s.failures) time.Sleep(100 * time.Millisecond) return fmt.Errorf("simulated failure %d", s.failures) } fmt.Printf("%s now stable\n", s.name) <-ctx.Done() return nil } func main() { spec := suture.Spec{ EventHook: func(e suture.Event) { switch evt := e.(type) { case suture.EventServiceTerminate: log.Printf("[TERMINATE] Service: %s, Failures: %.1f/%.1f, Restarting: %v, Error: %v", evt.ServiceName, evt.CurrentFailures, evt.FailureThreshold, evt.Restarting, evt.Err) case suture.EventServicePanic: log.Printf("[PANIC] Service: %s, Msg: %s, Stack: %s", evt.ServiceName, evt.PanicMsg, evt.Stacktrace) case suture.EventBackoff: log.Printf("[BACKOFF] Supervisor %s entering backoff mode", evt.SupervisorName) case suture.EventResume: log.Printf("[RESUME] Supervisor %s resuming normal operation", evt.SupervisorName) case suture.EventStopTimeout: log.Printf("[TIMEOUT] Service %s failed to stop in time", evt.ServiceName) } // Event also provides Map() for structured logging eventMap := e.Map() fmt.Printf("Event data: %+v\n", eventMap) }, FailureThreshold: 2, FailureBackoff: 3 * time.Second, Timeout: 5 * time.Second, } supervisor := suture.New("monitored", spec) supervisor.Add(&UnstableService{name: "flaky-service"}) ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() if err := supervisor.Serve(ctx); err != nil && err != context.Canceled { log.Printf("Supervisor ended with error: %v", err) } } ``` -------------------------------- ### Reporting Unstopped Services (Go) Source: https://context7.com/thejerf/suture/llms.txt Retrieves a report of services that failed to stop within the configured timeout period during a supervisor's shutdown. This is useful for diagnosing issues where services might be stuck in cleanup routines. The `UnstoppedServiceReport()` method returns a list of services that did not stop gracefully. ```go package main import ( "context" "fmt" "time" "github.com/thejerf/suture/v4" ) type SlowService struct { name string stopDelay time.Duration } func (s *SlowService) Serve(ctx context.Context) error { fmt.Printf("%s started\n", s.name) <-ctx.Done() // Simulate slow cleanup fmt.Printf("%s cleaning up for %v...\n", s.name, s.stopDelay) time.Sleep(s.stopDelay) fmt.Printf("%s stopped\n", s.name) return nil } func main() { spec := suture.Spec{ Timeout: 2 * time.Second, // short timeout to demonstrate timeout handling } supervisor := suture.New("timeout-test", spec) // Add services with different stop times supervisor.Add(&SlowService{name: "fast", stopDelay: 500 * time.Millisecond}) supervisor.Add(&SlowService{name: "slow", stopDelay: 5 * time.Second}) supervisor.Add(&SlowService{name: "medium", stopDelay: 1 * time.Second}) ctx, cancel := context.WithCancel(context.Background()) go func() { time.Sleep(1 * time.Second) fmt.Println("\nInitiating shutdown...") cancel() }() errChan := make(chan error) go func() { errChan <- supervisor.Serve(ctx) }() // Wait for supervisor to finish if err := <-errChan; err != nil && err != context.Canceled { fmt.Printf("Supervisor error: %v\n", err) } // Get report of services that didn't stop report, err := supervisor.UnstoppedServiceReport() if err != nil { fmt.Printf("Error getting report: %v\n", err) return } if report != nil && len(report) > 0 { fmt.Printf("\n%d service(s) failed to stop:\n", len(report)) for _, unstopped := range report { fmt.Printf(" - %s (token: %v)\n", unstopped.Name, unstopped.ServiceToken) } } else { fmt.Println("\nAll services stopped successfully") } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.