Skip to content

Event-driven serverless video transcoding pipeline. Uses Cloudflare Workers for control-plane orchestration, R2 for storage, Upstash Redis for state coordination, and Fly.io Machines for ephemeral compute.

Notifications You must be signed in to change notification settings

v0id-user/tcoder

Repository files navigation

TCoder - Event Driven Serverless Transcoding Pipeline

Implementation of an event-driven, serverless video transcoding pipeline. Composes Cloudflare Workers for orchestration, R2 for object storage, Upstash Redis for state management, and Fly.io Machines for compute. Built with TypeScript, Hono, and Effect.

This is a personal side project built to explore architectural tradeoffs in distributed orchestration, backpressure handling, and worker lifecycle management. It is not intended for production use.

Demo Site: https://tcoder-web.cloudflare-c49.workers.dev/

Blog Post: I tried to understand how large-scale video pipelines work, so I built a serverless transcoding system

Architecture

Three-layer separation: control plane, state store, and compute plane. Each layer has distinct responsibilities and failure boundaries.

Layer Component Responsibility
Control Plane Cloudflare Worker API endpoints, admission control, machine lifecycle management
State Store Upstash Redis Job queue, machine pool tracking, job status
Compute Plane Fly.io Machines FFmpeg transcoding, R2 I/O operations

Event-Driven Serverless Transcoding Pipeline

System Design

Redis Worker Orchestration System

Admission Control Flow

Worker Lifecycle

Event-Driven Design

R2 object creation events drive the pipeline. Uploads trigger queue messages, which update Redis state and trigger machine provisioning decisions.

  1. Upload: Client requests presigned URL from Worker API. Uploads video directly to R2 input bucket.

  2. Event Notification: R2 emits object-created event to Cloudflare Queue (tcoder-events).

  3. Queue Processing: Worker queue handler receives batch, extracts job ID from object key, updates Redis job status to pending, enqueues job in sorted set.

  4. Admission Control: Worker checks Redis machine pool for available capacity. If under limit, attempts to start stopped machine or spawn new Fly.io Machine.

  5. Job Processing: Fly.io Machine polls Redis for jobs using ZPOPMIN. On job assignment, downloads input from R2, runs FFmpeg transcoding, uploads outputs to R2 output bucket.

  6. Completion: Machine sends webhook to Worker API with job results. Worker updates Redis job status. Client polls status endpoint or receives webhook callback.

  7. Machine Lifecycle: Idle machines remain in pool. Scheduled cron job stops machines idle beyond threshold and recovers stuck uploading jobs. Stopped machines can be restarted for new jobs.

Quick Start

Prerequisites

  • Bun runtime
  • Cloudflare account (Workers, R2, Queues)
  • Upstash account (Redis)
  • Fly.io account

Setup

  1. Install dependencies:

    bun install
  2. Create R2 buckets and queue:

    bunx wrangler r2 bucket create tcoder-input && \
    bunx wrangler r2 bucket create tcoder-output && \
    bunx wrangler queues create tcoder-events && \
    bunx wrangler r2 bucket notification create tcoder-input --event-type object-create --queue tcoder-events
  3. Set Cloudflare Worker secrets:

    bunx wrangler secret bulk .env

    Required secrets (see env.local.example):

    • UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN
    • FLY_API_TOKEN, FLY_APP_NAME, FLY_REGION
    • R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY
    • R2_INPUT_BUCKET_NAME, R2_OUTPUT_BUCKET_NAME
    • WEBHOOK_BASE_URL
  4. Initialize Fly.io app:

    bun run fly:first-launch

    Set Fly secrets (see fly/README.md).

  5. Deploy:

    bun run deploy        # Cloudflare Worker
    bun run fly:deploy    # Fly.io image

Project Structure

tcoder/
├── src/
│   ├── index.ts              # Worker entry, queue + cron handlers
│   ├── api/                  # Hono API routes
│   ├── r2/                   # Presigned URLs, event handling
│   ├── redis/                # Upstash client and schema
│   └── orchestration/        # Admission, spawner, machine pool
├── fly/
│   ├── ffmpeg-worker/        # Fly Machine worker code
│   └── Dockerfile            # Worker container
├── packages/
│   └── tcoder-client/        # TypeScript SDK
└── design/
    └── architecture/         # PlantUML diagrams

Documentation

Scripts

bun run dev              # Local development
bun run deploy           # Deploy Cloudflare Worker
bun run fly:deploy       # Deploy Fly.io image
bun run fly:logs         # View Fly.io logs
bun run test             # Run tests

Related Projects

  • TCoder Middleware: Bunny.net edge middleware that protects /premium/ paths by verifying JWT tokens.

About

Event-driven serverless video transcoding pipeline. Uses Cloudflare Workers for control-plane orchestration, R2 for storage, Upstash Redis for state coordination, and Fly.io Machines for ephemeral compute.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published