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 ¶
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 ¶
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 (*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 ¶
func (h *Host) Open(ctx context.Context, id operator.Identity, opts operator.OpenOpts) (operator.Session, error)
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 ¶
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.
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 ¶
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.
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.