Skip to content

feat(data-warehouse): implement inngest import source - #70715

Merged
talyn-app[bot] merged 4 commits into
masterfrom
posthog-code/inngest-warehouse-source
Jul 15, 2026
Merged

feat(data-warehouse): implement inngest import source#70715
talyn-app[bot] merged 4 commits into
masterfrom
posthog-code/inngest-warehouse-source

Conversation

@Gilbert09

Copy link
Copy Markdown
Member

Problem

Inngest (durable workflow engine: event-triggered functions with steps, retries, and flow control) was scaffolded as a warehouse source but had no sync logic. Inngest's own event and run history is plan-gated (24 hours on free plans up to 90 days on enterprise), so users can't keep long-term history or join workflow data with their product data — a synced copy in the PostHog Data warehouse solves both.

Changes

Implements the inngest source end-to-end behind unreleasedSource=True with releaseStatus=alpha:

  • Auth: per-environment signing key (Authorization: Bearer signkey-...), which covers both the v1 and v2 REST APIs (dashboard API keys are v2-only and can't reach events/runs). Optional environment field targets branch environments via the X-Inngest-Env header.
  • Tables:
    • events – append-only sync driven by the server-side received_after/received_before window (always passed explicitly, since the server default is only 1 hour) with cursor + limit=100 pagination. First sync backfills up to 90 days.
    • function_runs – merge sync. Runs have no list endpoint, so they're discovered by walking the incremental events window and fetching GET /v1/events/{internal_id}/runs per event. Each row carries an injected event_received_at watermark column, batch runs are deduped by run_id within a sync, and a 1-hour default incremental lookback re-reads recent runs so statuses settle.
    • cancellations, environments, webhooks, event_keys, signing_keys – small full-refresh inventories. The raw key secret returned by the v2 key endpoints is stripped before rows are yielded, so key material never lands in the warehouse.
  • Architecture follows the ResumableSource contract: declarative endpoint catalog in settings.py, transport/pagination/normalization in inngest.py, registration/schemas/credential validation in source.py, plus canonical_descriptions.py for the docs/AI table catalog. Resume state (cursor + pinned window) is saved after each yielded page. All HTTP goes through make_tracked_session() with the signing key value-redacted and sample capture disabled (event payloads are arbitrary customer data).
  • The events walk declares sort_mode="desc" so the incremental watermark persists only at successful job end. The API's ordering within a window is undocumented and I couldn't curl-verify it without credentials (endpoint shapes were verified against the live API's OpenAPI specs and unauthenticated probes; noted in code comments). Same reason the paginator defensively drops a re-returned cursor event.
  • Icon (official Inngest mark), SOURCES.md moved to Implemented, user-facing doc added as inngest.posthog-doc.mdx in the source directory — a posthog.com checkout wasn't available, so it needs to be copied to posthog.com/contents/docs/cdp/sources/inngest.md and audit_source_docs run once it lands.

How did you test this code?

Automated tests only (no live Inngest credentials were available, so no manual end-to-end sync was run):

  • tests/test_inngest.py (transport): window computation guards the 1-hour server default and clamps future watermarks; cursor pagination carries the pinned window on every page, terminates on partial/empty pages, saves resume state after each yielded page and not on the final one, resumes from saved state without re-deriving the window, and drops a re-returned cursor event; runs fan-out injects event_received_at, JSON-encodes non-string outputs, and dedupes batch runs; v2 pagination follows page.hasMore with a repeated-cursor loop guard and strips secret key material; 429/5xx retry vs 4xx fail-fast; sort mode/partition/primary keys per endpoint.
  • tests/test_inngest_source.py (source class): schema catalog and per-endpoint incremental/append support, credential validation plumbing (including the env header), non-retryable 401/403 mapping, resumable manager binding, and pipeline argument plumbing (blank environment normalized to None, watermark omitted on full refresh).
  • Also ran the registry-wide suites (sources/tests/, common/test/test_source_config_generator.py, 1551 tests) plus ruff check/ruff format and hogli ci:preflight --fix (0 failures).

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

Docs update

User-facing doc included as inngest.posthog-doc.mdx (needs to land in the posthog.com repo, see above).

🤖 Agent context

Autonomy: Fully autonomous

Implemented with Claude Code following the /implementing-warehouse-sources, /documenting-warehouse-sources, and /writing-tests skills. Endpoint behavior was verified against Inngest's published v1/v2 OpenAPI specs and unauthenticated probes of the live API (auth error shapes, route existence); decisions that couldn't be verified without credentials were made conservatively and commented: sort_mode="desc" (unknown ordering), inclusive-cursor defense, no limit on v2 lists (undocumented maxima), and dual-spelling normalization of the event receivedAt/received_at field. Chose a hand-rolled paginator over the generic rest_source.RESTClient because the runs table needs a per-event fan-out driven off the same windowed cursor walk as events. Skipped a functions table: v2 has no list-apps endpoint, so app/function metadata isn't enumerable.


Created with PostHog Code

@github-actions

Copy link
Copy Markdown
Contributor

Hey @Gilbert09! 👋

It looks like your git author email on this PR isn't your @posthog.com address (owerstom@gmail.com). Since you're on the PostHog team, it's worth pointing your local git author email at your @posthog.com address. Why it matters:

  • Consistent work identity in git history — internal tooling that attributes commits to team members keys off your @posthog.com address.
  • Keeps team contributions easy to tell apart from external community ones when scanning history.

You can fix it for this repo with:

git config user.email "you@posthog.com"

Or set it globally with git config --global user.email "you@posthog.com". No need to redo this PR — just a nudge for next time. 🙂

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

🦔 Hogbox preview · ✅ ready

▶ Open the preview

🔑 Login test@posthog.com / 12345678 (demo data)
🧩 Running this PR's backend and frontend, on the PostHog :master base
🔗 Link stable across rebuilds — a re-push swaps the box underneath, the URL stays
🔒 Access tailnet only (PostHog VPN)
🛠️ Admin inspect & debug state in hogland
💤 Idle sleeps after ~30 min idle (snapshot to S3, zero node cost) and wakes on your next visit in ~30s, behind a brief "waking up" screen

commit 4f11758 · box box-26f6704af2cc · ready in 705s (push → usable) · build log · rebuilds on every push, torn down on close

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

🤖 CI report

Bundle size — no change

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 64.77 MiB · no change

No file changed by more than 1000 B.

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

Eager graph — within budget

How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.

Root Eager (shipped) Δ vs base Budget
entry (logged-out pages, app bootstrap)
src/index.tsx
1.22 MiB · 22 files no change ███░░░░░░░ 28.4% of 4.29 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
8.13 MiB · 2,978 files no change █████████░ 87.9% of 9.25 MiB

🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx

Largest files eagerly shipped from src/index.tsx
Size File
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
24.6 KiB ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js
6.3 KiB ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js
4.5 KiB ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js
3.9 KiB ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js
1.4 KiB ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js
1.3 KiB src/RootErrorBoundary.tsx
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
789 B src/scenes/ChunkLoadErrorBoundary.tsx
762 B src/index.tsx
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
281.3 KiB ../node_modules/.pnpm/posthog-js@1.402.3/node_modules/posthog-js/dist/rrweb.js
267.7 KiB ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
235.5 KiB src/taxonomy/core-filter-definitions-by-group.json
222.9 KiB ../node_modules/.pnpm/posthog-js@1.402.3/node_modules/posthog-js/dist/module.js
164.0 KiB src/queries/validators.js
154.3 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
105.8 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
92.7 KiB ../packages/quill/packages/quill/dist/index.js

Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479

Dist folder size — 🔺 +2.5 KiB (+0.0%)

Total size of the built frontend/dist folder (all assets), compared against the base branch.

Total: 1312.49 MiB · 🔺 +2.5 KiB (+0.0%)

Playwright — all passed

All tests passed.

View test results →

⚠️ Backend coverage — 98.0% of changed backend lines covered — 7 uncovered

🧪 Backend test coverage

Patch coverage — changed backend lines (products + core): ████████████████████ 98.0% (522 / 529)

File Patch Uncovered changed lines
products/warehouse_sources/backend/temporal/data_imports/sources/inngest/inngest.py 95.9% 114, 118–120, 281, 293, 301

🤖 Agents: add a test covering the lines above, or note why under "How did you test this code?". Machine-readable gap list: the patch-coverage artifact on this run (gh run download 29457855823 -n patch-coverage), or the coverage-data block at the end of this comment.

Per-product line coverage (touched products)
Product Coverage Lines
demo ███████████░░░░░░░░░ 56.2% 1,497 / 2,663
tasks █████████████░░░░░░░ 67.4% 25,560 / 37,895
signals ████████████████░░░░ 79.1% 19,033 / 24,073
data_modeling ████████████████░░░░ 80.0% 4,834 / 6,045
cdp ████████████████░░░░ 80.7% 3,118 / 3,864
notebooks █████████████████░░░ 84.3% 6,343 / 7,520
agent_platform █████████████████░░░ 84.7% 3,273 / 3,862
cohorts █████████████████░░░ 86.1% 4,022 / 4,671
actions █████████████████░░░ 86.6% 717 / 828
product_tours █████████████████░░░ 87.5% 1,266 / 1,447
exports ██████████████████░░ 88.3% 6,891 / 7,800
conversations ██████████████████░░ 88.9% 16,129 / 18,133
dashboards ██████████████████░░ 89.1% 5,719 / 6,418
mcp_analytics ██████████████████░░ 89.1% 2,502 / 2,807
error_tracking ██████████████████░░ 89.6% 9,718 / 10,852
alerts ██████████████████░░ 89.9% 3,638 / 4,046
engineering_analytics ██████████████████░░ 90.1% 5,105 / 5,665
streamlit_apps ██████████████████░░ 90.4% 2,499 / 2,764
slack_app ██████████████████░░ 90.6% 9,511 / 10,503
marketing_analytics ██████████████████░░ 90.8% 11,514 / 12,684
product_analytics ██████████████████░░ 91.1% 5,599 / 6,143
data_warehouse ██████████████████░░ 92.1% 18,133 / 19,683
workflows ██████████████████░░ 92.4% 5,148 / 5,574
web_analytics ███████████████████░ 92.7% 13,624 / 14,691
ai_observability ███████████████████░ 92.8% 14,868 / 16,019
surveys ███████████████████░ 92.9% 5,687 / 6,120
posthog_ai ███████████████████░ 93.2% 1,322 / 1,418
approvals ███████████████████░ 93.3% 3,395 / 3,640
reminders ███████████████████░ 93.4% 468 / 501
early_access_features ███████████████████░ 93.8% 848 / 904
endpoints ███████████████████░ 94.1% 8,606 / 9,143
skills ███████████████████░ 94.4% 2,827 / 2,995
revenue_analytics ███████████████████░ 94.5% 3,598 / 3,809
review_hog ███████████████████░ 94.6% 6,532 / 6,905
logs ███████████████████░ 95.3% 9,528 / 9,994
experiments ███████████████████░ 95.6% 24,171 / 25,288
replay_vision ███████████████████░ 95.7% 13,354 / 13,952
annotations ███████████████████░ 96.2% 732 / 761
warehouse_sources ███████████████████░ 96.2% 230,770 / 239,807
feature_flags ███████████████████░ 96.3% 16,002 / 16,625
user_interviews ███████████████████░ 96.4% 2,242 / 2,325
data_catalog ███████████████████░ 97.1% 2,035 / 2,095
customer_analytics ███████████████████░ 97.2% 7,480 / 7,698

Report-only. Patch coverage = changed backend lines covered vs origin/master. Sorted lowest first.
Known gaps: lines covered only by Temporal tests show as uncovered; core line numbers may drift if master changed the same file.

@veria-ai

veria-ai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

PR overview

All previously flagged issues have been addressed. No open security concerns remain on this pull request.

Security review

No open security issues remain on this pull request.

Fixed/addressed: 2 · PR risk: 0/10

@trunk-io

trunk-io Bot commented Jul 14, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

@danielcarletti danielcarletti left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Implements the Inngest warehouse source end-to-end: events (append via
server-side received_after windowing), function runs (merge, discovered by
fanning out over the incremental events walk), plus cancellations,
environments, webhooks, and event/signing key inventories as full-refresh
tables. Resumable cursor walk with pinned time windows, tracked HTTP
transport, canonical table descriptions, icon, docs, and tests.

Generated-By: PostHog Code
Task-Id: fe7d3805-9748-42dc-b991-77c43b21515a
Webhook intake URLs are capability-bearing: anyone holding one can submit
events that trigger Inngest functions. Strip them before yielding, like the
event/signing key secret material, and cover it with a test.

Generated-By: PostHog Code
Task-Id: fe7d3805-9748-42dc-b991-77c43b21515a
Remove unreleasedSource=True so the finished source is visible in the
connector catalog, and drop any test asserting the hidden state.
Long stretches of run-less events yield no rows, making the per-event runs
walk look stalled; emit a progress log every 1000 events walked. A per-sync
request budget was considered and deliberately not added: the events walk
ordering is unverified, so stopping early could persist a watermark past
events never walked (silent data loss), and no global list-runs endpoint
exists to replace the per-event lookups.

Generated-By: PostHog Code
Task-Id: fe7d3805-9748-42dc-b991-77c43b21515a
@Gilbert09
Gilbert09 force-pushed the posthog-code/inngest-warehouse-source branch from a1600f5 to 4f11758 Compare July 15, 2026 23:12
@talyn-app
talyn-app Bot merged commit 131baa6 into master Jul 15, 2026
257 checks passed
@talyn-app
talyn-app Bot deleted the posthog-code/inngest-warehouse-source branch July 15, 2026 23:42
@deployment-status-posthog

deployment-status-posthog Bot commented Jul 16, 2026

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-07-16 00:06 UTC Run
prod-us ✅ Deployed 2026-07-16 00:21 UTC Run
prod-eu ✅ Deployed 2026-07-16 00:26 UTC Run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants