Documentation
¶
Overview ¶
Package runner provides thread-safe lifecycle management for long-running services and periodic tasks. It offers two execution patterns:
- startStop: Service lifecycle with blocking start and graceful stop
- ticker: Periodic execution at regular intervals
All implementations are thread-safe with atomic operations, context-aware, and include automatic error collection and panic recovery.
Example usage with HTTP server:
runner := startStop.New(
func(ctx context.Context) error {
return httpServer.ListenAndServe() // Blocks until stopped
},
func(ctx context.Context) error {
return httpServer.Shutdown(ctx) // Graceful shutdown
},
)
runner.Start(context.Background())
defer runner.Stop(context.Background())
Example usage with periodic task:
ticker := ticker.New(30*time.Second, func(ctx context.Context, tck *time.Ticker) error {
return performHealthCheck() // Executes every 30 seconds
})
ticker.Start(context.Background())
defer ticker.Stop(context.Background())
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func RecoveryCaller ¶
RecoveryCaller logs a recovered panic with a stack trace to stderr. This function is safe to call with nil rec (it will do nothing), making it convenient for use in defer statements with recover().
It prints:
- The process name and panic value
- Any additional data passed via the data parameter
- Up to 10 frames of stack trace with file paths and line numbers
The output is written to stderr to avoid interfering with normal program output. This function is used internally by all runner implementations to prevent panics from crashing the entire process.
Parameters:
- proc: A descriptive name for the process/function where the panic occurred
- rec: The value returned by recover() (can be nil)
- data: Optional additional data to include in the output
Example usage in a defer statement:
defer func() {
if r := recover(); r != nil {
runner.RecoveryCaller("myservice/mypackage/myfunction", r)
}
}()
Example with additional data:
defer func() {
if r := recover(); r != nil {
runner.RecoveryCaller("myservice/mypackage/myfunction", r, "WorkerID:", workerID)
}
}()
Output format:
Recovering process 'process-name': panic-value additional-data trace #0 => Line: 123 - File: /path/to/file.go trace #1 => Line: 456 - File: /path/to/other.go
func RunNbr ¶
RunNbr performs a polling operation up to max attempts, executing chk() to test a condition and run() between checks. This is useful for retry logic with a fixed number of attempts.
The function executes in this order:
- Check condition with chk()
- If true, return true immediately
- Otherwise, execute run() (typically a sleep or state update)
- Repeat up to max times
- Perform final check and return result
Parameters:
- max: Maximum number of retry attempts (0 means only final check)
- chk: Function to check if condition is met
- run: Function to execute between checks (e.g., time.Sleep)
Returns true if the condition is met within max attempts, false otherwise.
Example:
success := runner.RunNbr(10,
func() bool { return server.IsReady() },
func() { time.Sleep(100 * time.Millisecond) },
)
func RunTick ¶
RunTick performs a polling operation with timeout and tick interval, executing chk() to test a condition and run() between checks. This is useful for waiting on async operations with both time limits and context cancellation support.
The function uses a time.Ticker to check the condition at regular intervals until either the condition is met, the context is cancelled, or the maximum duration is exceeded.
Parameters:
- ctx: Context for cancellation (returns false if cancelled)
- tick: Interval between checks
- max: Maximum total duration to wait
- chk: Function to check if condition is met
- run: Function to execute between checks
Returns:
- true if the condition is met within max duration
- false if context is cancelled or max duration exceeded
Example:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
ready := runner.RunTick(ctx,
500*time.Millisecond, // Check every 500ms
10*time.Second, // Give up after 10s
func() bool { return db.IsConnected() },
func() { log.Println("Waiting for database...") },
)
Types ¶
type FunCheck ¶
type FunCheck func() bool
FunCheck is a function type that checks if a condition is met. It returns true if the condition is satisfied, false otherwise. Used by RunNbr and RunTick for polling operations.
type FunRun ¶
type FunRun func()
FunRun is a function type that performs an action between checks. Typically used for sleep operations or state updates in polling loops. Used by RunNbr and RunTick for actions between condition checks.
type FuncAction ¶
FuncAction represents a function that performs an action with context support. It is used by the startStop subpackage for both start and stop operations. The function should respect context cancellation and return any errors encountered.
The start function typically blocks until the service terminates, while the stop function performs cleanup and graceful shutdown operations.
type FuncTicker ¶
FuncTicker represents a function executed by the ticker at regular intervals. It receives both the context (which will be cancelled on Stop) and the underlying time.Ticker for advanced control if needed.
The function is called repeatedly until the ticker is stopped or the context is cancelled. Errors are collected and can be retrieved via ErrorsLast() or ErrorsList(). Returning an error does not stop the ticker.
Example:
func(ctx context.Context, tck *time.Ticker) error {
if err := performTask(); err != nil {
return fmt.Errorf("task failed: %w", err)
}
return nil
}
type Runner ¶
type Runner interface {
// Start launches the runner with the given context. For startStop runners,
// the start function executes asynchronously in a goroutine. For ticker
// runners, execution begins at regular intervals.
//
// If the runner is already running, it will be stopped first to ensure
// clean state transition. The context is used to create a cancellable
// child context for the runner's lifecycle.
//
// Returns an error if the context is nil. Operational errors are collected
// internally and retrievable via the Errors interface (if available).
Start(ctx context.Context) error
// Stop gracefully stops the runner if it is currently running. This is an
// idempotent operation - calling Stop on an already stopped runner is safe
// and returns nil immediately.
//
// The method cancels the runner's context and waits for cleanup to complete
// using exponential backoff polling (up to 2 seconds). For startStop runners,
// the stop function is also called asynchronously.
//
// Returns an error if the context is nil. The context is used for timeout
// control but not for the stop operation itself.
Stop(ctx context.Context) error
// Restart atomically stops the runner (if running) and starts it again with
// a fresh state. This is equivalent to calling Stop() followed by Start(),
// but ensures atomicity through mutex protection.
//
// Previous errors are cleared on restart. The context is used for both
// the stop and start operations.
//
// Returns an error if the context is nil or if the stop/start operations fail.
Restart(ctx context.Context) error
// IsRunning returns true if the runner is currently active. This is determined
// by checking if the uptime is greater than zero.
//
// This method uses atomic operations for lock-free reads and is safe to call
// concurrently from multiple goroutines.
IsRunning() bool
// Uptime returns the duration since the runner was started. Returns 0 if the
// runner is not currently running.
//
// This method uses atomic operations for lock-free reads and is safe to call
// concurrently from multiple goroutines. The uptime is calculated from the
// atomically stored start time.
Uptime() time.Duration
}
Runner defines the core interface for lifecycle management of services and tasks. It provides operations to start, stop, restart, and monitor the running state of a managed component.
All methods are thread-safe and can be called concurrently from multiple goroutines. State transitions are properly synchronized using atomic operations and mutexes.
Implementations include:
- startStop.StartStop: For long-running services with blocking start functions
- ticker.Ticker: For periodic task execution at regular intervals
type WaitNotify ¶
type WaitNotify interface {
// StartWaitNotify begins waiting for notifications with the given context.
StartWaitNotify(ctx context.Context)
// StopWaitNotify stops waiting for notifications.
StopWaitNotify()
}
WaitNotify is an optional interface that can be implemented by runners to support waiting for startup completion or receiving notifications. This interface is currently not implemented by the standard runner types but is defined for future extensibility.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package startStop provides a thread-safe runner for managing service lifecycle with start and stop operations.
|
Package startStop provides a thread-safe runner for managing service lifecycle with start and stop operations. |
|
Package ticker provides a ticker-based runner implementation that executes a function at regular intervals.
|
Package ticker provides a ticker-based runner implementation that executes a function at regular intervals. |