realtime

package
v1.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 15, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package realtime provides SSE and WebSocket clients for real-time Spooled events.

Index

Constants

View Source
const DefaultMaxMessageBytes = 4 << 20

DefaultMaxMessageBytes is the default ConnectionOptions.MaxMessageBytes.

Variables

This section is empty.

Functions

This section is empty.

Types

type ConnectionOptions

type ConnectionOptions struct {
	// BaseURL is the base API URL (e.g., "https://api.spooled.cloud")
	BaseURL string
	// WSURL is the WebSocket URL (e.g., "wss://api.spooled.cloud/api/v1/ws")
	WSURL string
	// Token is the JWT or API key for authentication
	Token string
	// APIKey is the API key for authentication (alternative to Token)
	APIKey string
	// AutoReconnect is ignored: reconnecting is on unless DisableAutoReconnect is
	// set. A zero ConnectionOptions used to mean "never reconnect", so a client
	// built from Client.Realtime/RealtimeSSE went silent for good the first time
	// the connection dropped - and the server ends every stream after 30 minutes.
	//
	// Deprecated: use DisableAutoReconnect to turn reconnecting off.
	AutoReconnect bool
	// DisableAutoReconnect turns automatic reconnection off.
	DisableAutoReconnect bool
	// MaxReconnectAttempts is the maximum number of consecutive failed reconnect
	// attempts before the client gives up (default: 10; negative = unlimited). The
	// count restarts once a connection has stayed up for a while.
	MaxReconnectAttempts int
	// MaxMessageBytes is the largest event the client reads (default: 4 MiB). A
	// job.completed event carries the job result, which can be large; an event
	// over the limit drops the connection.
	MaxMessageBytes int
	// ReconnectDelay is the initial delay between reconnect attempts
	ReconnectDelay time.Duration
	// MaxReconnectDelay is the maximum delay between reconnect attempts
	MaxReconnectDelay time.Duration
	// Debug enables debug logging
	Debug bool
	// Logger is a custom logger function
	Logger func(msg string, args ...any)
}

ConnectionOptions configures a realtime connection.

func DefaultConnectionOptions

func DefaultConnectionOptions() ConnectionOptions

DefaultConnectionOptions returns options with sensible defaults.

type ConnectionState

type ConnectionState string

ConnectionState represents the state of a realtime connection.

const (
	StateDisconnected ConnectionState = "disconnected"
	StateConnecting   ConnectionState = "connecting"
	StateConnected    ConnectionState = "connected"
	StateReconnecting ConnectionState = "reconnecting"
)

type Event

type Event struct {
	Type      EventType       `json:"type"`
	Timestamp time.Time       `json:"timestamp"`
	Data      json.RawMessage `json:"data"`
}

Event represents a realtime event from the Spooled API.

type EventHandler

type EventHandler func(event *Event)

EventHandler is a callback for handling events.

type EventType

type EventType string

EventType represents the type of realtime event.

const (
	// Canonical event types emitted by the server. The server tags these with
	// PascalCase variant names on the wire (e.g. "JobStatusChange"); the SDK
	// normalizes them to the dotted names below before dispatch. See
	// normalizeEventType and serverEventTypeMap.
	EventJobStatusChanged   EventType = "job.status_changed"
	EventJobCreated         EventType = "job.created"
	EventJobCompleted       EventType = "job.completed"
	EventJobFailed          EventType = "job.failed"
	EventQueueStats         EventType = "queue.stats"
	EventWorkerHeartbeat    EventType = "worker.heartbeat"
	EventWorkerRegistered   EventType = "worker.registered"
	EventWorkerDeregistered EventType = "worker.deregistered"
	EventSystemHealth       EventType = "system.health"
	EventPing               EventType = "ping"
	EventError              EventType = "error"

	// Additional event names retained for backward compatibility. These are not
	// currently emitted by the server but remain valid handler registration keys.
	EventJobStarted     EventType = "job.started"
	EventJobRetrying    EventType = "job.retrying"
	EventJobProgress    EventType = "job.progress"
	EventQueuePaused    EventType = "queue.paused"
	EventQueueResumed   EventType = "queue.resumed"
	EventWorkerJoined   EventType = "worker.joined"
	EventWorkerLeft     EventType = "worker.left"
	EventWorkerActive   EventType = "worker.active"
	EventWorkerInactive EventType = "worker.inactive"
)

type JobEvent

type JobEvent struct {
	JobID     string `json:"job_id"`
	QueueName string `json:"queue_name"`
	// Status is the job's status. On job.status_changed the server sends
	// old_status and new_status and no "status", so Status is filled from
	// NewStatus; a handler comparing e.Status to "processing" therefore works.
	Status string `json:"status"`
	// OldStatus and NewStatus are sent with job.status_changed.
	OldStatus  string  `json:"old_status,omitempty"`
	NewStatus  string  `json:"new_status,omitempty"`
	Priority   int     `json:"priority,omitempty"`
	RetryCount int     `json:"retry_count,omitempty"`
	Error      string  `json:"error,omitempty"`
	Progress   float64 `json:"progress,omitempty"`
	// DurationMs is how long the job ran; sent with job.completed.
	DurationMs int64 `json:"duration_ms,omitempty"`
	// Result is the job result when it is a JSON object, and nil otherwise.
	// RawResult has the result whatever its JSON type; a non-object result used to
	// make the whole event fail to decode and silently disappear.
	Result      map[string]any    `json:"-"`
	RawResult   any               `json:"result,omitempty"`
	WorkerID    string            `json:"worker_id,omitempty"`
	Timestamp   time.Time         `json:"timestamp,omitempty"`
	ScheduledAt *time.Time        `json:"scheduled_at,omitempty"`
	StartedAt   *time.Time        `json:"started_at,omitempty"`
	CompletedAt *time.Time        `json:"completed_at,omitempty"`
	FailedAt    *time.Time        `json:"failed_at,omitempty"`
	Metadata    map[string]string `json:"metadata,omitempty"`
}

JobEvent contains data for job-related events.

func (*JobEvent) UnmarshalJSON added in v1.4.0

func (e *JobEvent) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a job event, mapping new_status onto Status and keeping a non-object result instead of failing the event.

type JobEventHandler

type JobEventHandler func(event *JobEvent)

JobEventHandler is a callback for handling job events.

type QueueEvent

type QueueEvent struct {
	QueueName string `json:"queue_name"`
	Reason    string `json:"reason,omitempty"`
}

QueueEvent contains data for queue-related events.

type QueueEventHandler

type QueueEventHandler func(event *QueueEvent)

QueueEventHandler is a callback for handling queue events.

type RealtimeClient

type RealtimeClient interface {
	// Connect establishes the connection
	Connect() error
	// Disconnect closes the connection
	Disconnect() error
	// State returns the current connection state
	State() ConnectionState
	// Subscribe adds a subscription filter (WebSocket only - SSE uses filter at connect time)
	Subscribe(filter SubscriptionFilter) error
	// Unsubscribe removes a subscription (WebSocket only)
	Unsubscribe(filter SubscriptionFilter) error
	// OnEvent registers a handler for all events
	OnEvent(handler EventHandler)
	// OnJobEvent registers a handler for job events
	OnJobEvent(eventType EventType, handler JobEventHandler)
	// OnQueueEvent registers a handler for queue events
	OnQueueEvent(eventType EventType, handler QueueEventHandler)
	// OnWorkerEvent registers a handler for worker events
	OnWorkerEvent(eventType EventType, handler WorkerEventHandler)
	// OnStateChange registers a handler for state changes
	OnStateChange(handler StateChangeHandler)
}

RealtimeClient is the interface for realtime connections.

type SSEClient

type SSEClient struct {
	// contains filtered or unexported fields
}

SSEClient implements RealtimeClient using Server-Sent Events. Note: SSE is unidirectional - subscriptions must be set at connection time.

func NewSSEClient

func NewSSEClient(opts ConnectionOptions) *SSEClient

NewSSEClient creates a new SSE realtime client.

func (*SSEClient) Connect

func (c *SSEClient) Connect() error

Connect establishes the SSE connection. For SSE, subscriptions must be provided at connect time via ConnectWithFilter.

func (*SSEClient) ConnectWithFilter

func (c *SSEClient) ConnectWithFilter(filter *SubscriptionFilter) error

ConnectWithFilter establishes the SSE connection with a subscription filter.

func (*SSEClient) Disconnect

func (c *SSEClient) Disconnect() error

Disconnect closes the SSE connection.

func (*SSEClient) OnEvent

func (c *SSEClient) OnEvent(handler EventHandler)

OnEvent registers a handler for all events.

func (*SSEClient) OnJobEvent

func (c *SSEClient) OnJobEvent(eventType EventType, handler JobEventHandler)

OnJobEvent registers a handler for job events.

func (*SSEClient) OnQueueEvent

func (c *SSEClient) OnQueueEvent(eventType EventType, handler QueueEventHandler)

OnQueueEvent registers a handler for queue events.

func (*SSEClient) OnStateChange

func (c *SSEClient) OnStateChange(handler StateChangeHandler)

OnStateChange registers a handler for state changes.

func (*SSEClient) OnWorkerEvent

func (c *SSEClient) OnWorkerEvent(eventType EventType, handler WorkerEventHandler)

OnWorkerEvent registers a handler for worker events.

func (*SSEClient) State

func (c *SSEClient) State() ConnectionState

State returns the current connection state.

func (*SSEClient) Subscribe

func (c *SSEClient) Subscribe(filter SubscriptionFilter) error

Subscribe is not supported for SSE - use ConnectWithFilter instead.

func (*SSEClient) Unsubscribe

func (c *SSEClient) Unsubscribe(filter SubscriptionFilter) error

Unsubscribe is not supported for SSE.

type StateChangeHandler

type StateChangeHandler func(state ConnectionState)

StateChangeHandler is a callback for connection state changes.

type SubscriptionFilter

type SubscriptionFilter struct {
	QueueName string   `json:"queue_name,omitempty"`
	JobID     string   `json:"job_id,omitempty"`
	WorkerID  string   `json:"worker_id,omitempty"`
	Events    []string `json:"events,omitempty"`
}

SubscriptionFilter specifies which events to receive.

type WebSocketClient

type WebSocketClient struct {
	// contains filtered or unexported fields
}

WebSocketClient implements RealtimeClient using WebSocket.

func NewWebSocketClient

func NewWebSocketClient(opts ConnectionOptions) *WebSocketClient

NewWebSocketClient creates a new WebSocket realtime client.

func (*WebSocketClient) Connect

func (c *WebSocketClient) Connect() error

Connect establishes the WebSocket connection.

func (*WebSocketClient) Disconnect

func (c *WebSocketClient) Disconnect() error

Disconnect closes the WebSocket connection.

func (*WebSocketClient) OnEvent

func (c *WebSocketClient) OnEvent(handler EventHandler)

OnEvent registers a handler for all events.

func (*WebSocketClient) OnJobEvent

func (c *WebSocketClient) OnJobEvent(eventType EventType, handler JobEventHandler)

OnJobEvent registers a handler for job events.

func (*WebSocketClient) OnQueueEvent

func (c *WebSocketClient) OnQueueEvent(eventType EventType, handler QueueEventHandler)

OnQueueEvent registers a handler for queue events.

func (*WebSocketClient) OnStateChange

func (c *WebSocketClient) OnStateChange(handler StateChangeHandler)

OnStateChange registers a handler for state changes.

func (*WebSocketClient) OnWorkerEvent

func (c *WebSocketClient) OnWorkerEvent(eventType EventType, handler WorkerEventHandler)

OnWorkerEvent registers a handler for worker events.

func (*WebSocketClient) State

func (c *WebSocketClient) State() ConnectionState

State returns the current connection state.

func (*WebSocketClient) Subscribe

func (c *WebSocketClient) Subscribe(filter SubscriptionFilter) error

Subscribe registers a subscription filter with the server.

The server applies the queue/job filters supplied at connection time and treats the subscribe command as advisory; it sends NO acknowledgement. Prior versions sent {"type":"subscribe",...} and then blocked up to 10s waiting for a "subscribed" reply that never arrived (stalling every reconnect resubscribe). Subscribe is now fire-and-forget: it writes {"cmd":"subscribe","queue","job_id"} and records the filter for replay on reconnect, without waiting on a reply.

func (*WebSocketClient) Unsubscribe

func (c *WebSocketClient) Unsubscribe(filter SubscriptionFilter) error

Unsubscribe removes a subscription.

Like Subscribe, this is fire-and-forget: the server sends no acknowledgement, so it writes {"cmd":"unsubscribe","queue","job_id"} and drops the stored filter without blocking on a reply.

type WorkerEvent

type WorkerEvent struct {
	WorkerID   string    `json:"worker_id"`
	QueueName  string    `json:"queue_name"`
	Hostname   string    `json:"hostname,omitempty"`
	Version    string    `json:"version,omitempty"`
	LastSeenAt time.Time `json:"last_seen_at,omitempty"`
}

WorkerEvent contains data for worker-related events.

type WorkerEventHandler

type WorkerEventHandler func(event *WorkerEvent)

WorkerEventHandler is a callback for handling worker events.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL