hostgrpc

package
v0.109.1 Latest Latest
Warning

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

Go to latest
Published: Sep 22, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package hostgrpc is the out-of-process operator host: it implements pkg/operator.Host over pkg/client/operatorclient, speaking OperatorService to the engine with a per-tenant API token from a TokenSource. It depends on the client packages and pkg/operator only, so an operator binary links it without the engine. The legacy pkg/client is used for two things only: turning a token and the HATCHET_CLIENT_* environment into a connection, and the durable task listener the Go SDK worker shares.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoToken = errors.New("hostgrpc: no token for tenant")

ErrNoToken is returned by a TokenSource for a tenant it does not serve, and by Open when the host therefore cannot authenticate as the tenant. A multi-tenant operator keeps the tenant and retries Open later, so a token that appears afterwards is picked up without a restart.

Functions

This section is empty.

Types

type ClientFactory

type ClientFactory func(token string) (engineClient, error)

ClientFactory builds the engine client for one token. The default derives the gRPC address and TLS settings from the token's claims and HATCHET_CLIENT_* environment, like the SDK.

type Host

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

Host caches one engine client per tenant. The token is asked from the source on every connect so a rotated token replaces the cached client. A client is evicted when it is replaced, when ReleaseTenant reports the tenant is no longer served, or when the host closes; it is closed when it is evicted and no session holds it any more.

func New

func New(fs ...Opt) (*Host, error)

New builds a Host. WithTokenSource is required; the other options have defaults.

func (*Host) Close

func (h *Host) Close()

Close closes every cached client, whether or not a session still holds it. Sessions are closed by whoever opened them, before the host.

func (*Host) Open

Open implements operator.Host. The identity must name the operator by name: OperatorService upserts one GRPC row per (tenant, name), so an existing row cannot be opened by id, and a kind other than GRPC is refused. An Unauthenticated connect drops the cached client and asks the source once more, so a token rotated between two Opens is used without waiting for the source's own reload. The initial action set is streamed to the engine right after the connect and flushed before the session is returned; the session keeps it as the desired set and restores it when it has to open a new client session. Assigned actions reach opts.Handler from the session's delivery, which runs until Close.

The session supervises its client session: when the client's stream fails for good (its token was revoked, say) the session connects again through the host, which asks the source for the tenant's current token, and resumes delivery. It gives up, and reports so through Done and Err, only on a failure no retry can fix.

func (*Host) ReleaseTenant

func (h *Host) ReleaseTenant(tenantId uuid.UUID)

ReleaseTenant evicts the tenant's cached client: the next Open builds a new one. A multi-tenant operator calls it once it serves no more of the tenant. A session of the tenant that is still open (one being drained, or one opened again while an older one is torn down) keeps the client until it closes; the eviction only stops the client being handed out.

type LocalExchange

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

LocalExchange is a TokenSource that reads tokens from a YAML file and reloads it when the file or any token_file it references changes. The mtimes are polled by a background goroutine so a rotated file or mounted secret is picked up without a restart; a reload that fails keeps the previous mapping and is logged when a logger is configured.

func NewLocalExchange

func NewLocalExchange(path string, opts ...LocalExchangeOpt) (*LocalExchange, error)

NewLocalExchange loads path once, failing on a missing or malformed file, and starts the mtime poller. Close stops it.

func (*LocalExchange) Close

func (e *LocalExchange) Close()

Close stops the mtime poller. Token keeps answering from the last loaded mapping.

func (*LocalExchange) Reload

func (e *LocalExchange) Reload() error

Reload re-reads the file and every token_file it references unconditionally.

func (*LocalExchange) Token

func (e *LocalExchange) Token(_ context.Context, tenantId uuid.UUID) (string, error)

Token implements TokenSource.

type LocalExchangeOpt

type LocalExchangeOpt func(*LocalExchange)

LocalExchangeOpt configures NewLocalExchange.

func WithExchangeLogger

func WithExchangeLogger(l *zerolog.Logger) LocalExchangeOpt

WithLogger reports reload failures; tokens are never logged.

func WithPollInterval

func WithPollInterval(d time.Duration) LocalExchangeOpt

WithPollInterval overrides how often the files' mtimes are checked.

type Opt

type Opt func(*opts)

Opt configures New.

func WithClientFactory

func WithClientFactory(f ClientFactory) Opt

WithClientFactory replaces the default client factory; tests inject a fake.

func WithLogger

func WithLogger(l *zerolog.Logger) Opt

WithLogger sets the host's logger; the default discards everything.

func WithTokenSource

func WithTokenSource(tokens TokenSource) Opt

WithTokenSource sets where the host asks for each tenant's API token. It is required.

type StaticExchange

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

StaticExchange is a TokenSource that serves a single tenant from one token, the tenant being the token's sub claim. It backs the HATCHET_CLIENT_TOKEN case for a single-tenant operator, local development and tests.

func NewStaticExchange

func NewStaticExchange(token string) (*StaticExchange, error)

NewStaticExchange parses the tenant id out of token's sub claim.

func (*StaticExchange) TenantId

func (s *StaticExchange) TenantId() uuid.UUID

TenantId is the single tenant the source serves.

func (*StaticExchange) Token

func (s *StaticExchange) Token(_ context.Context, tenantId uuid.UUID) (string, error)

Token implements TokenSource.

type TokenSource

type TokenSource interface {
	// Token returns the tenant's token, or ErrNoToken when the tenant is not served.
	Token(ctx context.Context, tenantId uuid.UUID) (string, error)
}

TokenSource resolves the API token the host uses to register as a tenant. The database never stores tokens; every deployment plugs in its own source.

Jump to

Keyboard shortcuts

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