Worker API reference
Worker code talks to the Alien worker runtime that runs next to it. You register handlers; the runtime delivers HTTP requests, commands, and trigger events to them.
| Language | Package | Handlers available |
|---|---|---|
| TypeScript | @alienplatform/sdk | HTTP, commands, queue, queue batch, storage, cron, waitUntil |
| Python | alienplatform (install alienplatform[worker]) | Queue, queue batch. Worker binding. |
| Rust | alien-sdk (AlienContext) | HTTP, commands, queue, queue batch, storage, cron, wait_until. Worker binding. |
TypeScript
HTTP
Export an HTTP app as the module's default export. Any framework with a fetch handler works, such as Hono. The runtime serves it on loopback and forwards the Worker's public endpoint traffic to it.
import { Hono } from "hono"
const app = new Hono()
app.get("/health", c => c.json({ ok: true }))
export default appcommand
function command<TResult = unknown>(
name: string,
handler: (params: unknown, context: WorkerCommandContext) => TResult | Promise<TResult>,
): void
function command<Schema extends StandardSchema, TResult = unknown>(
name: string,
schema: Schema,
handler: (
params: StandardSchemaOutput<Schema>,
context: WorkerCommandContext,
) => TResult | Promise<TResult>,
): void
interface WorkerCommandContext {
commandId: string
attempt: number // starts at 1; above 1 means redelivery
deadline?: Date
}Registers a command handler. The schema form validates params with any Standard Schema v1 validator, such as zod or valibot.
Invalid params throw Command input failed validation: <issues>. An unknown command name fails with the list of registered names.
Delivery is at least once: use attempt to make redeliveries safe. Requires .commandsEnabled(true). See Commands.
onQueueMessage
function onQueueMessage<T = unknown>(
queueName: string,
handler: (message: QueueMessageEvent<T>) => Promise<void>,
): () => void
interface QueueMessageEvent<T = unknown> {
id: string
source: string // queue name
receiptHandle: string
payload: T
attemptCount: number
timestamp: Date
attributes?: { [key: string]: string }
}Called once per message. Resolving acknowledges the message. Throwing makes it available for redelivery.
onQueueBatch
function onQueueBatch<T = unknown>(
queueName: string,
handler: (batch: QueueBatchEvent<T>) => Promise<QueueDeliveryOutcome[]>,
): () => void
interface QueueBatchEvent<T = unknown> {
source: string
deliveries: QueueDelivery<T>[]
}
interface QueueDelivery<T = unknown> {
deliveryId: string // identifies this delivery attempt, not the message
message: QueueMessageEvent<T>
}
interface QueueDeliveryOutcome {
deliveryId: string
disposition: "success" | "retry"
}Needs a queue trigger with batch. Return one outcome per delivery. A retry outcome redelivers that message only; it doesn't roll back the others.
Batches can be smaller than maxMessages and are unordered.
onStorageEvent
function onStorageEvent(
bucket: string,
handler: (event: StorageEvent) => Promise<void>,
options?: { prefix?: string },
): () => void
interface StorageEvent {
bucketName: string
objectKey: string
eventType:
| "created"
| "deleted"
| "copied"
| "metadataUpdated"
| "restored"
| "tierChanged"
| "unknown"
timestamp: string
size?: number
etag?: string
contentType?: string
versionId?: string
region?: string
metadata?: Record<string, string>
copySource?: string
currentTier?: string
previousTier?: string
}prefix filters by object key.
onCronEvent
function onCronEvent(
scheduleName: string,
handler: (event: CronEvent) => Promise<void>,
): () => void
interface CronEvent {
scheduleName: string
timestamp: string
}waitUntil
function waitUntil(promise: Promise<unknown>): voidTracks an already-started promise so work can continue after the response. Errors are logged, not returned. See Wait until.
Notes
- Every
on*function returns an unregister function. - Pass
"*"as the queue, bucket, or schedule name to handle every source. - Register handlers at module load. The runtime reads the registry when the Worker starts.
Python
from alienplatform import (
QueueBatch, QueueDelivery, QueueEvent, QueueOutcome,
on_queue_message, on_queue_batch, run_worker,
)
def on_queue_message(source: str, handler: Callable[[QueueEvent], Awaitable[None]]) -> None
def on_queue_batch(
source: str,
handler: Callable[[QueueBatch], Awaitable[Sequence[QueueOutcome]]],
) -> None
async def run_worker(*, address: str | None = None) -> None
@dataclass(frozen=True)
class QueueEvent:
id: str
payload: bytes
source: str
attempt_count: int
@dataclass(frozen=True)
class QueueDelivery:
delivery_id: str
message: QueueEvent
@dataclass(frozen=True)
class QueueBatch:
source: str
deliveries: tuple[QueueDelivery, ...]
@dataclass(frozen=True)
class QueueOutcome:
delivery_id: str
disposition: Literal["success", "retry"]Register handlers, then run the loop:
import asyncio
from alienplatform import on_queue_message, run_worker, QueueEvent
async def handle(event: QueueEvent) -> None:
print(event.source, event.attempt_count, event.payload)
on_queue_message("tasks", handle)
asyncio.run(run_worker())Handlers run one at a time. run_worker returns on shutdown or when the connection to the runtime is lost, and never acknowledges unfinished work.
Rust
use alien_sdk::AlienContext;
let ctx = AlienContext::from_env().await?;| Method | Signature |
|---|---|
on_queue_message | fn on_queue_message<F, Fut>(&self, queue: &str, handler: F) where F: Fn(QueueMessage) -> Fut, Fut: Future<Output = Result<()>> |
on_queue_batch | async fn on_queue_batch<F, Fut>(&self, queue: &str, handler: F) where Fut: Future<Output = Result<QueueBatchResult>> |
on_storage_event | fn on_storage_event<F, Fut>(&self, resource: &str, handler: F) where F: Fn(StorageEvent) -> Fut |
on_cron_event | fn on_cron_event<F, Fut>(&self, schedule: &str, handler: F) where F: Fn(CronEvent) -> Fut |
on_command | fn on_command<P, R, F, Fut>(&self, command: &str, handler: F) where P: DeserializeOwned, R: Serialize, F: Fn(P) -> Fut, Fut: Future<Output = Result<R>> |
register_http_server | async fn register_http_server(&self, port: u16) -> Result<()>. Tells the runtime where your HTTP server listens. |
run | async fn run(&self) -> Result<()>. Receives and dispatches tasks until shutdown. |
wait_until | fn wait_until<F, Fut>(&self, task_fn: F) -> Result<()> where F: FnOnce() -> Fut + Send + 'static, Fut: Future<Output = ()> + Send + 'static |
get_task_count | async fn get_task_count(&self) -> Result<u32>. Pending wait_until tasks. |
bindings | fn bindings(&self) -> &Bindings. Linked resources. |
pub struct QueueMessage {
pub id: String,
pub payload: Vec<u8>,
pub receipt_handle: String,
pub source: String,
pub attempt_count: u32,
}
pub struct StorageEvent {
pub key: String,
pub event_type: String,
pub bucket: String,
pub size: u64,
pub content_type: String,
}
pub struct CronEvent {
pub schedule_name: String,
pub scheduled_time: chrono::DateTime<chrono::Utc>,
}QueueBatch, QueueDelivery, QueueDeliveryOutcome, QueueBatchResult, and QueueDisposition are re-exported from the worker protocol. A batch result holds one outcome per delivery_id with disposition Success or Retry.
Worker binding
Rust and Python can call a linked Worker directly, without a public endpoint. Link the target Worker in alien.ts, then:
from alienplatform import worker
response = await worker("image-processor").invoke(
method="POST",
path="/resize",
headers={"content-type": "application/json"},
body=b'{"id":"img_123"}',
timeout_ms=10_000,
)
print(response.status, response.headers, response.body)
url = await worker("image-processor").public_url() # None for a private Worker| Platform | How invoke reaches the target |
|---|---|
| AWS | Lambda Invoke API |
| Google Cloud | Private Cloud Run service URL |
| Azure | Container App URL |
| Kubernetes | Internal Service |
The caller's permission profile needs worker/invoke on the target. TypeScript has no Worker binding: use the target's public endpoint or a command.