Documentation
¶
Overview ¶
Package tripswitch provides the official Go client SDK for Tripswitch, a circuit breaker management service.
The client maintains real-time circuit breaker state via Server-Sent Events (SSE) and automatically reports execution samples to the Tripswitch API. It is goroutine-safe and designed for high-throughput applications.
Authentication ¶
The runtime client uses two credentials:
- Project API key (eb_pk_...): For SSE subscriptions and state reads
- Ingest secret: For HMAC-signed sample ingestion
Create project keys via the admin API or Tripswitch dashboard.
Quick Start ¶
ts, err := tripswitch.NewClient(ctx, "proj_abc123",
tripswitch.WithAPIKey("eb_pk_..."), // project key for SSE
tripswitch.WithIngestSecret("..."), // 64-char hex string for HMAC
)
if err != nil {
log.Fatal(err)
}
defer ts.Close(context.Background())
// Wrap operations with circuit breaker
resp, err := tripswitch.Execute(ts, ctx, func() (*http.Response, error) {
return client.Do(req)
},
tripswitch.WithBreakers("external-api"), // Gating: block if breaker is open
tripswitch.WithRouter("router-id"), // Route samples to this router
tripswitch.WithMetrics(map[string]any{"latency": tripswitch.Latency}),
)
Circuit Breaker States ¶
The SDK handles three breaker states:
- closed: All requests allowed, results reported
- open: All requests rejected with ErrOpen
- half_open: Requests throttled based on allow_rate (probabilistic)
Error Handling ¶
Use IsBreakerError to check if an error is circuit breaker related:
if tripswitch.IsBreakerError(err) {
// Return cached/fallback response
}
Graceful Shutdown ¶
Always call Client.Close to flush buffered samples:
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() ts.Close(ctx)
Index ¶
- Constants
- Variables
- func Execute[T any](c *Client, ctx context.Context, task func() (T, error), opts ...ExecuteOption) (T, error)
- func IsBreakerError(err error) bool
- type BreakerMeta
- type BreakerStatus
- type Client
- func (c *Client) Close(ctx context.Context) error
- func (c *Client) GetAllStates() map[string]BreakerStatus
- func (c *Client) GetBreakersMetadata() []BreakerMeta
- func (c *Client) GetRoutersMetadata() []RouterMeta
- func (c *Client) GetState(name string) *BreakerStatus
- func (c *Client) GetStatus(ctx context.Context) (*Status, error)
- func (c *Client) ListBreakersMetadata(ctx context.Context, etag string) ([]BreakerMeta, string, error)
- func (c *Client) ListRoutersMetadata(ctx context.Context, etag string) ([]RouterMeta, string, error)
- func (c *Client) Report(input ReportInput)
- func (c *Client) Stats() SDKStats
- type ExecuteOption
- func WithBreakers(names ...string) ExecuteOption
- func WithDeferredMetrics[T any](fn func(T, error) map[string]float64) ExecuteOption
- func WithErrorEvaluator(f func(error) bool) ExecuteOption
- func WithIgnoreErrors(errs ...error) ExecuteOption
- func WithMetrics(metrics map[string]any) ExecuteOption
- func WithRouter(routerID string) ExecuteOption
- func WithSelectedBreakers(fn func([]BreakerMeta) []string) ExecuteOption
- func WithSelectedRouter(fn func([]RouterMeta) string) ExecuteOption
- func WithTag(key, value string) ExecuteOption
- func WithTags(tags map[string]string) ExecuteOption
- func WithTraceID(traceID string) ExecuteOption
- type Logger
- type Option
- func WithAPIKey(key string) Option
- func WithBaseURL(url string) Option
- func WithFailOpen(failOpen bool) Option
- func WithGlobalTags(tags map[string]string) Option
- func WithIngestKey(key string) Option
- func WithIngestSecret(secret string) Option
- func WithLogger(logger Logger) Option
- func WithMetadataSyncInterval(d time.Duration) Option
- func WithOnStateChange(f func(name, from, to string)) Option
- func WithTraceIDExtractor(f func(ctx context.Context) string) Option
- type ReportInput
- type RouterMeta
- type SDKStats
- type Status
Constants ¶
const ContractVersion = "0.2"
ContractVersion declares the SDK Contract version this implementation conforms to. See https://app.tripswitch.dev/docs/sdk-contract.md
Variables ¶
var ( // ErrOpen is returned by Execute when the circuit breaker is open. ErrOpen = errors.New("tripswitch: breaker is open") // ErrConflictingOptions is returned when mutually exclusive Execute options are used. ErrConflictingOptions = errors.New("tripswitch: conflicting execute options") ErrMetadataUnavailable = errors.New("tripswitch: metadata cache unavailable") )
var ErrNotModified = errors.New("tripswitch: not modified")
ErrNotModified is returned when the server responds with 304 Not Modified.
ErrUnauthorized is returned when the server responds with 401 or 403.
var Latency = &latencyMarker{}
Latency is a sentinel value for WithMetrics that instructs the SDK to automatically compute and report task duration in milliseconds.
Example:
tripswitch.Execute(c, ctx, task,
tripswitch.WithRouter("router-id"),
tripswitch.WithMetrics(map[string]any{"latency": tripswitch.Latency}),
)
Functions ¶
func Execute ¶
func Execute[T any](c *Client, ctx context.Context, task func() (T, error), opts ...ExecuteOption) (T, error)
Execute wraps a task with circuit breaker logic. It runs the task and optionally reports samples to a router. This is a package-level generic function because Go does not support generic methods.
Use WithBreakers to optionally gate execution on breaker state. Use WithRouter to specify where samples go (required for metrics to be emitted). Use WithMetrics to specify what values to report. Use WithDeferredMetrics to extract metrics from the task's return value.
Example:
result, err := tripswitch.Execute(c, ctx, task,
tripswitch.WithBreakers("checkout-error-rate"),
tripswitch.WithRouter("checkout-router"),
tripswitch.WithMetrics(map[string]any{"latency": tripswitch.Latency}),
tripswitch.WithTag("endpoint", "/checkout"),
)
func IsBreakerError ¶
IsBreakerError returns true if the error is a circuit breaker error.
Types ¶
type BreakerMeta ¶ added in v0.8.0
type BreakerMeta struct {
ID string `json:"id"`
Name string `json:"name"`
Metadata map[string]string `json:"metadata,omitempty"`
}
BreakerMeta contains a breaker's identity and metadata.
type BreakerStatus ¶ added in v0.8.0
type BreakerStatus struct {
Name string
State string // "open", "closed", "half_open"
AllowRate float64 // 0.0 to 1.0
}
BreakerStatus represents the cached state of a circuit breaker. Returned by GetState and GetAllStates for debugging and observability.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the main tripswitch client.
func NewClient ¶
NewClient creates a new tripswitch client. The provided context controls how long to wait for the initial SSE state sync. If an API key is configured, the client blocks until the first SSE event is received or the context expires. If no API key is set (or SSE is disabled), the client returns immediately.
The context governs initialization only — the client's internal lifetime is managed separately and is terminated by Client.Close.
func (*Client) Close ¶
Close gracefully shuts down the client, flushing any buffered samples. The provided context controls how long to wait for the flush to complete.
func (*Client) GetAllStates ¶ added in v0.8.0
func (c *Client) GetAllStates() map[string]BreakerStatus
GetAllStates returns a copy of all cached breaker states. Useful for admin dashboards, health checks, and debugging.
func (*Client) GetBreakersMetadata ¶ added in v0.8.0
func (c *Client) GetBreakersMetadata() []BreakerMeta
GetBreakersMetadata returns a deep copy of the cached breaker metadata.
func (*Client) GetRoutersMetadata ¶ added in v0.8.0
func (c *Client) GetRoutersMetadata() []RouterMeta
GetRoutersMetadata returns a deep copy of the cached router metadata.
func (*Client) GetState ¶ added in v0.8.0
func (c *Client) GetState(name string) *BreakerStatus
GetState returns the cached state for a single breaker. Returns nil if the breaker is not in the cache. Useful for debugging to verify the SDK's local state matches expected state.
func (*Client) GetStatus ¶ added in v0.3.0
GetStatus retrieves the project health status from the API. This returns the count of open and closed breakers for the project. Requires a project API key (eb_pk_).
func (*Client) ListBreakersMetadata ¶ added in v0.8.0
func (c *Client) ListBreakersMetadata(ctx context.Context, etag string) ([]BreakerMeta, string, error)
ListBreakersMetadata retrieves metadata for all breakers in the project. If etag is non-empty it is sent as If-None-Match; a 304 response returns (nil, etag, ErrNotModified).
func (*Client) ListRoutersMetadata ¶ added in v0.8.0
func (c *Client) ListRoutersMetadata(ctx context.Context, etag string) ([]RouterMeta, string, error)
ListRoutersMetadata retrieves metadata for all routers in the project. If etag is non-empty it is sent as If-None-Match; a 304 response returns (nil, etag, ErrNotModified).
func (*Client) Report ¶ added in v0.7.0
func (c *Client) Report(input ReportInput)
Report sends a sample to the report buffer. Use this for async workflows, result-derived metrics, or fire-and-forget reporting where Execute's synchronous wrap-and-report model doesn't fit.
ts.Report(tripswitch.ReportInput{
RouterID: "llm-router",
Metric: "total_tokens",
Value: float64(resp.Usage.TotalTokens),
OK: true,
})
type ExecuteOption ¶
type ExecuteOption func(*executeOptions)
ExecuteOption configures a single Execute call.
func WithBreakers ¶ added in v0.5.0
func WithBreakers(names ...string) ExecuteOption
WithBreakers specifies breaker names to check before executing the task. If ANY breaker is open, Execute returns ErrOpen without running the task. This makes gating opt-in - if not specified, no breaker check is performed.
func WithDeferredMetrics ¶ added in v0.7.1
func WithDeferredMetrics[T any](fn func(T, error) map[string]float64) ExecuteOption
WithDeferredMetrics registers a function that extracts metrics from the task's return value after execution. The function receives the result and error from the task and returns a map of metric names to values. Only one deferred function is supported per Execute call; if called multiple times, the last one wins.
This is useful for reporting values that are only available in the response, such as token counts from LLM APIs:
result, err := tripswitch.Execute(ts, ctx, func() (*Response, error) {
return anthropic.Complete(ctx, req)
},
tripswitch.WithRouter("llm-router"),
tripswitch.WithMetrics(map[string]any{"latency": tripswitch.Latency}),
tripswitch.WithDeferredMetrics(func(res *Response, err error) map[string]float64 {
if res == nil {
return nil
}
return map[string]float64{
"prompt_tokens": float64(res.Usage.PromptTokens),
"completion_tokens": float64(res.Usage.CompletionTokens),
"total_tokens": float64(res.Usage.TotalTokens),
}
}),
)
func WithErrorEvaluator ¶
func WithErrorEvaluator(f func(error) bool) ExecuteOption
WithErrorEvaluator sets a custom function to determine if an error is a failure. If set, this takes precedence over WithIgnoreErrors. Return true if the error should count as a failure.
func WithIgnoreErrors ¶
func WithIgnoreErrors(errs ...error) ExecuteOption
WithIgnoreErrors specifies errors that should not count as failures.
func WithMetrics ¶ added in v0.5.0
func WithMetrics(metrics map[string]any) ExecuteOption
WithMetrics sets the metrics to be reported with this Execute call. The map keys are metric names and values can be:
- Latency: SDK computes task duration in milliseconds
- func() float64: User closure called after task completes
- int or float64: Static numeric value
Empty keys are ignored.
func WithRouter ¶ added in v0.6.0
func WithRouter(routerID string) ExecuteOption
WithRouter specifies the router ID for sample routing. If not specified, no samples will be emitted (metrics will be silently ignored). If metrics are specified but no router, a warning will be logged.
func WithSelectedBreakers ¶ added in v0.8.0
func WithSelectedBreakers(fn func([]BreakerMeta) []string) ExecuteOption
WithSelectedBreakers dynamically selects breakers based on cached metadata. The selector function receives the current breaker metadata cache and returns the names of breakers to use for gating.
Cannot be combined with WithBreakers - returns ErrConflictingOptions if both are used. Returns ErrMetadataUnavailable if the metadata cache is empty. If the selector returns an empty list, no breaker gating is performed.
Example:
tripswitch.Execute(ts, ctx, task,
tripswitch.WithSelectedBreakers(func(breakers []tripswitch.BreakerMeta) []string {
var names []string
for _, b := range breakers {
if b.Metadata["region"] == "us-east-1" {
names = append(names, b.Name)
}
}
return names
}),
)
func WithSelectedRouter ¶ added in v0.8.0
func WithSelectedRouter(fn func([]RouterMeta) string) ExecuteOption
WithSelectedRouter dynamically selects a router based on cached metadata. The selector function receives the current router metadata cache and returns the ID of the router to use for sample routing.
Cannot be combined with WithRouter - returns ErrConflictingOptions if both are used. Returns ErrMetadataUnavailable if the metadata cache is empty. If the selector returns an empty string, no samples will be emitted.
Example:
tripswitch.Execute(ts, ctx, task,
tripswitch.WithSelectedRouter(func(routers []tripswitch.RouterMeta) string {
for _, r := range routers {
if r.Metadata["env"] == "production" {
return r.ID
}
}
return ""
}),
)
func WithTag ¶ added in v0.5.0
func WithTag(key, value string) ExecuteOption
WithTag adds a single diagnostic tag for this Execute call. Tags are merged with global tags, with call-site tags taking precedence.
func WithTags ¶
func WithTags(tags map[string]string) ExecuteOption
WithTags sets diagnostic tags for this specific Execute call. These are merged with global tags, with call-site tags taking precedence.
func WithTraceID ¶
func WithTraceID(traceID string) ExecuteOption
WithTraceID sets a specific trace ID for this Execute call. This takes precedence over the client's TraceIDExtractor.
type Logger ¶
type Logger interface {
Debug(msg string, args ...any)
Info(msg string, args ...any)
Warn(msg string, args ...any)
Error(msg string, args ...any)
}
Logger interface - compatible with slog.Logger
type Option ¶
type Option func(*Client)
Option is a functional option for configuring the client.
func WithAPIKey ¶
WithAPIKey sets the project API key for SSE subscriptions and state reads. Project keys have the prefix "eb_pk_" and are project-scoped.
func WithBaseURL ¶
WithBaseURL overrides the default base URL for the Tripswitch API.
func WithFailOpen ¶
WithFailOpen sets the fail-open behavior of the client. If true, the client will allow traffic when tripswitch is unreachable. Defaults to true.
func WithGlobalTags ¶
WithGlobalTags sets tags that will be applied to all samples reported by the client.
func WithIngestKey ¶
WithIngestKey is deprecated: use WithIngestSecret instead. This function exists for backwards compatibility.
func WithIngestSecret ¶ added in v0.2.0
WithIngestSecret sets the ingest secret for HMAC-signed sample ingestion. The secret is a 64-character hex string used to sign requests to the metrics endpoint.
func WithLogger ¶
WithLogger sets a custom logger for the client.
func WithMetadataSyncInterval ¶ added in v0.8.0
WithMetadataSyncInterval sets the interval for refreshing breaker and router metadata from the API. Defaults to 30 seconds. A value <= 0 disables sync.
func WithOnStateChange ¶
WithOnStateChange sets a callback that is invoked whenever a breaker's state changes.
type ReportInput ¶ added in v0.7.0
type ReportInput struct {
RouterID string // Required: router to associate the sample with
Metric string // Required: metric name
Value float64 // Metric value
OK bool // Whether this sample represents a successful outcome
TraceID string // Optional: trace ID for correlation
Tags map[string]string // Optional: per-sample tags (merged with global tags)
}
ReportInput contains fields for reporting a sample independently of Execute.
type RouterMeta ¶ added in v0.8.0
type RouterMeta struct {
ID string `json:"id"`
Name string `json:"name"`
Metadata map[string]string `json:"metadata,omitempty"`
}
RouterMeta contains a router's identity and metadata.
type SDKStats ¶
type SDKStats struct {
DroppedSamples uint64
BufferSize int
SSEConnected bool
SSEReconnects uint64
LastSuccessfulFlush time.Time
LastSSEEvent time.Time // Zero if no events received yet
FlushFailures uint64 // Batches dropped after retry exhaustion
CachedBreakers int // Number of breakers in local state cache
}
SDKStats holds health metrics about the SDK.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package admin provides a client for the Tripswitch management API.
|
Package admin provides a client for the Tripswitch management API. |
|
examples
|
|
|
database
command
Example: Database Query with Ignored Errors
|
Example: Database Query with Ignored Errors |
|
evaluator
command
Example: Custom Error Evaluator
|
Example: Custom Error Evaluator |
|
http
command
Example: HTTP Client Wrap
|
Example: HTTP Client Wrap |
|
shutdown
command
Example: Graceful Shutdown
|
Example: Graceful Shutdown |
|
tags
command
Example: Per-Request Tags
|
Example: Per-Request Tags |