Skip to main content

Hook0 Architecture

This document covers Hook0's architecture, the design decisions behind it, and how the components fit together.

System architecture

Default setup (PostgreSQL-only)

PostgreSQL handles everything: event storage, queue, and delivery state. Workers poll for pending deliveries using FOR UPDATE SKIP LOCKED for concurrent processing. One database to operate.

High-throughput setup (Pulsar + S3)

For high-throughput deployments, Hook0 can use Apache Pulsar for queuing and S3-compatible object storage for large payloads. The API server stores event payloads in S3 and publishes delivery tasks to Pulsar. Workers consume from Pulsar, retrieve event payloads from S3, deliver webhooks, and store response bodies back to S3. Workers also read metadata from PostgreSQL and record delivery results there. PostgreSQL remains the source of truth for metadata, subscriptions, and event types. The switch between backends is a per-worker database setting (queue_type column in infrastructure.worker), not a code change.

Component responsibilities

API server

Worker process

  • Retrieves pending delivery tasks from the queue (PostgreSQL or Pulsar)
  • Sends HTTP requests to subscription endpoints
  • Retries failed deliveries using a fixed schedule (3s, 10s, 3min, 30min, 1h, 3h, 5h, 10h)
  • Records delivery attempts and response data in PostgreSQL

Web dashboard

  • Vue.js-based management UI
  • Live updates on event processing
  • Configuration for subscriptions and event types
  • Delivery metrics and health dashboards

Event flow

For details on the event lifecycle, retry logic, and delivery handling, see the Event Processing Model.

Data model

Core entities

Event storage

Events are stored with:

Subscription matching

Subscriptions define:

Design decisions

Why Rust?

  • Memory safety without garbage collection
  • Good performance
  • Strong type system catches bugs at compile time

Why PostgreSQL as the default?

  • ACID guarantees
  • Good JSON support
  • Doubles as a job queue via FOR UPDATE SKIP LOCKED, so most deployments don't need a separate queuing system

Why Pulsar + S3 for high throughput?

  • Pulsar handles message ordering, fan-out, and backpressure at scale
  • S3-compatible storage offloads large payloads and response bodies from the database
  • Better fit for deployments processing millions of events per day
  • PostgreSQL stays the source of truth for metadata; Pulsar handles the delivery queue

Why Biscuit tokens?

Hook0 uses Biscuit tokens for both user sessions and service tokens:

  • More flexible than JWT
  • Built-in authorization
  • Supports token attenuation (restrict permissions without calling the server)

Next steps