Event System
Event pipeline stages, webhook receiver, Flow Router, Dead Letter Queue, and Synthetic Event Engine.
Fastn uses an event-driven architecture for processing integration triggers. Events flow through a multi-stage pipeline ensuring reliability and at-least-once delivery.
Event pipeline
Events pass through 6 stages:
1. Receive
External events arrive via webhook receiver or synthetic polling
Fastify HTTP server
2. Outbox
Events are written to the PostgreSQL outbox table within a database transaction
PostgreSQL transactional guarantee
3. Fan-out
Outbox poller publishes events to Redis Streams using FOR UPDATE SKIP LOCKED
Redis Streams
4. Normalize
Event normalizer creates a NormalizedEvent with a SHA-256 idempotency key
In-memory processing
5. Route
Flow Router matches events to registered triggers using condition AST
In-memory trigger index
6. Execute
Matched flows are dispatched to BullMQ for workflow execution
BullMQ job queue
Webhook receiver
Receives and validates incoming webhooks from third-party apps.
Verification
Signature verification
HMAC SHA-256
Configurable secret per connector. Rejects requests with invalid signatures.
Timestamp freshness
5-minute window
Rejects webhooks older than 5 minutes to prevent replay attacks.
Deduplication
Redis-based
Prevents duplicate processing of the same webhook.
Webhook registration
Each connector-tenant pair has a registered webhook endpoint:
The webhook receiver extracts the connector and tenant context from the URL, validates the signature, and passes the payload to the event pipeline.
Flow Router
Matches incoming events to registered triggers and dispatches flows for execution.
Trigger index
An in-memory index of all active triggers. When an event arrives, the router checks every trigger's conditions against the event data.
Condition AST operators
eq
Equals
status eq "completed"
neq
Not equals
status neq "cancelled"
gt
Greater than
total gt 100
lt
Less than
quantity lt 0
in
Value in list
status in ["completed", "shipped"]
contains
String contains
email contains "@company.com"
exists
Field exists and is not null
trackingNumber exists
Priority routing
P1
User-triggered
API requests, manual triggers — highest priority
P2
Event-driven
Webhook events, app events
P3
Background
Scheduled workflows, batch processing
P4
Polling
Synthetic events from polling — lowest priority
Higher priority events are processed first when the system is under load.
Dynamic trigger management
Triggers are registered and removed dynamically:
When a flow is deployed, its trigger is registered in the index
When a flow is undeployed or deleted, its trigger is removed
Changes take effect immediately — no restart required
Dead Letter Queue (DLQ)
Failed events that cannot be processed are captured in the DLQ.
What goes to the DLQ
Events that fail processing after all retry attempts
Events with invalid payloads that can't be normalized
Events that match no registered trigger (configurable — can be dropped instead)
DLQ record schema
id
Unique DLQ entry ID
event_payload
Full original event data
error_message
Why processing failed
error_context
Stack trace, step name, connector info
tenant_id
Which tenant's event failed
connector
Source connector
created_at
When the event entered the DLQ
retry_count
How many times replay has been attempted
status
pending, replayed, expired
DLQ operations
Manual replay — Retry a specific failed event
Automated replay — Configure automatic retry policies
Retention — Configurable cleanup policies for old DLQ entries
Depth monitoring — DLQ depth is tracked and triggers alerts when thresholds are exceeded
Synthetic Event Engine
Detects changes in external systems that don't support webhooks.
How it works
Poll — Fetch records from the external system at configurable intervals
Hash — Generate SHA-256 hash of each record
Compare — Compare current hashes against stored hashes in Redis (7-day TTL)
Diff — Field-level diffing identifies what changed
Emit — Generate synthetic events for new, updated, or deleted records
Adaptive polling
Polling intervals adjust automatically based on:
Changes detected
More changes → shorter intervals
Rate limiting
Rate limit responses → longer intervals
Business hours
More frequent polling during business hours
Activity patterns
Learning from historical change patterns
Base intervals are configurable per entity type.
Deletion detection
The engine detects deleted records by comparing the current snapshot against the previous one. Records present in the previous snapshot but absent in the current one are flagged as deleted.
Scheduling
Polling schedules are managed via Redis sorted sets for efficient scheduling across many tenants and entity types.
Last updated
Was this helpful?

