How we wired Trigger.dev to FastAPI automations
Reconn2’s spine is boring on purpose: one pattern per automation, whether the job is a full ConstructConnect extract or a login health probe.
Orchestration
Trigger.dev owns schedules, retries, and the operator-facing run log. Each task is a thin TypeScript wrapper that:
- Builds a small JSON payload (run id, optional target date, dry-run flag).
- POSTs to
/internal/automations/on the Render-hosted FastAPI service withX-Reconn2-Automation-Secret. - Parses the JSON
AutomationResultand surfaces failures as failed runs.
That keeps credentials out of Trigger payloads entirely.
Python execution
Each route delegates to a callable in reconn2.automations. The callable:
- Validates settings (API keys, portal URLs, usernames) up front.
- Runs the connector (OpenAI Agents sandbox, Playwright, or future paths).
- Uploads the raw extract JSON to
raw-artifacts/./ .json - Inserts or updates
public.source_runswith counts, errors, and the storage key.
Downstream graph projection reuses the same evidence model so CRM rows stay traceable.
Storage and Postgres
Supabase Storage holds bytes; Supabase Postgres holds queryable state under RLS. Signed URLs for artifacts are minted server-side — anonymous clients never see the bucket.
Failure modes we plan for
Portals change without notice. Failed ARHCA or ConstructConnect runs surface as red source_runs rows before downstream graph projection silently goes stale. ConstructConnect defaults to Playwright elastic extract; optional OpenAI sandbox and Firecrawl paths stay behind explicit feature flags.
Takeaway
Adding a connector means one FastAPI route, one Trigger task, and one row shape in source_runs. The UI, billing, and MCP layers stay stable because the contract is stable.
Read the operator runbook in docs/TRIGGER_DEV_RUNBOOK.md in the repo for task ids and manual run payloads.
Want to explore Canadian industrial data?
Start Free Trial