ipc

package
v0.2.0 Latest Latest
Warning

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

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

Documentation

Overview

Package ipc implements the handler side of the Celerity runtime's IPC protocol: one long-lived bidirectional stream carrying configuration, events, results, credit, WebSocket sends and shutdown.

The frame loop is written against Transport rather than against gRPC types, so the protocol's behaviour can be exercised without a transport. The gRPC client is a thin adapter over it, which is the same separation the runtime draws on its own side.

Index

Constants

View Source
const (
	ProtocolMajor uint32 = 1
	ProtocolMinor uint32 = 0
)

The contract version this SDK was built against, declared in the handshake.

Variables

This section is empty.

Functions

This section is empty.

Types

type Cancel

type Cancel struct {
	ID     string
	Reason CancelReason
}

Cancel tells the handler to stop work nobody is waiting for.

It may name an event that has already completed, which is ignored rather than treated as an error.

type CancelReason

type CancelReason int

CancelReason says why an event was cancelled.

const (
	CancelUnspecified CancelReason = iota
	CancelDeadlineExceeded
	// CancelCallerGone means the originating caller went away, so nothing is
	// waiting for the result. Sent when an HTTP client disconnects, and
	// deliberately not when a WebSocket connection closes: a message is closer
	// to a queue message than to a request, so the work is still worth
	// finishing.
	CancelCallerGone
	CancelShutdown
)

type Client

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

Client serves one handler process against the runtime.

func New

func New(transport Transport, config Config) *Client

New creates a client over a transport.

func (*Client) Draining

func (c *Client) Draining(deadline time.Time)

Draining tells the runtime this process is going away, so a supervisor can roll handler processes without dropping work.

func (*Client) Grant

func (c *Client) Grant(additional uint32)

Grant returns credit outside of a result, for resizing the window or resuming after a deliberate withhold.

func (*Client) Serve

func (c *Client) Serve(ctx context.Context) error

Serve runs the handshake and then the frame loop, returning when the stream closes or the context is cancelled.

type Config

type Config struct {
	// Tags are the handler tags this process serves, declared in the handshake
	// and checked against the blueprint by the runtime.
	Tags []string
	// Reconcile is given what the blueprint declares, before this process
	// declares itself, and returns the tags to declare.
	//
	// It is how a handler whose tag is not knowable from code alone settles it:
	// a WebSocket route keyed by something the API states, or a handler that
	// stated only its name and takes its routing from the blueprint. Returning
	// an error fails the handshake, which is the right outcome for a handler
	// that could never be dispatched to. Optional.
	Reconcile func(blueprint []HandlerConfig) ([]string, error)
	// Resolve returns the pipeline for a tag.
	Resolve func(tag string) (layer.Next, bool)
	// Concurrency is the worker pool size, and the initial credit.
	Concurrency int
	// Limits caps individual tags within the credit window, so one slow handler
	// cannot consume the whole of it.
	//
	// A function rather than a map because it is read after Reconcile which can
	// change a tag to the one the blueprint declares, and a cap keyed by the
	// tag built beforehand would name a handler the runtime does not know.
	// Optional.
	Limits     func() map[string]int
	SDKVersion string
}

Config is what a client needs in order to serve a handler process.

type CreditGrant

type CreditGrant struct {
	Additional uint32
}

CreditGrant returns credit to the runtime.

Credit is additive and is replenished only when the handler says so, never implicitly by a result arriving. Grants normally ride along with a result; this frame covers resizing the window and resuming after a withhold.

type DialConfig

type DialConfig struct {
	// Socket is the Unix socket path, which is the normal case.
	Socket string
	// FallbackEnabled reports that the runtime could not bind a socket and is
	// serving over loopback TCP instead.
	//
	// The SDK uses the fallback only when the runtime says it did. Falling back
	// on its own would widen who may register as a handler from the one user the
	// socket's permissions allow to any process that can reach loopback.
	FallbackEnabled bool
	FallbackPort    int

	// Retry bounds how long dialling is retried. A handler process is commonly
	// started alongside the runtime, so losing the race to its listener is
	// ordinary rather than fatal.
	RetryFor time.Duration
}

DialConfig says where the runtime is serving the handler stream.

func DialConfigFromEnv

func DialConfigFromEnv() DialConfig

DialConfigFromEnv reads the dial configuration the runtime publishes.

func (DialConfig) Target

func (c DialConfig) Target() (string, error)

Target returns the gRPC target to dial, preferring the Unix socket.

type Drain

type Drain struct {
	Deadline time.Time
}

Drain says the runtime is going away: it stops dispatching and waits for in-flight work until the deadline.

type Draining

type Draining struct {
	Deadline time.Time
}

Draining says the handler is going away, letting a supervisor roll handler processes without dropping work.

type FromRuntime

type FromRuntime struct {
	Config   *RuntimeConfig
	ReadyAck *ReadyAck
	Dispatch *handler.Event
	Cancel   *Cancel
	Drain    *Drain
	WsAck    *WsSendAck
}

FromRuntime is a frame travelling from the runtime to the handler. Exactly one field is set.

type HandlerConfig

type HandlerConfig struct {
	HandlerName    string
	HandlerTag     string
	Timeout        time.Duration
	TracingEnabled bool
	// PublishedName is the name the blueprint publishes this handler under,
	// empty when it sets none.
	PublishedName string
}

HandlerConfig describes one handler the blueprint declares.

type HandlerLimit

type HandlerLimit struct {
	HandlerTag    string
	MaxConcurrent uint32
}

HandlerLimit caps how much of the credit window one tag may occupy.

type Outbound

type Outbound struct {
	handler.OutboundMessage
	IsBinary bool
}

Outbound is a message on its way to the runtime.

It carries the frame kind, which the public API deliberately does not as an application asks for binary through handler.BinarySender, and by the time a message reaches here the bytes are already framed and the kind is settled.

type ProtocolVersion

type ProtocolVersion struct {
	Major uint32
	Minor uint32
}

ProtocolVersion is the version of the contract one end of the stream speaks.

Minor versions are additive, so a handler built against an earlier minor of the same major serves unchanged against a later one. A different major is not compatible in either direction and is refused at the handshake.

func (ProtocolVersion) String

func (v ProtocolVersion) String() string

type ProtocolVersionError

type ProtocolVersionError struct {
	// Declared is what this SDK was built against.
	Declared ProtocolVersion
	// Served is what the runtime sent with its configuration, which is the
	// zero value if it sent none.
	Served ProtocolVersion
}

ProtocolVersionError reports a handshake refused because the contract this SDK speaks is not one the runtime serves.

Nothing about the application causes it, so nothing about the application fixes it, a rebuild is required against an SDK whose contract the runtime serves.

func (*ProtocolVersionError) Error

func (e *ProtocolVersionError) Error() string

type Ready

type Ready struct {
	HandlerTags []string
	// InitialCredit is the total events the runtime may have in flight to this
	// process across all tags, which is the SDK's worker pool size.
	InitialCredit uint32
	SDKVersion    string
	// Limits cap individual tags so one slow tag cannot consume the whole
	// credit window and starve the others.
	Limits []HandlerLimit
	// Protocol is the contract version this SDK was built against.
	// This is required, the runtime refuses a handler that declares none,
	// rather than assuming it speaks the current one.
	Protocol ProtocolVersion
}

Ready declares what this handler process serves and how much work it will take. The runtime does not dispatch until it arrives.

type ReadyAck

type ReadyAck struct {
	Accepted bool
	// UnknownTags are registered by the handler but absent from the blueprint.
	UnknownTags []string
	// UnhandledTags are in the blueprint but not registered by the handler.
	UnhandledTags []string
	// Reason says which check refused this handler. The tag lists alone cannot
	// tell a version refusal from an accepted handler with nothing to report.
	Reason RefusedReason
}

ReadyAck reports whether the handler's tags line up with the blueprint.

type RefusedReason

type RefusedReason int

RefusedReason says which check refused a handler at the handshake.

const (
	RefusedUnspecified RefusedReason = iota
	RefusedTagMismatch
	// RefusedProtocolVersion means the handler declared no contract version,
	// or one whose major the runtime does not serve.
	RefusedProtocolVersion
)

type Result

type Result struct {
	Outcome *handler.Result
	// CreditGrant is normally 1. Zero withholds, telling the runtime to stop
	// dispatching to this stream until a later [CreditGrant] frame.
	CreditGrant uint32
}

Result is a handler's outcome together with the credit it returns.

The two travel as one frame because they must: a result that carries no grant shrinks the credit window permanently, so the protocol gives a result nowhere to omit it.

type RuntimeConfig

type RuntimeConfig struct {
	TracingEnabled bool
	MetricsEnabled bool
	Handlers       []HandlerConfig
	// Protocol is the contract version the runtime serves, sent before this
	// handler is asked for anything.
	Protocol ProtocolVersion
}

RuntimeConfig is what the runtime sends before the handler declares itself, so the SDK can check the handlers registered in code against the ones the blueprint declares.

func (*RuntimeConfig) Tags

func (c *RuntimeConfig) Tags() []string

Tags returns the handler tags the blueprint declares.

type TagMismatchError

type TagMismatchError struct {
	Unknown   []string
	Unhandled []string
}

TagMismatchError reports a handshake refused because the handlers registered in code do not match the ones the blueprint declares.

It is a startup error rather than a 404 in production, which is the whole point of the check.

func (*TagMismatchError) Error

func (e *TagMismatchError) Error() string

type ToRuntime

type ToRuntime struct {
	Ready    *Ready
	Result   *Result
	Credit   *CreditGrant
	WsSend   *WsSend
	Draining *Draining
}

ToRuntime is a frame travelling from the handler to the runtime. Exactly one field is set.

type Transport

type Transport interface {
	Send(*ToRuntime) error
	Recv() (*FromRuntime, error)
	Close() error
}

Transport carries frames in both directions.

The gRPC client stream is one implementation; an in-memory channel pair is another, and is what the protocol's behaviour is tested against.

func Dial

func Dial(ctx context.Context, config DialConfig) (Transport, error)

Dial connects to the runtime's handler stream and opens the event stream.

Dialling is retried: a handler process is commonly started alongside the runtime by a supervisor, so losing the race to the runtime's listener is ordinary rather than fatal.

type WsSend

type WsSend struct {
	CorrelationID string
	Messages      []Outbound
}

WsSend asks the runtime to deliver messages to WebSocket clients.

type WsSendAck

type WsSendAck struct {
	CorrelationID string
	Success       bool
	Failures      []handler.SendFailure
}

WsSendAck reports what happened to each message in a WsSend.

Jump to

Keyboard shortcuts

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