channel

package
v0.9.13 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Overview

Package channel is the listener side of a ConfigHub Channel: a process that claims a Channel, receives the runs of the commands it declares and the events it subscribes to, and reports what it did. Everything it does on the wire is a cubapi.Client call; what this package adds is the lifecycle.

Index

Constants

View Source
const (
	// FunctionInvokeCommand is the command the functions protocol rides on.
	FunctionInvokeCommand = "confighub.com/function.invoke"
	// FunctionRequestParam is the run's one option: the whole invocation request.
	FunctionRequestParam = "request"
	// FunctionAttribute, on the FunctionInvokeCommand declaration, lists the functions served:
	// {"toolchains": {<toolchain>: {<function>: FunctionSignature}}}.
	FunctionAttribute = "confighub.com/function"
)

Functions on a Channel. The functions protocol rides on one reserved command, FunctionInvokeCommand: a Channel that serves functions declares it, with the functions it serves by toolchain and name under FunctionAttribute, and every run of it carries one FunctionInvocationRequest, the unit's configuration and the functions to run on it in order, exactly what a function worker is sent. Users never see the command: cub function do --channel runs it. A bot that serves functions implements them as it always has, against the function executor's interface, and HandleFunctions does the rest.

The names are the server's; they are repeated here so a client needs nothing from the server's packages.

View Source
const (

	// DefaultDrainTimeout is how long shutdown waits for in-flight handlers.
	DefaultDrainTimeout = 30 * time.Second
	// DefaultConcurrency is how many runs a listener executes at once.
	DefaultConcurrency = 4
)
View Source
const (
	KindCommandRun = "CommandRun"
	KindEventLog   = "EventLog"
)

The kinds of message a poll delivers.

Variables

This section is empty.

Functions

func FunctionCommands added in v0.8.31

FunctionCommands is the declaration a Channel needs to serve the given functions: the one reserved command, with the served signatures by toolchain and name under FunctionAttribute. HandleFunctions declares it for an executor; it is exported for declaring out of band, with cub channel create or update --commands.

func Reject

func Reject(format string, args ...any) error

Reject builds the error that reports a run Rejected.

Types

type Connector added in v0.8.38

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

Connector serves a function executor on a Channel. It is the channel counterpart of the worker package's Connector, and takes the same executor: build the executor, register the functions, and Start. The functions are declared on the Channel when it starts, so the bot has nothing to declare out of band.

func NewConnector added in v0.8.38

func NewConnector(opts ConnectorOptions) (*Connector, error)

NewConnector checks the options and returns a Connector; Start runs it.

func (*Connector) PrintCommands added in v0.8.38

func (c *Connector) PrintCommands(w io.Writer) error

PrintCommands writes the commands the Connector declares when it starts, as the JSON object cub channel create and cub channel update take with --commands. It is for declaring them out of band, so the bot's identity needs only Claim: a bot that finds its declaration current writes nothing to the Channel.

func (*Connector) Run added in v0.8.38

func (c *Connector) Run(ctx context.Context) error

Run serves the Channel until ctx is done, which is a clean stop.

func (*Connector) Start added in v0.8.38

func (c *Connector) Start() error

Start serves the Channel until SIGINT or SIGTERM, which stop it cleanly: in-flight runs finish and the lease is released. Any other end is an error.

type ConnectorOptions added in v0.8.38

type ConnectorOptions struct {
	// Channel names the Channel to serve, as space/slug or its ID.
	Channel string
	// ConfigHubURL and PrivateKey are the server and the service account's private key (its
	// JWK), as a bot deployment carries them in CONFIGHUB_URL and CONFIGHUB_AUTH_PRIVATE_KEY.
	// The key signs a short-lived assertion for each session, renewed for as long as the
	// process runs. Without a key, the client is the one cubapi.ResolveClient builds: CUB_SERVER
	// and CUB_TOKEN, or the active cub context, which is enough for development.
	ConfigHubURL string
	PrivateKey   string
	// FunctionExecutor runs the functions; the SDK's executors satisfy it.
	FunctionExecutor FunctionExecutor
	// Concurrency is how many runs execute at once. Zero means one, which keeps a Unit's
	// functions in order, as a function worker ran them.
	Concurrency int
	// UserAgent names the bot in the server's logs. Empty means "function-bot".
	UserAgent string
}

ConnectorOptions configure a Connector. FunctionExecutor is required, and Channel is required to serve.

type EventHandler

type EventHandler func(ctx context.Context, event *goclientnew.EventLog)

EventHandler reacts to one event the Channel subscribes to. Events are handled in delivery order on the poll goroutine, so a slow handler delays the next poll, which is the backpressure a bookmark that advances on delivery wants.

Delivery is best effort: the bookmark advances as events are delivered, so a handler can miss an event (a lost response, a process that dies mid-batch, a server that died before emitting, a reader behind the retention window), and nothing marks the gap. A reaction is a way to act sooner, never the source of truth: reconcile from state on start and on a schedule, and let a missed event cost latency rather than correctness.

type FunctionExecutor added in v0.8.38

type FunctionExecutor interface {
	FunctionInvoker
	RegisteredFunctions() map[workerapi.ToolchainType]map[string]funcapi.FunctionSignature
}

FunctionExecutor is a FunctionInvoker that says which functions it serves, as the SDK's function executors do. HandleFunctions declares those functions on the Channel.

type FunctionInvoker added in v0.8.31

type FunctionInvoker interface {
	Invoke(ctx context.Context, request *funcapi.FunctionInvocationRequest) (*funcapi.FunctionInvocationResponse, error)
}

FunctionInvoker executes a function invocation request: what a function executor does. The SDK's standard executor and any executor built on it satisfy it.

type Handler

type Handler func(ctx context.Context, run *Run) (json.RawMessage, error)

Handler executes one run of a command. It returns the result to report, a JSON value in the shape the command's signature declares, or nil for none; or an error, which reports the run Failed, or Rejected when it is a Rejection. The context ends at the run's delivered timeout, or at shutdown; a handler that is still working then has its result dropped and the run redelivered later, so handlers are idempotent or refuse a re-delivery.

type Listener

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

Listener serves one Channel. Build it with NewListener, register handlers, then Run it.

func NewListener

func NewListener(client *cubapi.Client, ref Ref, opts ...Options) *Listener

NewListener builds a listener for the Channel ref names, over the client. The client carries the session, and should be built with an Authenticator so the session renews for as long as the listener runs.

func (*Listener) Channel

func (l *Listener) Channel() *goclientnew.Channel

Channel is the Channel the listener resolved, once Run has.

func (*Listener) Commands

func (l *Listener) Commands() []string

Commands lists the commands the listener handles, sorted.

func (*Listener) Declare added in v0.8.38

func (l *Listener) Declare(commands map[string]goclientnew.CommandSignature) *Listener

Declare has the listener write these commands onto the Channel when it starts, wherever the Channel declares them differently or not at all, so that the bot's code is the declaration. It is the convenience channels.md §4.6 allows: the write is an ordinary update of the Channel, and needs Edit on it. Commands the Channel declares beyond these are left alone. HandleFunctions declares the functions an executor serves this way.

func (*Listener) Handle

func (l *Listener) Handle(command string, handler Handler) *Listener

Handle registers the handler for a command the Channel declares.

func (*Listener) HandleFunctions added in v0.8.31

func (l *Listener) HandleFunctions(invoker FunctionInvoker) *Listener

HandleFunctions serves functions on the listener: every run of FunctionInvokeCommand is decoded into the invocation request, executed by the invoker, and answered with the function response. A request the run does not carry is Rejected; an executor error is Failed, with its message. An invoker that is a FunctionExecutor also has its functions declared on the Channel when the listener starts (Declare), as a function worker's were registered when it connected.

func (*Listener) OnEvent

func (l *Listener) OnEvent(handler EventHandler) *Listener

OnEvent registers the handler for the events the Channel subscribes to.

func (*Listener) Run

func (l *Listener) Run(ctx context.Context) error

Run drives the listener until ctx is done, or until something it cannot recover from. It resolves the Channel, then loops: claim with backoff, verify the commands once, poll until the lease dies, and on shutdown drain, report and release.

func (*Listener) Status

func (l *Listener) Status() ListenerStatus

Status reports the listener's state for a liveness or readiness probe.

type ListenerStatus

type ListenerStatus struct {
	Channel     string
	LeaseHeld   bool
	LastPoll    time.Time
	LastWork    time.Time
	InFlight    int
	Polls       int64
	Runs        int64
	Events      int64
	Concurrency int
}

ListenerStatus is what a probe reads: whether the lease is held, when the listener last polled and last had work, and what is in flight.

type Options

type Options struct {
	// Concurrency is how many runs execute at once; each poll asks for exactly the free slots.
	// One is a serialising listener. Zero means DefaultConcurrency.
	Concurrency int
	// DrainTimeout is how long shutdown waits for in-flight handlers before cancelling them.
	// Zero means DefaultDrainTimeout.
	DrainTimeout time.Duration
	// Logger receives the listener's log lines. Nil means the standard logger.
	Logger *log.Logger
}

Options tune a Listener.

type Ref

type Ref = cubapi.Ref

Ref names the Channel to listen on: a slug, a space/slug, or a UUID, as cubapi resolves it.

type Rejection

type Rejection struct {
	Reason string
}

Rejection is the error a Handler returns to report a run Rejected rather than Failed: the handler did not try, because the command or its params are not ones it accepts.

func (*Rejection) Error

func (r *Rejection) Error() string

type Run

type Run struct {
	*goclientnew.CommandRun
	// Client is the listener's client, so that what a handler does back against ConfigHub
	// goes over the same session.
	Client *cubapi.Client
	// contains filtered or unexported fields
}

Run is one delivered run, with its params decoded for the handler.

func (*Run) Bool

func (r *Run) Bool(name string) bool

Bool returns the named boolean option, or false when it was not given.

func (*Run) Has

func (r *Run) Has(name string) bool

Has reports whether the named option was given.

func (*Run) Int

func (r *Run) Int(name string) int64

Int returns the named integer option, or 0 when it was not given.

func (*Run) Param

func (r *Run) Param(name string, target any) (bool, error)

Param decodes the named option into target. It reports whether the option was given; a value that does not decode is an error.

func (*Run) String

func (r *Run) String(name string) string

String returns the named string option, or "" when it was not given.

type Status

type Status string

Status is where a run is in its life, as the server reports it.

const (
	StatusPending   Status = "Pending"
	StatusDelivered Status = "Delivered"
	StatusCompleted Status = "Completed"
	StatusFailed    Status = "Failed"
	StatusRejected  Status = "Rejected"
	StatusCanceled  Status = "Canceled"
	StatusExpired   Status = "Expired"
	StatusTimedOut  Status = "TimedOut"
)

func (Status) IsTerminal

func (s Status) IsTerminal() bool

IsTerminal reports whether a run in this status can no longer change.

Jump to

Keyboard shortcuts

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