Architecture
A deep-dive into how AlgoBridge works internally.
Overview
AlgoBridge consists of two database layers and a sync engine that runs on a fixed 10-second schedule.
┌─────────────────────────────────────────────────────┐
│ AlgoBridge Server │
│ │
│ ┌─────────────┐ ┌──────────────────────┐ │
│ │ Platform DB │ │ Sync Engine │ │
│ │ (platform PG) │ │ (runs every 10s) │ │
│ │ │ │ │ │
│ │ tenants │ │ 1. Poll _trigger_log │ │
│ │ workspaces │ │ 2. Batch → SF API │ │
│ │ mappings │ │ 3. Write back result │ │
│ └─────────────┘ └──────────────────────┘ │
└─────────────────────────────────────────────────────┘
│ │
▼ ▼
┌─────────────┐ ┌────────────────┐
│ Client PG │ │ Salesforce │
│ (your DB) │◄────────►│ API │
│ │ │ │
│ _trigger_log│ │ SOAP / Bulk │
│ contact │ │ v2 │
│ opportunity │ └────────────────┘
└─────────────┘
Two Database Model
AlgoBridge strictly separates two databases:
Platform Database (managed by AlgoBridge)
Stores operational metadata only. Never stores your sync data.
| Table | Purpose |
|---|---|
workspaces |
Workspace accounts |
workspace_connections |
Salesforce + PostgreSQL credentials (encrypted) |
workspace_mappings |
Object-to-table mapping configuration |
sync_history |
Per-batch sync audit log |
Client Database (your PostgreSQL)
Your own PostgreSQL instance. AlgoBridge installs a small set of system objects and then works entirely within them.
| Object | Type | Purpose |
|---|---|---|
_trigger_log |
Table | CDC queue — captures every change |
_trigger_log_archive |
Table | 31-day audit trail of processed rows |
_abmeta |
Table | Schema metadata (mapped columns, sfid mapping) |
ab_{table}_logtrigger |
Trigger | Fires on INSERT/UPDATE/DELETE, writes to _trigger_log |
ab_{table}_logger() |
Function | Trigger function for the log trigger |
ab_{table}_status_trigger |
Trigger | Write-back guard — skips the log trigger during SF→PG writes |
ab_{table}_status() |
Function | Checks ab.in_sync session variable |
Trigger-Based Change Data Capture
When a row changes in a mapped table, the logger trigger fires and inserts a row into _trigger_log:
-- Installed automatically for each mapped table
CREATE OR REPLACE FUNCTION ab_contact_logger()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO _trigger_log (
txid, table_name, record_id, sfid, action, state, values
) VALUES (
txid_current(),
'contact',
NEW.id,
NEW.sfid,
TG_OP, -- 'INSERT', 'UPDATE', or 'DELETE'
'NEW',
hstore(NEW) - hstore(OLD) -- hstore diff: only changed columns
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER ab_contact_logtrigger
AFTER INSERT OR UPDATE OR DELETE ON contact
FOR EACH ROW EXECUTE FUNCTION ab_contact_logger();
Why hstore (not JSONB)?
hstore stores the column diff as a flat key-value map. This matches the de facto standard for Salesforce sync. The diff (hstore(NEW) - hstore(OLD)) captures only the columns that actually changed, reducing payload size to Salesforce.
State Machine
Every row in _trigger_log moves through a defined state machine:
NEW ──► PENDING ──► SUCCESS
└──► FAILED
| State | Meaning |
|---|---|
NEW |
Row inserted by trigger, not yet picked up |
PENDING |
Sync engine has claimed the row, API call in-flight |
SUCCESS |
Salesforce confirmed the operation |
FAILED |
API call failed; _ab_err populated with error detail |
The _ab_lastop column on the mapped table itself reflects the outcome:
_ab_lastop |
Set when |
|---|---|
PENDING |
Row first inserted (trigger sets this) |
INSERTED |
SF confirmed a new record was created |
UPDATED |
SF confirmed an existing record was updated |
SYNCED |
Row written back from Salesforce → PostgreSQL |
FAILED |
Sync failed |
Sync Engine — 10-Second Batch
The sync worker runs on a fixed 10-second schedule (not configurable — this matches the de facto standard). Each cycle:
- Claim:
UPDATE _trigger_log SET state = 'PENDING' WHERE state = 'NEW' RETURNING * - Batch: Group claimed rows by Salesforce object
- Route: ≤ 200 records → SOAP API; > 200 records → Bulk API v2
- Write back: On success, set
state = 'SUCCESS'and_ab_lastop = 'INSERTED' | 'UPDATED' - Guard: Before writing back to the mapped table, set
SET LOCAL ab.in_sync = 'true'— the status trigger checks this variable and skips re-logging the write
SOAP vs Bulk API
| SOAP API | Bulk API v2 | |
|---|---|---|
| Threshold | ≤ 200 records per batch | > 200 records per batch |
| Latency | Low (~200ms round-trip) | Higher (job-based, async) |
| Best for | Small, frequent changes | Large initial loads or bulk updates |
| SF API calls used | 1 per record (counted against daily limit) | 1 job + chunks (lower per-record cost) |
SF → PG Write-Back
When Salesforce pushes changes back (via polling the SF REST API), the sync engine:
- Queries Salesforce for records modified since the last
systemmodstamp - Upserts rows into the mapped PostgreSQL table
- Sets
SET LOCAL ab.in_sync = 'true'before each write - The status trigger sees
ab.in_sync = 'true'and skips inserting into_trigger_log, preventing a feedback loop
-- Status trigger function (installed per mapped table)
CREATE OR REPLACE FUNCTION ab_contact_status()
RETURNS TRIGGER AS $$
BEGIN
IF current_setting('ab.in_sync', true) = 'true' THEN
RETURN NEW; -- skip logging, this is a write-back
END IF;
NEW._ab_lastop := 'PENDING';
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
31-Day Archive
After a _trigger_log row reaches SUCCESS or FAILED, it is moved to _trigger_log_archive:
INSERT INTO _trigger_log_archive SELECT * FROM _trigger_log WHERE state IN ('SUCCESS', 'FAILED');
DELETE FROM _trigger_log WHERE state IN ('SUCCESS', 'FAILED');
Rows in _trigger_log_archive are purged after 31 days. This gives you a full audit trail without unbounded table growth.
Credential Security
PostgreSQL connection strings and Salesforce OAuth tokens are stored encrypted at rest in the platform database. Encryption uses the ENCRYPTION_KEY environment variable (a 32-character key). The raw credentials are never logged or exposed through any API endpoint.
Exponential Backoff on FAILED Rows
When a trigger-log row transitions to FAILED, AlgoBridge does not immediately retry it on the next 10-second cycle — doing so would hammer Salesforce with known-broken records and exhaust your daily API quota.
Instead, FAILED rows follow an exponential backoff schedule:
| Attempt | Wait before retry |
|---|---|
| 1st failure | 30 seconds |
| 2nd failure | 2 minutes |
| 3rd failure | 10 minutes |
| 4th failure | 1 hour |
| 5th+ failure | 6 hours (cap) |
The _trigger_log.retry_after timestamp controls when the row becomes eligible again. The sync worker skips rows where retry_after > now().
To bypass the backoff and force an immediate retry, use the Retry button in the Record Explorer or reset the row’s state to NEW directly.
CDC Gap Detection and SOQL Backfill
Salesforce’s Change Data Capture (CDC) replay window is 72 hours. If the AlgoBridge process is down or the CDC subscription lapses for longer than that, the replay window expires and CDC events are lost.
AlgoBridge detects this condition by comparing the last-seen CDC event timestamp against the current time. When the gap exceeds a configurable threshold (default: 72 hours), it automatically falls back to a full SOQL backfill for each affected mapping:
- Queries Salesforce for all records where
SystemModstamp > last_successful_sync_at - Upserts those records into PostgreSQL
- Resumes CDC streaming from the current position
This backfill runs as a one-off job and does not interrupt the normal 10-second sync cycle for other mappings.
Bulk API v2 for Initial Loads
When a mapping is first activated, AlgoBridge performs an initial load — fetching the entire dataset for that Salesforce object and inserting it into PostgreSQL. For large objects (e.g. millions of Account records), this initial load uses Bulk API v2 regardless of record count, because the SOAP API batch limit (200 records per call) would exhaust the daily API quota.
The Bulk API v2 initial load:
- Creates a Bulk API v2 query job for the mapped fields
- Streams result batches directly into PostgreSQL via upsert
- Sets
_ab_lastop = 'SYNCED'on every inserted row - Marks the mapping as
activeonly after the initial load completes successfully
Subsequent incremental syncs (CDC + SOQL polling) use the normal SOAP/Bulk threshold (≤ 200 → SOAP, > 200 → Bulk).
Compound External Keys (Multi-Field Upsert Keys)
By default, AlgoBridge uses the sfid column as the upsert key for SF→PG writes. For bidirectional sync, a secondary external key field (e.g. Email on Contact) handles the race window where a new record has not yet received its sfid from Salesforce.
AlgoBridge supports up to 3-column compound external keys for mappings where a single field is insufficient for deduplication. When a compound key is configured, the SF→PG upsert strategy becomes:
UPDATE … WHERE sfid = $1— matches by Salesforce ID if knownUPDATE … WHERE ext_key_1 = $1 AND ext_key_2 = $2 AND sfid IS NULL— matches by the compound key when sfid has not yet been written backINSERT— new record if neither of the above matched
Configure compound keys in Mappings → Edit Mapping → External Key Fields (select up to 3 fields).
Conflict Resolution for Bidirectional Sync
In bidirectional sync mode, the same record can be modified in both PostgreSQL and Salesforce within the same 10-second window. Without a resolution policy, the last writer wins — which can cause updates to be silently overwritten.
AlgoBridge resolves conflicts using Salesforce as the system of record by default:
- The PG→SF sync sends the PostgreSQL change to Salesforce
- Salesforce accepts the write and updates
SystemModstamp - The next SF→PG poll detects the updated
SystemModstampand writes the Salesforce version back to PostgreSQL - If the Salesforce write failed (e.g. validation rule), the
FAILEDrow in_trigger_logpreserves the original PostgreSQL value for inspection
This means that if both sides change simultaneously, the Salesforce value wins on the next poll cycle (typically within 60–70 seconds).