Skip to main content
Version: 3.20.0 (stable)

How Requests Flow Through mimOE

Understanding how mimOE processes requests is essential for building efficient mims and AI agents. This guide walks through each stage of the request lifecycle, from initial HTTP request to final response.

Overview

mimOE implements a serverless execution model where mims are instantiated on-demand for each request and terminated immediately after. This approach minimizes memory footprint and ensures isolation between requests.

Stage 1: Request Reception

The lifecycle begins when the mimOE runtime receives an HTTP request.

Request Structure

All requests to mims follow standard HTTP conventions:

POST /myservice/v1/process HTTP/1.1
Host: localhost:8083
Authorization: Bearer eyJhbGc...
Content-Type: application/json

{
"input": "data"
}

Route Resolution

The runtime determines which mim to invoke:

  • Endpoint: From the request endpoint, determine which mim handles it

Stage 2: mim Instantiation

Once the target mim is identified, the runtime creates a fresh instance and injects the platform APIs. Each request gets its own isolated instance.

Context Object (JavaScript)

The runtime injects a context object providing access to platform capabilities:

// The context object is globally available
// context.http - HTTP client
// context.storage - Persistent storage
// context.edge - Discovery APIs
// context.info - Node metadata

app.get('/status', (request, response) => {
response.end(JSON.stringify({ status: 'ok' }));
});

Authentication

Authentication is handled by the mim, not by the runtime. After instantiation, the mim receives the request and validates the token:

app.post('/process', (request, response) => {
// The mim is responsible for validating the token
var token = request.headers["authorization"];
if (!token) {
response.statusCode = 401;
response.end(JSON.stringify({ error: 'No token provided' }));
return;
}

// Process the request...
response.end(JSON.stringify({ message: 'OK' }));
});

Stage 3: Request Processing

With the instance initialized and the request authenticated, the mim processes the request.

Request Object

The request object contains all HTTP request information:

app.post('/process', (request, response) => {
// request.method - HTTP method (GET, POST, etc.)
// request.url - URL path
// request.headers - Request headers (object)
// request.query - Query parameters (object)
// request.params - URL parameters (object)
// request.body - Request body (string)
// request.authorization - Authorization header value

console.log(request.method + ' ' + request.url);

response.end(JSON.stringify({ message: 'OK' }));
});

Asynchronous Operations

mims can perform asynchronous HTTP operations using callbacks:

app.get('/data', (request, response) => {
// HTTP requests use callbacks
context.http.request({
url: 'https://api.example.com/data',
success: (result) => {
var apiData = JSON.parse(result.data);

// Storage operations are synchronous
var userData = context.storage.getItem('user:123');

response.end(JSON.stringify({
apiData: apiData,
userData: JSON.parse(userData)
}));
},
error: (err) => {
response.statusCode = 500;
response.end(err.message);
}
});
});

Stage 4: Response Generation

The mim returns a response object to the runtime.

Response Object

The response object provides methods to send HTTP responses:

response.statusCode    // Set HTTP status code (default: 200)
response.writeMimeType // Set Content-Type header
response.end(body) // Send response and end request

Response Examples

// Simple response
app.get('/status', (request, response) => {
response.end(JSON.stringify({ message: 'OK' }));
});

// Response with custom status
app.post('/users', (request, response) => {
response.statusCode = 201;
response.end(JSON.stringify({ id: 'new-resource-123' }));
});

// Error response
app.post('/validate', (request, response) => {
var body = JSON.parse(request.body);
if (!body.email) {
response.statusCode = 400;
response.end(JSON.stringify({
error: 'invalid_input',
message: 'Field "email" is required'
}));
return;
}
response.end(JSON.stringify({ valid: true }));
});

Streaming Responses

mimOE supports Server-Sent Events (SSE) and chunked transfer encoding for streaming responses:

app.get('/stream', (request, response) => {
response.setHeader('Content-Type', 'text/event-stream');
response.setHeader('Transfer-Encoding', 'chunked');

response.write('data: first chunk\n\n');
response.write('data: second chunk\n\n');
response.end();
});

Stage 5: Instance Termination

After the response is sent to the client, the instance is immediately terminated.

What This Means for You

No State Persistence

All in-memory state is destroyed. Variables, caches, and computed data are lost unless explicitly saved to storage.

// ❌ This state is LOST after request
var cache = {};

app.post('/data', (request, response) => {
var body = JSON.parse(request.body);
cache[body.id] = body.data; // Lost immediately after response!
response.end(JSON.stringify({ status: 'saved' }));
});
// ✅ This state persists
app.post('/data', (request, response) => {
var body = JSON.parse(request.body);
context.storage.setItem('cache:' + body.id, JSON.stringify(body.data));
response.end(JSON.stringify({ status: 'saved' }));
});

Performance Characteristics

Understanding the lifecycle helps optimize performance:

Cold Start vs. Warm Start

Cold start (first request or after idle period):

  • Load mim code from storage
  • Initialize VM/WASM module
  • Typical overhead: 10-50ms

Warm start (subsequent requests):

  • Microservice code may be cached in memory
  • Still instantiates new VM/module
  • Typical overhead: 5-10ms

Optimization Strategies

1. Minimize initialization work

// ❌ Slow - loads data on every request
app.get('/process', (request, response) => {
context.http.request({
url: 'https://api.example.com/config',
success: (result) => {
var config = JSON.parse(result.data);
// Process with config...
response.end('done');
},
error: (err) => {
response.statusCode = 500;
response.end(err.message);
}
});
});
// ✅ Fast - cache config in storage
app.get('/process', (request, response) => {
var config = context.storage.getItem('config');

if (config) {
// Use cached config
processWithConfig(JSON.parse(config), response);
} else {
// Fetch and cache
context.http.request({
url: 'https://api.example.com/config',
success: (result) => {
context.storage.setItem('config', result.data);
processWithConfig(JSON.parse(result.data), response);
},
error: (err) => {
response.statusCode = 500;
response.end(err.message);
}
});
}
});

2. Keep bundles small

  • Smaller JavaScript bundles load faster
  • Use tree-shaking and minification
  • Remove unused dependencies

3. Use transactions for multiple operations

// ❌ Not atomic - could be inconsistent if interrupted
context.storage.setItem('balance:alice', String(aliceBalance - amount));
context.storage.setItem('balance:bob', String(bobBalance + amount));
// ✅ Atomic - all or nothing
context.storage.lockExecute(function() {
context.storage.setItem('balance:alice', String(aliceBalance - amount));
context.storage.setItem('balance:bob', String(bobBalance + amount));
});

Error Handling

Errors during the lifecycle are handled differently based on where they occur:

Authentication Errors

HTTP/1.1 401 Unauthorized
{
"error": "invalid_token",
"message": "The access token is invalid or expired"
}

Instantiation Errors

HTTP/1.1 500 Internal Server Error
{
"error": "instantiation_failed",
"message": "Failed to load mim"
}

Runtime Errors

app.post('/users', (request, response) => {
var body = JSON.parse(request.body);

if (!body.email) {
// Explicit error response
response.statusCode = 400;
response.end(JSON.stringify({
error: 'missing_field',
message: 'Email is required'
}));
return;
}

// Unhandled exceptions become 500 errors
throw new Error('Something went wrong'); // → 500 error
});

Timeout Errors

HTTP/1.1 504 Gateway Timeout
{
"error": "timeout",
"message": "Request processing exceeded 30 seconds"
}

Next Steps

Now that you understand the request lifecycle:

Best Practices

For production mims:

  • Implement proper error handling
  • Use storage for any data that must persist
  • Keep initialization work minimal
  • Test timeout scenarios