On this page

Streaming code execution

~8 min Python TypeScript

Goal: Run a long-running script inside a sandbox and stream every stdout line to your frontend UI in real time — no polling, no buffering the full output.

What you’ll use: Sandboxes, SSE events, exec streaming

What you’ll build

A minimal code-execution console: your backend creates a sandbox, runs a script, and pipes the sandbox SSE event stream back to the browser. The browser displays each line as it arrives. Looks like this in the terminal:

[00:01] Starting data pipeline...
[00:03] Loaded 50,000 rows
[00:05] Processing batch 1/10...
[00:09] Processing batch 2/10...
...
[01:12] Done. Output written to /workspace/output.csv

Prerequisites

  • A MIOSA workspace API key (msk_live_*) — see API Keys
  • Node 22+ or Python 3.11+

Step 1 — Install and configure

Step 2 — Write a long-running script into the sandbox

Create a sandbox and write the script you want to execute. The script here simulates a ten-batch data pipeline with a sleep between batches.

Step 3 — Stream exec output

Use exec with stream=True (Python) or the async iterable exec API (TypeScript) to receive lines as they arrive rather than waiting for the process to exit.

Step 4 — Forward the stream to a browser via SSE

In a real application your backend runs the sandbox exec and forwards each line to the browser over an HTTP SSE response. Below is the pattern for both a Python ASGI server (FastAPI) and a Node HTTP handler.

Step 5 — Consume in the browser

A minimal browser snippet that connects to the SSE endpoint and appends each line to a <pre> element:

<!doctype html>
<html>
  <body>
    <button id="run">Run pipeline</button>
    <pre id="output" style="background:#111;color:#0f0;padding:1rem;min-height:200px"></pre>
    <script>
      document.getElementById('run').addEventListener('click', () => {
        const output = document.getElementById('output');
        output.textContent = '';

        const es = new EventSource('/run-sse'); // GET endpoint that starts a job
        es.onmessage = (e) => {
          const event = JSON.parse(e.data);
          if (event.type === 'stdout' || event.type === 'stderr') {
            output.textContent += event.line + '\n';
          } else if (event.type === 'exit') {
            output.textContent += `\n[exit ${event.code}]`;
            es.close();
          }
        };
        es.onerror = () => es.close();
      });
    </script>
  </body>
</html>

Backpressure

The MIOSA SSE stream pushes events as they arrive. If your client (browser tab, UI component) is slow, the network layer buffers them. For most exec workloads this is fine.

For very high-throughput scripts (millions of log lines), apply backpressure explicitly:

What you learned

  • exec with streaming yields events as the process runs — no waiting for exit.
  • stdout, stderr, and exit are the three event types to handle.
  • SSE responses need X-Accel-Buffering: no behind nginx to avoid buffering.
  • For high-throughput output, a token-bucket rate limiter protects the browser client.

Next

Was this helpful?