Skip to content

zoobz-io/capitan

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

39 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

capitan

CI Status codecov Go Report Card CodeQL Go Reference License Go Version Release

Type-safe event coordination for Go with zero dependencies.

Emit events with typed fields, hook listeners, and let capitan handle the rest with async processing and backpressure.

Send a Signal, Listen Anywhere

Events carry typed fields with compile-time safety.

// Define typed keys
orderID := capitan.NewStringKey("order_id")
total   := capitan.NewFloat64Key("total")

// Define a signal
orderCreated := capitan.NewSignal("order.created", "New order placed")

// Emit with typed fields
capitan.Emit(ctx, orderCreated,
    orderID.Field("ORD-123"),
    total.Field(99.99),
)

Each signal queues to its own worker — isolated, async, backpressure-aware.

// Hook a listener — extract typed values directly
capitan.Hook(orderCreated, func(ctx context.Context, e *capitan.Event) {
    id, _ := orderID.From(e)      // string
    amount, _ := total.From(e)    // float64
    process(id, amount)
})

// Observe all signals — unified visibility across the system
capitan.Observe(func(ctx context.Context, e *capitan.Event) {
    log.Info("event", "signal", e.Signal().Name())
})

Type-safe at the edges. Async and isolated in between.

Installation

go get github.com/zoobz-io/capitan

Requires Go 1.24+.

Quick Start

package main

import (
    "context"
    "fmt"
    "github.com/zoobz-io/capitan"
)

// Define signals and keys as package-level variables
var (
    orderCreated = capitan.NewSignal("order.created", "New order placed")
    orderID      = capitan.NewStringKey("order_id")
    total        = capitan.NewFloat64Key("total")
)

func main() {
    // Hook a listener
    capitan.Hook(orderCreated, func(ctx context.Context, e *capitan.Event) {
        id, _ := orderID.From(e)
        amount, _ := total.From(e)
        fmt.Printf("Order %s: $%.2f\n", id, amount)
    })

    // Emit an event (async with backpressure)
    capitan.Emit(context.Background(), orderCreated,
        orderID.Field("ORDER-123"),
        total.Field(99.99),
    )

    // Gracefully drain pending events
    capitan.Shutdown()
}

Capabilities

Feature Description Docs
Typed Fields Built-in keys for primitives; NewKey[T] for any custom type Fields
Per-Signal Workers Each signal gets its own goroutine and buffered queue Architecture
Observers Cross-cutting handlers that see all signals (or a whitelist) Concepts
Configuration Buffer sizes, rate limits, drop policies, panic handlers Configuration
Graceful Shutdown Drain pending events before exit Best Practices
Testing Utilities Sync mode, event capture, isolated instances Testing

Why capitan?

  • Type-safe — Typed fields with compile-time safety, including custom structs
  • Zero dependencies — Standard library only
  • Async by default — Per-signal workers with backpressure
  • Isolated — Slow listeners don't affect other signals
  • Panic-safe — Listener panics recovered, system stays running
  • Testable — Sync mode and capture utilities for deterministic tests

Decoupled Coordination

Capitan enables a pattern: packages emit, concerned parties listen, services observe.

Your domain packages emit events when meaningful things happen. Other packages hook the signals they care about. Service-level concerns — audit trails, structured logging, metrics collection — observe everything through a unified stream.

// In your order package
capitan.Emit(ctx, orderCreated, orderID.Field(id), total.Field(amount))

// In your notification package
capitan.Hook(orderCreated, sendConfirmationEmail)

// In your audit service
capitan.Observe(writeToAuditLog)

Three packages, one event flow, zero direct imports between them.

Documentation

Full documentation is available in the docs/ directory:

Learn

Guides

  • Configuration — Buffer sizes, panic handlers, runtime metrics
  • Context — Request tracing, cancellation, timeouts
  • Errors — Error propagation, severity levels, retry patterns
  • Testing — Sync mode, event capture, isolated instances
  • Best Practices — Signal design, listener lifecycle, performance
  • Persistence — Event storage and replay

Integrations

  • aperture — OpenTelemetry observability
  • herald — Message broker bridge (Kafka, NATS)
  • ago — Workflow orchestration (Experimental)

Reference

Contributing

See CONTRIBUTING.md for guidelines. Run make help for available commands.

License

MIT License — see LICENSE for details.

About

Type-safe event coordination for Go with zero dependencies

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Contributors