Operations
Isolation model
Section titled “Isolation model”Tenant scripts are isolated at the process level, not merely by runtime sandbox. A runaway script consumes its own process’s quota and is killed there; it does not degrade the service or another tenant.
This is why the block exists as a service rather than a library linked into every caller. A sandbox inside the calling process still shares that process’s memory limits and scheduler.
Quotas and limits
Section titled “Quotas and limits”Enforced per execution:
- CPU — how much compute one execution may consume
- Memory — the ceiling before the execution is terminated
- Wall-clock — the timeout
Set these for the worst script you will accept, not the typical one. Limits exist for the pathological case, and a generous timeout is how a hung script becomes a capacity problem.
Choosing a runtime
Section titled “Choosing a runtime”Runtime choice is an operational decision as much as an authoring one:
| Runtime | Startup | Notes |
|---|---|---|
CEL, expr | Fastest | Single expressions; cannot loop indefinitely |
| Lua, Starlark | Fast | Small, predictable footprint |
| JavaScript (Goja) | Moderate | Pure Go, no external dependency |
| JavaScript (V8) | Slower start, faster run | Worth it for heavy compute, not for hooks |
| Go (Yaegi) | Slower | Interpreted Go |
| WebAssembly | Fast run | Compiled elsewhere; the artifact is opaque to review |
For a hook on a request path, startup cost dominates and CEL or Lua is usually right. For a batch transform, run speed dominates and V8 may pay for itself.
Failure modes
Section titled “Failure modes”A script exceeds its quota. Terminated, and the caller receives an error. This is working as intended — the alternative is the script deciding the service’s resource policy.
A script hangs on a network call. The wall-clock limit catches it. Scripts making outbound calls should carry their own timeouts too; relying on the execution timeout means a slow dependency consumes the whole budget.
A namespace is unavailable. The script fails on the call rather than silently no-op’ing. Usually the invoking context did not bind that namespace — see Namespace Reference.
Async results are not collected. Submitted executions produce results someone must retrieve. Unread results accumulate.
What to watch
Section titled “What to watch”| Signal | Why it matters |
|---|---|
| Quota terminations by tenant | A script that outgrew its limits, or one misbehaving |
| p99 execution time by runtime | Runtime choice mismatched to the workload |
| Async queue depth | Submissions outpacing execution, or results uncollected |
| Namespace denial rate | Scripts written against namespaces they are not granted |
| Process restart rate | Scripts crashing their sandbox rather than exiting cleanly |
Namespace denials are the most informative signal for a platform team. A rising rate usually means authors expect a capability the invoking context does not grant — either the binding is too narrow, or the script belongs in a different context.