Ephemeral Plugins¶
The Ephemeral mode is the third execution mode of Xcore, alongside Trusted and Sandboxed. It is designed for serverless-like, stateless plugins that are created per call and destroyed right after.
What is Ephemeral Mode?¶
An Ephemeral plugin is loaded, executed, and unloaded for every call. No instance survives between two calls, which means:
- Zero implicit state: the plugin cannot leak memory, connections, or cached values between requests.
- Bounded memory: idle instances are reclaimed by an automatic sweeper.
- Per-call isolation: even a crash in
handle()discards the instance without affecting the next call.
The kernel never knows the plugin is ephemeral: EphemeralHandler implements the same PluginHandler interface as LifecycleManager and SandboxProcessManager, so the supervisor, permissions, rate limiting, and HTTP routing all work unchanged.
sequenceDiagram
participant S as Supervisor
participant H as EphemeralHandler
participant P as WarmPool
participant I as Plugin Instance
S->>H: call("sum", {a:1, b:2})
H->>P: acquire()
alt pool available
P-->>I: warm instance (0ms)
else cold boot
P-->>I: new instance (3–6ms)
end
I->>I: handle("sum", {a:1, b:2})
I-->>H: {status:"ok", result:3}
H->>P: release() → back to pool or unload
H-->>S: {status:"ok", result:3}
Why Use Ephemeral Mode?¶
| Scenario | Why Ephemeral |
|---|---|
| Hot reload without memory leaks | Repeated reloads no longer accumulate instances — each is garbage-collected after the call. |
| Unpredictable load spikes | Cold boots absorb bursts; the warm pool covers the steady baseline. |
| Untrusted / third-party logic (faster than sandbox) | Same-process execution gives near-native speed with per-call isolation. |
| Side-effect-heavy plugins | Connections (DB, Redis) opened in on_load are torn down after each call — no dangling handles. |
| Serverless-style actions | pool_size=0 gives pure cold-boot execution, ideal for rare or low-frequency actions. |
When NOT to use Ephemeral
- Stateful plugins (sessions, in-memory caches, connection reuse) — each call starts from scratch.
- High-frequency hot paths — per-call
on_loadhas a real cost. For millions of calls/second, prefer Trusted mode. - Background schedulers (
@cron,@interval) — scheduled tasks run against a handler, not a live instance.
How It Works¶
The Warm Pool¶
The WarmPool (xcore/kernel/runtime/warm_pool.py) pre-loads pool_size instances at boot and keeps them ready:
- Pool hit: an available instance is served immediately (~0 ms).
- Cold boot: if the pool is empty, a new
LifecycleManageris loaded on demand (3–6 ms per benchmark). - Backpressure:
max_concurrentcaps the total number of simultaneous instances (pool + cold). Beyond this,acquire()waits instead of unboundedly creating instances. - Idle sweeper: every 10 s, instances idle for more than
max_idle_secondsare unloaded. The freshestpool_sizeinstances are always kept. - Error safety: if
handle()raises, the instance is discarded (not returned to the pool) — a potentially corrupted instance never gets reused.
Call lifecycle¶
acquire()— pool hit or cold boot (bounded bymax_concurrent).handle(action, payload)— your plugin logic runs insidesrc/main.py.release()— the instance returns to the pool, or is unloaded if the pool is full.- On error —
discard()unloads the instance and releases its concurrency slot.
Prerequisites¶
- Xcore Installation (≥ 2.3.3)
- A plugin with the standard structure (
plugin.yaml+src/main.py)
Configuration¶
The ephemeral settings are resolved in this precedence order:
- Per-plugin: the
ephemeral:block inplugin.yaml. - Global: the
plugins.ephemeral:section inintegration.yaml/xcore.yaml. - Defaults:
EphemeralConfig()if nothing is configured.
1. Per-plugin (plugin.yaml)¶
- Must be
ephemeral. Values accepted:trusted|sandboxed|legacy|ephemeral. - Optional. Falls back to the global
plugins.ephemeral:config.
2. Global (integration.yaml)¶
Every ephemeral plugin without its own ephemeral: block inherits this configuration.
3. Defaults¶
| Key | Type | Default | Description |
|---|---|---|---|
pool_size |
int |
0 |
Warm instances pre-loaded. 0 = pure cold boot on every call. |
max_idle_seconds |
int |
60 |
Seconds before an idle instance is unloaded. |
max_concurrent |
int |
10 |
Max simultaneous instances (pool + cold boot). Beyond this, calls wait. |
boot_timeout |
float |
5.0 |
Seconds allowed for a single instance boot before it fails. |
Tuning advice
- Start with
pool_size: 1and monitorcold_bootsin the status endpoint. - If cold boots stay at zero over time, raise
pool_sizeto remove latency; if instances sit idle, lower it. max_concurrentis your safety valve against load spikes — set it to the maximum memory you can afford.
Writing an Ephemeral Plugin¶
The plugin source is identical to a Trusted plugin. Only the manifest changes.
Stateless by design
Do not cache data on self between calls, open long-lived connections in on_load, or start background tasks. Everything is torn down when the call finishes.
Monitoring¶
Each ephemeral plugin exposes its status through the standard plugin status endpoint (supervisor.status()):
| Field | Meaning |
|---|---|
pool.available |
Ready instances in the pool right now. |
pool.total_alive |
Instances currently in existence (pool + in flight). |
pool.cold_boots |
Total cold boots since start — if it climbs fast, pool_size is too low. |
calls_error |
Calls that failed and triggered a discard(). |
Common Errors & Pitfalls¶
Boot timeout
Ephemeral boot timeout (Xs) means on_load() took longer than boot_timeout.
Fix: move heavy initialization out of on_load, or raise boot_timeout.
Instances are never reused after an error
A failed handle() discards the instance. If your plugin fails often, expect more cold boots (visible in pool.cold_boots).
Stateful behavior breaks silently
Ephemeral plugins have no persistence. Rely on the cache (self.get_service("cache")) or the database for anything that must survive a call.
See Also¶
- Execution Modes
- Comparison of all execution modes.
- Trusted Plugins
- Same plugin API without per-call isolation.
- Plugin Anatomy
- Structure and manifest reference.
- Hot Reloading
- Ephemeral mode is the recommended companion for frequent hot reloads.