Workers Fundamentals
Worker là gì?
Edge Computing Model
┌─────────────────────────────────────────────────────────────┐
│ WORKERS EXECUTION │
├─────────────────────────────────────────────────────────────┤
│ │
│ Traditional Server: │
│ User (Vietnam) ──▶ Server (US) ──▶ Response │
│ Latency: ~200-300ms │
│ │
│ Cloudflare Workers: │
│ User (Vietnam) ──▶ Edge (Singapore) ──▶ Response │
│ Latency: ~20-50ms │
│ │
│ Code runs at the edge, closest to your users! │
│ │
└─────────────────────────────────────────────────────────────┘
V8 Isolates (không phải Containers)
┌─────────────────────────────────────────────────────────────┐
│ V8 ISOLATES │
├─────────────────────────────────────────────────────────────┤
│ │
│ Containers (Lambda): V8 Isolates (Workers): │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Container │ │ V8 Engine │ │
│ │ ┌────────────┐ │ │ ┌────┐ ┌────┐ │ │
│ │ │ App 1 │ │ │ │Is1 │ │Is2 │ │ │
│ │ └────────────┘ │ │ └────┘ └────┘ │ │
│ └──────────────────┘ │ ┌────┐ ┌────┐ │ │
│ │ │Is3 │ │Is4 │ │ │
│ Cold start: 100ms-1s+ │ └────┘ └────┘ │ │
│ Memory: 128MB-10GB └──────────────────┘ │
│ │
│ Cold start: ~0ms │
│ Memory: 128MB │
│ │
└─────────────────────────────────────────────────────────────┘
Basic Worker Structure
Minimal Worker
// src/index.ts
export default {
async fetch(request: Request): Promise<Response> {
return new Response('Hello World!');
},
};
With Environment
// Define environment interface
interface Env {
MY_VAR: string;
MY_SECRET: string;
MY_KV: KVNamespace;
MY_QUEUE: Queue;
}
export default {
// Main request handler
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
// env contains bindings (KV, Queue, vars, secrets)
// ctx for background tasks
return new Response(`Hello! Env: ${env.MY_VAR}`);
},
// Queue consumer (optional)
async queue(
batch: MessageBatch<any>,
env: Env,
ctx: ExecutionContext
): Promise<void> {
// Handle queue messages
},
// Cron handler (optional)
async scheduled(
event: ScheduledEvent,
env: Env,
ctx: ExecutionContext
): Promise<void> {
// Handle scheduled events
},
};
Request Handling
Request Object
async fetch(request: Request): Promise<Response> {
// URL information
const url = new URL(request.url);
console.log('Path:', url.pathname); // /api/users
console.log('Params:', url.searchParams); // ?id=123
// Method
console.log('Method:', request.method); // GET, POST, etc.
// Headers
console.log('Auth:', request.headers.get('Authorization'));
console.log('Content-Type:', request.headers.get('Content-Type'));
// Body (for POST, PUT)
if (request.method === 'POST') {
const body = await request.json();
console.log('Body:', body);
}
return new Response('OK');
}
Response Object
// Simple response
return new Response('Hello');
// JSON response
return new Response(JSON.stringify({ message: 'Hello' }), {
headers: { 'Content-Type': 'application/json' },
});
// Response with status
return new Response('Not Found', { status: 404 });
// Response helper
return Response.json({ message: 'Hello' });
return Response.redirect('https://example.com');
Routing Patterns
Simple Router
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
const path = url.pathname;
const method = request.method;
// Route matching
if (method === 'GET' && path === '/') {
return new Response('Home');
}
if (method === 'GET' && path === '/api/users') {
return handleGetUsers(env);
}
if (method === 'POST' && path === '/api/users') {
return handleCreateUser(request, env);
}
// Dynamic routes
const userMatch = path.match(/^\/api\/users\/([^/]+)$/);
if (userMatch) {
const userId = userMatch[1];
if (method === 'GET') return handleGetUser(userId, env);
if (method === 'DELETE') return handleDeleteUser(userId, env);
}
return new Response('Not Found', { status: 404 });
}
Using Hono (Recommended)
import { Hono } from 'hono';
interface Env {
MY_KV: KVNamespace;
}
const app = new Hono<{ Bindings: Env }>();
app.get('/', (c) => c.text('Home'));
app.get('/api/users', async (c) => {
const users = await c.env.MY_KV.get('users', 'json');
return c.json(users);
});
app.post('/api/users', async (c) => {
const body = await c.req.json();
// Create user
return c.json({ created: true }, 201);
});
app.get('/api/users/:id', (c) => {
const id = c.req.param('id');
return c.json({ id });
});
export default app;
ExecutionContext
Background Tasks
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
// Respond immediately
const response = new Response('Accepted');
// Do background work (doesn't block response)
ctx.waitUntil(
doBackgroundWork(env)
);
return response;
}
async function doBackgroundWork(env: Env) {
// This runs after response is sent
await env.MY_QUEUE.send({ type: 'log', data: 'something' });
await fetch('https://analytics.example.com/track', {
method: 'POST',
body: JSON.stringify({ event: 'request' }),
});
}
Pass Promises to waitUntil
// ✅ GOOD: Non-blocking
ctx.waitUntil(sendAnalytics());
return new Response('OK');
// ❌ BAD: Blocking (slow)
await sendAnalytics();
return new Response('OK');
Error Handling
Try-Catch Pattern
async fetch(request: Request, env: Env): Promise<Response> {
try {
const result = await processRequest(request, env);
return Response.json(result);
} catch (error) {
console.error('Error:', error);
if (error instanceof ValidationError) {
return Response.json(
{ error: error.message },
{ status: 400 }
);
}
return Response.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}
class ValidationError extends Error {
constructor(message: string) {
super(message);
this.name = 'ValidationError';
}
}
Limits
Worker Limits
┌─────────────────────────────────────────────────────────────┐
│ WORKER LIMITS │
├─────────────────────────────────────────────────────────────┤
│ │
│ Free: Paid: │
│ - 100k requests/day - 10M requests/month │
│ - 10ms CPU time - 50ms CPU time (30s total) │
│ - 128MB memory - 128MB memory │
│ - No scheduled - Cron triggers │
│ │
│ All Plans: │
│ - 100 subrequests per request │
│ - 6 concurrent connections │
│ - 1MB request body │
│ - 128KB script size (after gzip) │
│ │
└─────────────────────────────────────────────────────────────┘
Tổng kết
Worker Structure
export default {
// HTTP requests
async fetch(request, env, ctx) { ... },
// Queue messages
async queue(batch, env, ctx) { ... },
// Cron triggers
async scheduled(event, env, ctx) { ... },
};
Key Concepts
| Concept |
Description |
| Request |
Incoming HTTP request |
| Response |
HTTP response to return |
| Env |
Bindings (KV, Queue, vars) |
| ExecutionContext |
For background tasks |
| waitUntil |
Non-blocking async work |
Q&A
- Có kinh nghiệm serverless chưa?
- Routing library preference?
- Questions về limits?