Create an Ephemeral Function
How to create a temporary worker that completes a task and gracefully shuts down.
Goal
Create a script that connects to the engine, waits to process a task (e.g., generating a heavy report), and then gracefully shuts down.
Context
This pattern is useful for executing resource-intensive or one-off tasks on serverless container platforms (like AWS Fargate or Kubernetes Jobs) where you want to minimize execution time and infrastructure costs.
Steps
1. Initialize and Register
Connect to iii and register the reports::generate function handler to process the heavy CPU task.
import { registerWorker, Logger } from 'iii-sdk'
const iii = registerWorker(process.env.III_URL ?? 'ws://localhost:49134')
iii.registerFunction({ id: 'reports::generate' }, async (req) => {
const logger = new Logger()
const reportId = req.body?.reportId ?? 'unknown'
logger.info('Generating heavy report...', { reportId })
// ... perform resource-intensive work here ...
await new Promise(resolve => setTimeout(resolve, 5000)) // example 5 second delay
logger.info('Report generated', { reportId })
return { status_code: 200, body: { success: true, reportId } }
})import os
import time
from iii import Logger, register_worker
iii = register_worker(os.environ.get("III_URL", "ws://localhost:49134"))
def generate_report(req):
logger = Logger()
report_id = req.get("body", {}).get("reportId", "unknown")
logger.info("Generating heavy report...", {"reportId": report_id})
# ... perform resource-intensive work here ...
time.sleep(5) # example 5 second delay
logger.info("Report generated", {"reportId": report_id})
return {"status_code": 200, "body": {"success": True, "reportId": report_id}}
iii.register_function({"id": "reports::generate"}, generate_report)use iii_sdk::{Logger, RegisterFunctionMessage, TriggerRequest, register_worker, InitOptions};
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let url = std::env::var("III_URL").unwrap_or_else(|_| "ws://127.0.0.1:49134".to_string());
let iii = register_worker(&url, InitOptions::default());
iii.register_function(
RegisterFunctionMessage {
id: "reports::generate".into(),
description: None,
request_format: None,
response_format: None,
metadata: None,
invocation: None,
},
|req| async move {
let logger = Logger::new();
let report_id = req["body"]["reportId"].as_str().unwrap_or("unknown");
logger.info("Generating heavy report...", Some(json!({ "reportId": report_id })));
// ... perform resource-intensive work here ...
tokio::time::sleep(std::time::Duration::from_secs(5)).await; // example 5 second delay
logger.info("Report generated", Some(json!({ "reportId": report_id })));
Ok(json!({
"status_code": 200,
"body": { "success": true, "reportId": report_id }
}))
},
);2. Trigger and Graceful Shutdown
The main thread connects, triggers the function, awaits its completion, then calls shutdown() to cleanly close the WebSocket and exit the process.
async function main() {
console.log("Worker ready, triggering task...")
// Trigger the task and await its completion
const result = await iii.trigger({
function_id: 'reports::generate',
payload: { body: { reportId: '123' } },
})
console.log("Task completed", result.status_code, result.body)
console.log("Task completed. Shutting down worker...")
// Cleanly close the WebSocket connection
await iii.shutdown()
process.exit(0)
}
main().catch(console.error)print("Worker ready, triggering task...")
# Trigger the task and await its completion
result = iii.trigger({
"function_id": "reports::generate",
"payload": {"body": {"reportId": "123"}},
})
print(f"Task completed: status_code={result.get('status_code')} body={result.get('body')}")
print("Task completed. Shutting down worker...")
# Cleanly close the WebSocket connection
iii.shutdown() println!("Worker ready, triggering task...");
// Trigger the task and await its completion
let result = iii
.trigger(TriggerRequest {
function_id: "reports::generate".into(),
payload: json!({ "body": { "reportId": "123" } }),
action: None,
timeout_ms: None,
})
.await?;
println!("Task completed: {}", result);
println!("Task completed. Shutting down worker...");
// Cleanly close the WebSocket connection
iii.shutdown_async().await;
Ok(())
}Result
When the script runs, it connects to the Engine, waits for a single invocation of reports::generate, executes it, and cleanly disconnects and exits immediately after. This prevents zombie processes and automatically scales your infrastructure down once the heavy lifting is done.