Skip to main content

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"
}

Authentication Check

The runtime immediately validates the authentication token:

  1. Extract token from Authorization header
  2. Verify token signature and expiration
  3. Check permissions for the target mim
  4. Reject request if authentication fails
// Example: Authenticated request
const response = await fetch('http://localhost:8083/myservice/v1/process', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ input: 'data' })
});

Route Resolution

After authentication, the runtime determines:

  • mim ID: Which mim to invoke
  • Endpoint: Which handler function to call
  • Version: Which version of the mim (if multiple deployed)

Stage 2: mim Instantiation

Once the target mim is identified, the runtime creates a new instance.

Instance Creation

For JavaScript mims:

  1. Create new JavaScript VM instance
  2. Load mim code bundle
  3. Inject context object with runtime APIs
  4. Call initialization (if defined)

For WASM mims:

  1. Load WASM module from storage
  2. Instantiate WebAssembly module
  3. Bind imported functions (storage, HTTP, etc.)
  4. Call WASM entry point

Context Object Injection (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' }));
});

Stage 3: Request Processing

With the instance initialized, 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.path - 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.path);

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

Limited Streaming Support

Currently, mimOE does not support streaming responses (SSE, chunked encoding). All responses must be complete before returning. Streaming support is planned for a future release.

Stage 5: Instance Termination

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

Cleanup Process

Cleanup steps:

  1. Close open connections: Any HTTP connections opened by the instance
  2. Flush pending I/O: Ensure storage writes complete
  3. Release memory: Free heap and stack memory
  4. Destroy VM/module: Terminate JavaScript VM or WASM instance
  5. Update metrics: Record execution time, memory used, etc.

State Destruction

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-20ms

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