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:
POST /render– Submits a new video rendering job with a ZIP archive and configuration optionsGET /render/:jobId– Polls the status of an existing jobGET /render/:jobId/download– Retrieves the final MP4 file or a presigned URLDELETE /render/:jobId– Cancels a queued or running jobGET /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 allocatedRenderCoordinator.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.tsfor job submission, status polling, artifact retrieval, cancellation, and health checks. - Admission control via
RenderCoordinatorimplements 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
JobStoreandArtifactStoreinterfaces 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →