What Is the render-service in OpenMAIC? Architecture and API Guide

The render-service is an isolated HTTP microservice in OpenMAIC that converts Hyperframes project archives into MP4 videos using the @hyperframes/producer library, protecting the main application from the heavy CPU, GPU, and memory demands of video rendering.

The render-service in OpenMAIC is a dedicated Node.js microservice designed to handle resource-intensive video rendering workflows separately from the main web application. By isolating the rendering engine within its own containerized boundary, OpenMAIC ensures that memory-heavy ZIP extraction and CPU/GPU-intensive video encoding do not degrade the availability of the core platform.

Architectural Isolation and Public API Contract

The render-service exposes a stable, minimal HTTP contract consisting of exactly five endpoints defined in render-service/src/main.ts within the createApp function:

  1. POST /render – Submits a new video rendering job with a ZIP archive and configuration options
  2. GET /render/:jobId – Polls the status of an existing job
  3. GET /render/:jobId/download – Retrieves the final MP4 file or a presigned URL
  4. DELETE /render/:jobId – Cancels a queued or running job
  5. GET /health – Returns runtime environment details and resource profiles

This narrow interface allows the OpenMAIC frontend or any external client to manage video generation without knowledge of internal storage mechanisms or rendering implementation details.

Admission Control and Queue Management

To prevent resource starvation, the render-service implements sophisticated admission controls in render-service/src/render-coordinator.ts. The RenderCoordinator class enforces reservation-before-buffering semantics through two key methods:

  • RenderCoordinator.reserve – Acquires a slot in the rendering queue before any memory is allocated
  • RenderCoordinator.submit – Accepts the actual job payload only after reservation succeeds

This pattern guarantees that rejected requests never consume RAM, protecting the service from out-of-memory (OOM) attacks. The coordinator also enforces per-user limits and global queue caps to ensure fair resource allocation across the OpenMAIC platform.

Bounded Buffering and ZIP Extraction

All memory-intensive operations are guarded by a concurrency semaphore to prevent container overload. In render-service/src/main.ts, the extractionGate (a Semaphore instance from render-service/src/semaphore.ts) controls concurrent access to:

  • Multipart form parsing
  • ZIP archive extraction
  • Temporary file buffering

By wrapping these operations in extractionGate.run, the service caps the number of simultaneous RAM-heavy extractions, preventing burst uploads from overwhelming the container's memory limits.

Pluggable Rendering Engine

The service abstracts the actual video encoding behind a RenderExecutor interface defined in render-service/src/render-executor.ts. The default InProcessExecutor implementation wraps the @hyperframes/producer library to transform project archives into MP4 format.

This abstraction allows the rendering policy—including chunking strategies, worker counts, and capture modes—to be swapped for testing or future scaling (such as distributed rendering) without modifying the HTTP layer or API contracts.

Job Persistence and Artifact Storage

Decoupling job lifecycle from storage backends enables flexible deployment configurations. The render-service uses two primary abstractions:

  • JobStore (default: InMemoryJobStore) – Tracks job state transitions from queued through rendering to completed or failed
  • ArtifactStore (default: LocalDiskArtifactStore) – Manages the resulting MP4 files or presigned URLs for external object storage

These interfaces allow operators to substitute Redis for job tracking, S3 for artifact storage, or any custom implementation without changing the core service logic in main.ts.

Health Monitoring and Runtime Detection

The /health endpoint provides operational visibility by returning the configured resource profile and detected runtime versions. The collectRuntimeVersions function in render-service/src/runtime-info.ts gathers version information for:

  • Node.js runtime
  • Chromium headless shell
  • FFmpeg binaries

This data allows the OpenMAIC frontend to display current rendering capabilities and helps operators verify container environment integrity.

Interacting with the render-service

Below are practical TypeScript examples demonstrating how clients interact with the render-service API.

Submitting a Render Job

const form = new FormData();
form.append('project', await fetch('my-project.zip').then(r => r.blob()), 'project.zip');
form.append('fps', '24');
form.append('quality', 'standard');
form.append('format', 'mp4');

const submitRes = await fetch('https://render-service.example.com/render', {
  method: 'POST',
  headers: { 'x-openmaic-client': 'my-user-id' },
  body: form,
});
const { jobId } = await submitRes.json();   // e.g. { jobId: "c1a2b3…" }

Polling for Completion

async function poll(jobId: string) {
  while (true) {
    const r = await fetch(`https://render-service.example.com/render/${jobId}`);
    const status = await r.json();
    if (status.done) return status;      // contains `status: "succeeded"` etc.
    await new Promise(res => setTimeout(res, 2000));
  }
}
const finalStatus = await poll(jobId);

Downloading the Result

if (finalStatus.status === 'succeeded') {
  const dl = await fetch(`https://render-service.example.com/render/${jobId}/download`);
  if (dl.redirected) {
    // Presigned URL – fetch from the storage provider directly
    const mp4 = await fetch(dl.url).then(r => r.arrayBuffer());
  } else {
    // Direct stream from the service
    const mp4 = await dl.arrayBuffer();
  }
}

Cancelling a Job

await fetch(`https://render-service.example.com/render/${jobId}`, { method: 'DELETE' });

Summary

  • The render-service is an isolated microservice in THU-MAIC/OpenMAIC that handles video rendering separately from the main web application to ensure platform stability.
  • It exposes five HTTP endpoints defined in render-service/src/main.ts for job submission, status polling, artifact retrieval, cancellation, and health checks.
  • Admission control via RenderCoordinator implements reservation-before-buffering to prevent memory exhaustion from rejected requests.
  • A semaphore-guarded extraction gate limits concurrent ZIP parsing and file buffering to protect container resources.
  • The pluggable executor architecture allows swapping rendering engines (defaulting to @hyperframes/producer) without API changes.
  • Storage abstraction via JobStore and ArtifactStore interfaces enables flexible backends from in-memory to Redis/S3.

Frequently Asked Questions

How does render-service prevent memory exhaustion during uploads?

The service uses a Semaphore called extractionGate in render-service/src/main.ts to cap concurrent ZIP extraction and multipart parsing operations. By wrapping these RAM-intensive tasks in extractionGate.run, the service ensures that burst upload traffic cannot overwhelm the container's memory, preventing OOM crashes.

What endpoints does the OpenMAIC render-service expose?

According to the source code in render-service/src/main.ts, the service exposes exactly five endpoints: POST /render for job submission, GET /render/:jobId for status polling, GET /render/:jobId/download for artifact retrieval, DELETE /render/:jobId for job cancellation, and GET /health for runtime monitoring.

Can I swap the video rendering engine used by render-service?

Yes. The RenderExecutor interface in render-service/src/render-executor.ts provides a seam for alternative implementations. While the default InProcessExecutor uses @hyperframes/producer, you can inject custom executors for distributed rendering or different encoding pipelines without modifying the HTTP API.

What storage backends does the render-service support?

The service uses the JobStore and ArtifactStore abstractions defined in the coordinator and main files. Default implementations use in-memory job tracking and local disk artifact storage, but the interfaces support Redis for job persistence and S3 (via presigned URLs) for artifact storage.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →