zoobzio December 13, 2025 Edit this page

Reliability

zyn integrates with pipz for production-grade reliability patterns.

Available Options

synapse, _ := zyn.Binary("question", provider,
    zyn.WithRetry(3),                              // Retry on failure
    zyn.WithBackoff(3, 100*time.Millisecond),      // Retry with backoff
    zyn.WithTimeout(10*time.Second),               // Timeout protection
    zyn.WithCircuitBreaker(5, 30*time.Second),     // Circuit breaker
    zyn.WithRateLimit(10, 100),                    // Rate limiting
    zyn.WithFallback(backupSynapse),               // Fallback synapse
    zyn.WithErrorHandler(errorPipeline),           // Custom error handling
)

Retry

Automatically retry failed calls:

// Simple retry (up to 3 attempts)
zyn.WithRetry(3)

// With exponential backoff
// Attempts with delays: 100ms, 200ms, 400ms, ...
zyn.WithBackoff(3, 100*time.Millisecond)

When to use:

  • Transient failures (network blips)
  • Rate limit errors (429)
  • Provider temporary errors (503)

Best practices:

  • Keep attempts low (2-3) to avoid cost explosion
  • Use backoff for rate limits
  • Combine with timeout to bound total duration

Timeout

Bound maximum execution time:

zyn.WithTimeout(10 * time.Second)

When to use:

  • Always. LLM calls can hang indefinitely
  • User-facing requests with latency requirements
  • Background jobs with resource constraints

Guidelines:

  • Simple queries: 5-10 seconds
  • Complex reasoning: 30-60 seconds
  • Batch processing: longer, but always bounded

Circuit Breaker

Stop calling a failing provider:

// Open after 5 failures, try again after 30 seconds
zyn.WithCircuitBreaker(5, 30*time.Second)

States:

  1. Closed - Normal operation, failures counted
  2. Open - Fails immediately, no provider calls
  3. Half-Open - After recovery time, tries one request

When to use:

  • Provider outages
  • Protecting downstream systems
  • Cost control during failures

Rate Limiting

Control request throughput:

// 10 requests per second, burst of 100
zyn.WithRateLimit(10, 100)

When to use:

  • Respecting provider rate limits
  • Controlling costs
  • Fair resource sharing

Note: Rate limiters are per-synapse. For global limits, share a rate limiter instance.

Fallback

Use a backup synapse on failure:

// Create backup synapse (different provider)
backupSynapse, _ := zyn.Binary("question", backupProvider)

// Primary with fallback
synapse, _ := zyn.Binary("question", primaryProvider,
    zyn.WithFallback(backupSynapse),
)

Use cases:

  • Multi-provider redundancy
  • Graceful degradation (fall back to simpler model)
  • A/B testing with fallback

Error Handling

Custom error processing:

import "github.com/zoobz-io/pipz"

// Define identity for the error handler
var logErrorsID = pipz.NewIdentity("log-errors", "Logs synapse errors")

errorHandler := pipz.Apply(logErrorsID,
    func(ctx context.Context, e *pipz.Error[*zyn.SynapseRequest]) (*pipz.Error[*zyn.SynapseRequest], error) {
        log.Printf("Synapse error: %v", e.Err)
        metrics.Increment("synapse_errors")
        return e, nil
    },
)

synapse, _ := zyn.Binary("question", provider,
    zyn.WithErrorHandler(errorHandler),
)

Combining Options

Options compose naturally:

synapse, _ := zyn.Classification("classify", categories, provider,
    // Retry with backoff for transient failures
    zyn.WithBackoff(3, 100*time.Millisecond),

    // Timeout to bound total duration
    zyn.WithTimeout(30*time.Second),

    // Circuit breaker for provider outages
    zyn.WithCircuitBreaker(5, 60*time.Second),

    // Rate limit to stay within quotas
    zyn.WithRateLimit(10, 50),

    // Fallback to backup provider
    zyn.WithFallback(backupSynapse),
)

Execution order:

Request → RateLimit → CircuitBreaker → Timeout → Retry → Provider

User-Facing API

zyn.WithRetry(2),
zyn.WithTimeout(10*time.Second),
zyn.WithCircuitBreaker(3, 30*time.Second),

Background Processing

zyn.WithBackoff(5, 500*time.Millisecond),
zyn.WithTimeout(60*time.Second),
zyn.WithRateLimit(5, 20),

High-Availability

zyn.WithRetry(2),
zyn.WithTimeout(15*time.Second),
zyn.WithCircuitBreaker(5, 30*time.Second),
zyn.WithFallback(backupSynapse),

Session Behavior

Sessions are transactional with reliability options:

session := zyn.NewSession()

// Even with 3 retries, session only updates once on success
synapse, _ := zyn.Binary("q", provider, zyn.WithRetry(3))
synapse.Fire(ctx, session, "input")

// If all retries fail, session is unchanged
// If any retry succeeds, session has exactly 2 messages

Next Steps