Elyra
Elyra The coding agent e The native code editor Elyra Grove Native local development environment Askr The real server for Laravel & PHP Elyra Framework Rust + Svelte 5 framework for desktop apps Elyra Conductor Local project conductor Elyra SQL Server MySQL-compatible SQL server in Rust Elyra Félagi Agents as teammates on one board Elyra SQL Client Native desktop SQL workbench Elyra SQL Anywhere Replication-ready SQL engine Elyra Sjá SEO & GEO workspace for macOS Elyra DataGrid Server-driven data grid for Laravel
Release notes
Changelog
Elyra
Events — the EventBus

Events — the EventBus

The EventBus is Elyra's Broadcasting: Rust pushes events to the frontend, batched per flush. Rust owns the state; the frontend subscribes to changes instead of polling.

Emitting (Rust)

The bus is created by App and bound in the container, so any command, provider, or task can resolve it:

#[command]
async fn tick(ctx: Ctx) {
    ctx.get::<EventBus>().emit("tick", &42u32).ok();
}

emit<T: Serialize>(channel, &value) is non-blocking and callable from any thread. To emit from main or a background thread, grab a clone before running:

let app = App::new().commands(commands![..]);
let bus = app.events();                       // a clone of the bus
std::thread::spawn(move || { bus.emit("tick", &1u32).ok(); });
app.run()?;

Subscribing (frontend)

channel(name) returns a Svelte-readable store, multiplexed over a single connection:

<script>
  import { channel } from "@elyra/runtime";
  const ticks = channel("tick");   // usable as $ticks
</script>
<p>{$ticks}</p>

Or subscribe manually:

const unsubscribe = channel<number>("tick").subscribe((n) => console.log(n));

Transport & batching

Events travel over a long-poll of elyra://localhost/__events: the shell holds the request open until events are ready, responds with a MessagePack batch ([[channel, value], ...]), and the frontend immediately reconnects. Binary, no base64, one connection for all channels. See wire format.

Emits accumulate and flush together, so N state changes cost one IPC round, not N. By default there's no artificial delay — the natural response→reconnect gap coalesces bursts. For sustained, time-spaced streams you can force frame-level coalescing:

App::new().batch_window(std::time::Duration::from_millis(8));

After ~20s idle the poll returns an empty keep-alive batch and the connection refreshes.

Fan-out: one queue per window

Every webview identifies itself with a random client id (x-elyra-client-id, added by @elyra/runtime) and gets its own queue. An emit is fanned out to all connected windows, so a multi-window app can't lose events — previously one shared queue meant whichever window polled first took the batch and the others never saw it.

Events emitted before any window has connected are held and delivered to the first poll (nothing emitted during startup is lost). A window that opens later does not get a replay of what it missed — push current state from a command instead when a new window needs to catch up.

Related