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
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:
- Design Trade-offs: Understand the runtime design decisions
- JavaScript Development: Build your first mim
- JavaScript mim Runtime API: Explore available APIs
For production mims:
- Implement proper error handling
- Use storage for any data that must persist
- Keep initialization work minimal
- Test timeout scenarios