Skip to main content

LumenizeWorker

LumenizeWorker is the base class for stateless mesh nodes running as Cloudflare Workers. Use it for:

  • External API calls — Proxy third-party services without DO wall-clock billing
  • Compute-intensive tasks — CPU-bound work that doesn't need state
  • Fan-out/fan-in — Distribute work across multiple Workers
  • Validation/transformation — Process data without persistence

For a hands-on introduction, see the Getting Started Guide.

Mesh API

LumenizeWorker shares the standard Mesh API with all node types — this.lmz for identity and calls, @mesh() decorator for entry points, onBeforeCall() for access control, and this.ctn<T>() for continuations. Note that this.lmz.instanceName is always undefined since Workers have no instance name.

Key Differences from LumenizeDO

AspectLumenizeDOLumenizeWorker
StorageSQL/KV via ctx.storageNone
InstanceNamed instancesEphemeral
ConsistencyStrongN/A (stateless)
AsyncMethods should be syncAsync allowed (no consistency concern)
NADISFull (this.svc)None (no storage-dependent services)
CostWall-clock billingCPU-only billing

No Instance Name

Workers don't have instances. When calling a Worker, pass undefined for the instance name:

// From a DO calling a Worker
this.lmz.call(
'VALIDATION_WORKER',
undefined, // No instance name
this.ctn<ValidationWorker>().validate(data)
);

Async Methods Are Fine

Unlike DOs, Workers don't have consistency constraints from input gates, so async methods are not discouraged:

class MyWorker extends LumenizeWorker<Env> {
@mesh()
async processData(data: InputData): Promise<OutputData> {
// Async operations are safe here — no race condition risk
const external = await fetch('https://api.example.com/process');
const transformed = await this.transformAsync(data, external);
return transformed;
}
}

Common Patterns

External API Proxy

Call external APIs with reduced DO wall-clock billing for longer external calls. Considering added request costs, the break even point is ~500ms. If doing this adds a single tracking DO storage write on the calling end as @lumenize/fetch does, the breakeven point is ~1.6s and is not recommended below 5s.

class EmailWorker extends LumenizeWorker<Env> {
@mesh()
async sendEmail(to: string, subject: string, body: string): Promise<SendResult> {
const response = await fetch('https://api.sendgrid.com/v3/mail/send', {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.env.SENDGRID_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
personalizations: [{ to: [{ email: to }] }],
from: { email: 'noreply@myapp.com' },
subject,
content: [{ type: 'text/plain', value: body }],
}),
});

if (!response.ok) {
const error = await response.text();
throw new Error(`Email send failed: ${error}`);
}

return { success: true, messageId: response.headers.get('X-Message-Id') };
}
}

Compute-Intensive Tasks

Offload CPU-bound work from DOs. This will likely cost more than doing it in a DO, but doing a CPU-bound task in a DO blocks other requests which increases latency and reduces the DO's throughput, unlike the IO-bound fetch example above which allows other request to interleave.

class ImageProcessingWorker extends LumenizeWorker<Env> {
@mesh()
processImage(imageData: ArrayBuffer): Promise<ProcessedImage> {
// CPU-intensive operations
const thumbnail = await this.generateThumbnail(imageData);
const metadata = await this.extractMetadata(imageData);
const optimized = await this.optimize(imageData);

return { thumbnail, metadata, optimized };
}
}

Two One-Way Call Pattern

For long-running calls like the two above, use a "two one-way call" pattern: DO fires-and-forgets to Worker, Worker calls back later with result. See Making Calls: Two One-Way Calls for the full pattern.

API Reference

See Mesh API for the full LumenizeWorker class reference including env, lmz, onBeforeCall(), and ctn<T>().