Bỏ qua

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 });
}
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

  1. Có kinh nghiệm serverless chưa?
  2. Routing library preference?
  3. Questions về limits?