mirror of
https://github.com/hanzoai/traces.git
synced 2026-10-30 18:20:41 +00:00
See https://github.com/grafana/dskit/issues/576 Signed-off-by: Daniel Strobusch <[email protected]>
127 lines
5.9 KiB
Go
127 lines
5.9 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
)
|
|
|
|
// State of the service. See Service interface for full state diagram.
|
|
type State int
|
|
|
|
// Possible states to represent the service State.
|
|
const (
|
|
New State = iota // New: Service is new, not running yet. Initial State.
|
|
Starting // Starting: Service is starting. If starting succeeds, service enters Running state.
|
|
Running // Running: Service is fully running now. When service stops running, it enters Stopping state.
|
|
Stopping // Stopping: Service is shutting down
|
|
Terminated // Terminated: Service has stopped successfully. Terminal state.
|
|
Failed // Failed: Service has failed in Starting, Running or Stopping state. Terminal state.
|
|
)
|
|
|
|
func (s State) String() string {
|
|
switch s {
|
|
case New:
|
|
return "New"
|
|
case Starting:
|
|
return "Starting"
|
|
case Running:
|
|
return "Running"
|
|
case Stopping:
|
|
return "Stopping"
|
|
case Terminated:
|
|
return "Terminated"
|
|
case Failed:
|
|
return "Failed"
|
|
default:
|
|
return fmt.Sprintf("Unknown state: %d", s)
|
|
}
|
|
}
|
|
|
|
// Service defines interface for controlling a service.
|
|
//
|
|
// State diagram for the service:
|
|
//
|
|
// ┌────────────────────────────────────────────────────────────────────┐
|
|
// │ │
|
|
// │ ▼
|
|
// ┌─────┐ ┌──────────┐ ┌─────────┐ ┌──────────┐ ┌────────────┐
|
|
// │ New │─────▶│ Starting │─────▶│ Running │────▶│ Stopping │───┬─▶│ Terminated │
|
|
// └─────┘ └──────────┘ └─────────┘ └──────────┘ │ └────────────┘
|
|
// │ │
|
|
// │ │
|
|
// │ │ ┌────────┐
|
|
// └──────────────────────────────────────────┴──▶│ Failed │
|
|
// └────────┘
|
|
type Service interface {
|
|
// StartAsync starts Service asynchronously. Service must be in New State, otherwise error is returned.
|
|
// Context is used as a parent context for service own context.
|
|
StartAsync(ctx context.Context) error
|
|
|
|
// AwaitRunning waits until service gets into Running state.
|
|
// If service is in New or Starting state, this method is blocking.
|
|
// If service is already in Running state, returns immediately with no error.
|
|
// If service is in a state, from which it cannot get into Running state, error is returned immediately.
|
|
AwaitRunning(ctx context.Context) error
|
|
|
|
// StopAsync tell the service to stop. This method doesn't block and can be called multiple times.
|
|
// If Service is New, it is Terminated without having been started nor stopped.
|
|
// If Service is in Starting or Running state, this initiates shutdown and returns immediately.
|
|
// If Service has already been stopped, this method returns immediately, without taking action.
|
|
StopAsync()
|
|
|
|
// AwaitTerminated waits for the service to reach Terminated or Failed state. If service is already in one of these states,
|
|
// when method is called, method returns immediately.
|
|
// If service enters Terminated state, this method returns nil.
|
|
// If service enters Failed state, or context is finished before reaching Terminated or Failed, error is returned.
|
|
AwaitTerminated(ctx context.Context) error
|
|
|
|
// FailureCase returns error if Service is in Failed state.
|
|
// If Service is not in Failed state, this method returns nil.
|
|
FailureCase() error
|
|
|
|
// State returns current state of the service.
|
|
State() State
|
|
|
|
// AddListener adds listener to this service. Listener will be notified on subsequent state transitions
|
|
// of the service. Previous state transitions are not replayed, so it is suggested to add listeners before
|
|
// service is started.
|
|
//
|
|
// AddListener guarantees execution ordering across calls to a given listener but not across calls to
|
|
// multiple listeners. Specifically, a given listener will have its callbacks invoked in the same order
|
|
// as the service enters those states. Additionally, at most one of the listener's callbacks will execute
|
|
// at once. However, multiple listeners' callbacks may execute concurrently, and listeners may execute
|
|
// in an order different from the one in which they were registered.
|
|
//
|
|
// Returned function can be used to stop the listener from receiving additional events from the service,
|
|
// and release resources used by the listener (e.g. goroutine, if it was started by adding listener).
|
|
AddListener(listener Listener) func()
|
|
}
|
|
|
|
// NamedService extends Service with a name.
|
|
type NamedService interface {
|
|
Service
|
|
|
|
// ServiceName returns name of the service, if it has one.
|
|
// Subsequent calls to ServiceName can return different values,
|
|
// for example service may update its name based on its state.
|
|
ServiceName() string
|
|
}
|
|
|
|
// Listener receives notifications about Service state changes.
|
|
type Listener interface {
|
|
// Starting is called when the service transitions from NEW to STARTING.
|
|
Starting()
|
|
|
|
// Running is called when the service transitions from STARTING to RUNNING.
|
|
Running()
|
|
|
|
// Stopping is called when the service transitions to the STOPPING state.
|
|
Stopping(from State)
|
|
|
|
// Terminated is called when the service transitions to the TERMINATED state.
|
|
Terminated(from State)
|
|
|
|
// Failed is called when the service transitions to the FAILED state.
|
|
Failed(from State, failure error)
|
|
}
|