Documentation
¶
Overview ¶
Package wasmhost runs Hatamoto plugins: Extism (wazero) modules built from standard Go (or any Extism PDK language) with a hard sandbox.
Every plugin gets, from its manifest: a cap on linear memory, a per-hook call timeout (always on: without it neither the timeout nor a cancelled request can stop a spinning guest; 250 ms for filters and 10 s for actions unless the manifest says otherwise; it starts once an instance is ready, waiting for a slot and starting a cold instance are bounded separately), an empty filesystem, no network, and a pool of instances with an admission cap. An instance that saw any error is thrown away, because a Go runtime that trapped is poisoned. Plugins load and unload without restarting; the registry is an immutable map behind an atomic pointer, so the request path takes no host-wide lock.
Index ¶
- Variables
- type Host
- func (h *Host) Call(ctx context.Context, name, export string, in []byte) ([]byte, error)
- func (h *Host) Close(ctx context.Context)
- func (h *Host) Discarded(name string) int64
- func (h *Host) HasExport(name, export string) bool
- func (h *Host) Load(ctx context.Context, m sdk.Manifest, wasm []byte) error
- func (h *Host) Loaded() []string
- func (h *Host) SetHostCall(fn HostCall)
- func (h *Host) Unload(ctx context.Context, name string) bool
- type HostCall
Constants ¶
This section is empty.
Variables ¶
var ErrCircuitOpen = errors.New("wasmhost: plugin hook disabled after repeated failures")
ErrCircuitOpen is returned without running the guest while the circuit breaker for that plugin export is open.
var ErrNotLoaded = errors.New("wasmhost: plugin not loaded")
ErrNotLoaded is returned when calling a plugin that is not (or no longer) loaded.
var ErrOutputTooLarge = errors.New("wasmhost: plugin output too large")
ErrOutputTooLarge is returned when a call's output exceeds the plugin's max_output_bytes.
var ErrSaturated = errors.New("wasmhost: plugin saturated")
ErrSaturated wraps the context error of a call that gave up waiting for a free instance slot.
Functions ¶
This section is empty.
Types ¶
type Host ¶
type Host struct {
// contains filtered or unexported fields
}
Host owns every loaded plugin.
func New ¶
New returns a Host. cacheDir != "" persists wazero's compiled code there so a restart does not recompile every module (about a second per Go guest); otherwise compiled code is cached in memory only. The directory is created private (0700): it holds native machine code the server executes. The cache is rebuildable, so a directory that cannot be used costs speed, not correctness: it is logged and the cache stays in memory.
func (*Host) Call ¶
Call runs export on plugin name with JSON input and returns its output.
A trap, timeout, out-of-memory or guest error returns an error and discards the instance that saw it; only a deliberate rejection (sdk.RejectPrefix) keeps its instance. Calls beyond the plugin's max_instances wait for a free slot until ctx ends or slotWait passes, then fail with ErrSaturated (the instances are untouched), so memory use stays inside max_instances x memory_pages x 2. The hook's timeout covers only the guest's run: neither the slot wait nor a cold start (at most maxStartWait) is charged to it, so the worst latency without a caller deadline is slotWait + maxStartWait + the hook's timeout. A caller deadline shortens all three together: the wait, the start and the run share it, so hooks called with one (render.head, jsonld.enrich) can still be cut short by it; that cut is not counted against the circuit breaker when our own waiting (slot wait plus cold start) was what shortened the guest's run; a guest cut by a short caller deadline that it had to itself is charged as usual.
func (*Host) Discarded ¶
Discarded reports how many instances of name were dropped after failures (-1 when the plugin is not loaded).
func (*Host) Load ¶
Load compiles wasm and places the plugin under m.Name, replacing a plugin of the same name once the old one's in-flight calls have finished. The manifest is validated and defaulted here; a module that cannot be compiled and instantiated fails the load. A Go guest's init() runs on the first call, not here, so a panicking init() fails every call instead.
func (*Host) SetHostCall ¶
SetHostCall sets who answers hm_call for plugins loaded from now on. Without it every call fails with an "unavailable" error response.
type HostCall ¶
HostCall serves a plugin's hm_call import: in is the guest's request, the result goes back to it. ctx is the context of the hook call that is running the guest (its values and deadline), so the callee can bind itself to the call. The callee never fails: errors are encoded in the response.