Skip to content

UN-3972 [DEV] Cut dashboard cron DB time by indexing workflow_file_execution on (status, created_at) - #2264

Open
kirtimanmishrazipstack wants to merge 5 commits into
UN-3883-Optimize-DB-cron-queries-causing-high-DB-loadfrom
UN-3972-index-file-execution-status-created-at
Open

UN-3972 [DEV] Cut dashboard cron DB time by indexing workflow_file_execution on (status, created_at)#2264
kirtimanmishrazipstack wants to merge 5 commits into
UN-3883-Optimize-DB-cron-queries-causing-high-DB-loadfrom
UN-3972-index-file-execution-status-created-at

Conversation

@kirtimanmishrazipstack

@kirtimanmishrazipstack kirtimanmishrazipstack commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

What

One database index on processed files, covering status and date together.

The second index the ticket also asks for is not here — dropped in comment 45015.

Why

The dashboard cron costs ~3,580 s of database time per 6 h on prod. Two queries are 83% of
that
, and both look up processed files by date and status.

Nothing organises the data that way, so the database reads all 1,278,885 execution rows on every
call. This index lets it start from the files in the date range instead.

How

SeparateDatabaseAndState: RunSQL builds the index CONCURRENTLY IF NOT EXISTS, a state-only
AddIndex keeps Django's model state in step, and atomic = False because CONCURRENTLY cannot
run in a transaction. A RAISE EXCEPTION guard fails loudly on a leftover INVALID index, which
IF NOT EXISTS would otherwise keep while Django recorded the migration as applied.

Do not regenerate with makemigrations — it emits a plain AddIndex, holding a SHARE lock
for the whole build on a 3.4 GB table.

Can this PR break any existing features. If yes, please list possible items. If no, please explain why.

No. Nothing but an index is added — no behaviour changes — and it is built without blocking
writes. The cost is slightly slower writes on that table, against 1,679 ms of query time saved
per 6 h.

Database Migrations

file_execution/0007_wfe_status_created_idx.py — builds the index without locking writes, and
reverses cleanly. Optionally build it by hand first; the deploy then skips it:

CREATE INDEX CONCURRENTLY IF NOT EXISTS wfe_status_created_idx
  ON workflow_file_execution (status, created_at);

Migration Order

The three UN-3883 PRs stack on the same integration branch. Merge in this order.

Order PR Migration Depends on This PR?
1 #2255 · UN-3973 dashboard_metrics/0005_add_reconciliation_task 0004_pg_periodic_tasks (UN-3445, already on main) No — merge before this PR
2 #2264 · UN-3972 file_execution/0007_wfe_status_created_idx file_execution/0006_… Yes — this PR
3 #2265 · UN-3974 dashboard_metrics/0006_split_aggregation_schedule 0005_add_reconciliation_task (#2255) No — merge after this PR

#2264's migration is in a different app and has no interaction with the other two. The one
hard dependency is #2265 on #2255 — merged out of order, #2265 fails at graph build:

NodeNotFoundError: Migration dashboard_metrics.0006_split_aggregation_schedule
dependencies reference nonexistent parent node ('dashboard_metrics', '0005_add_reconciliation_task')

Its tests are unaffected — the backend suite runs with --no-migrations.

Verified on a throwaway Postgres: 000400050006 applies from an empty database,
reverses, and re-applies, with makemigrations --check clean at each step.

Env Config

None.

Relevant Docs

UN-3883 analysis §6.4.

Related Issues or PRs

Parent UN-3883. #2255 (UN-3973) — AC-3 depends on it. #2265 (UN-3974). See Migration Order above.

Dependencies Versions

None.

Notes on Testing

Nine scenarios and five unit tests. Detail in Jira comment 45381.

# Acceptance criterion Verdict
1 Index present, indisvalid = t Met
2 Non-atomic + CONCURRENTLY, no write-blocking lock Met
3 get_documents_processed free of a seq scan on workflow_file_execution Confirm on prod
4 get_failed_pages free of a seq scan on workflow_execution Met
5 get_recent_activity under 1 s Flagged — belongs to the dropped index

After deploy: confirm the index is valid, then re-pull the 6-hour Query Insights window against
the 870 / 809 ms baseline.

Screenshots

n/a — schema-only change.

Checklist

I have read and understood the Contribution Guidelines.

The dashboard metrics cron's documents_processed and failed_pages queries
filter this table on status + a created_at window, but all four existing
indexes lead with workflow_execution_id. With no entry point here the planner
drives top-down from the org and sequentially scans all 1.28M rows of
workflow_execution — 83% of the cron's DB time on production.

Built CONCURRENTLY with atomic = False; a plain AddIndex would hold a SHARE
lock over a 3.4GB table taking live inserts. Guarded against a leftover
INVALID index from an interrupted build, which IF NOT EXISTS would otherwise
keep silently.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGZBF68CShem3pbUJM2tBc
@greptile-apps

greptile-apps Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds a concurrent PostgreSQL index on (status, created_at) for workflow file executions and keeps Django’s model state synchronized.

  • Adds a non-atomic migration with concurrent create/drop operations and an invalid-index guard.
  • Declares the corresponding index in WorkflowFileExecution.Meta.
  • Adds focused migration-shape and model-state tests.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
backend/workflow_manager/file_execution/migrations/0007_wfe_status_created_idx.py Adds an independently ordered, non-atomic migration that creates and drops the composite index concurrently and rejects an existing invalid index.
backend/workflow_manager/file_execution/models.py Adds the matching (status, created_at) index declaration to Django model state.
backend/workflow_manager/file_execution/tests/test_wfe_status_created_idx.py Verifies concurrent migration SQL, non-atomic execution, invalid-index handling, and agreement between migration and model state.

Reviews (7): Last reviewed commit: "Merge remote-tracking branch 'origin/UN-..." | Re-trigger Greptile

Comment thread backend/dashboard_metrics/internal_views.py
Comment thread workers/queue_backend/pg_queue/pg_scheduler.py
The docstring restated the prod plan, deployment runbook and recovery steps.
That detail belongs in the PR, not in a file every future agent scans.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGZBF68CShem3pbUJM2tBc
@github-actions

Copy link
Copy Markdown
Contributor

Unstract test results

Per-group results

Status Group Tier Passed Failed Errors Skipped Duration (s)
e2e-api-deployment e2e 3 0 0 0 16.8
e2e-coowners e2e 1 0 0 0 1.6
e2e-etl e2e 1 0 0 0 8.4
e2e-login e2e 2 0 0 0 1.2
e2e-prompt-studio e2e 1 0 0 0 4.6
e2e-smoke e2e 2 0 0 0 1.5
e2e-workflow e2e 1 0 0 0 16.4
integration-backend integration 310 0 0 26 44.3
integration-connectors integration 1 0 0 7 7.6
integration-workers integration 157 0 0 1 48.1
unit-backend unit 1158 0 0 1 38.4
unit-connectors unit 63 0 0 0 9.6
unit-core unit 33 0 0 0 1.1
unit-platform-service unit 15 0 0 0 2.3
unit-rig unit 117 0 0 0 5.0
unit-runner unit 5 0 0 0 2.6
unit-sdk1 unit 563 0 0 0 27.1
unit-workers unit 1397 0 0 1 125.5
TOTAL 3830 0 0 36 362.1

Critical paths

⚠️ Critical paths not yet covered

  • workflow-execution-fan-out — Multi-file workflow execution fans out to file-processing workers and rejoins. (declared coverage: no groups declared)
✅ Covered critical paths
  • auth-login — covered by e2e-login
  • adapter-register-llm — covered by integration-backend
  • workflow-author — covered by integration-backend
  • co-owner-manage — covered by integration-backend, e2e-coowners
  • workflow-create-execute — covered by e2e-workflow
  • api-deployment-provision — covered by integration-backend
  • api-deployment-auth — covered by integration-backend
  • api-deployment-run — covered by e2e-api-deployment
  • mcp-server-auth — covered by integration-backend
  • mcp-platform-auth — covered by integration-backend
  • prompt-studio-author — covered by integration-backend
  • prompt-studio-fetch-response — covered by e2e-prompt-studio
  • connector-register-test — covered by integration-backend
  • pipeline-etl-execute — covered by e2e-etl
  • usage-aggregate-read — covered by integration-backend
  • usage-token-tracking — covered by e2e-api-deployment
  • callback-result-delivery — covered by e2e-api-deployment

@kirtimanmishrazipstack

Copy link
Copy Markdown
Contributor Author

@greptile-apps please re-review.

The Confidence Score block above is stale — it still cites backend/dashboard_metrics/internal_views.py and workers/queue_backend/pg_queue/pg_scheduler.py, neither of which is in this PR. Both came from a stale-base diff that pulled the already-merged UN-3445 queue commit (#2254) in; the base is now main and the diff is 2 files. You retracted both findings in the threads and they are resolved.

For a human reader: this PR is backend/workflow_manager/file_execution/models.py (one models.Index line) and its hand-written concurrent migration. Nothing else.

@kirtimanmishrazipstack
kirtimanmishrazipstack changed the base branch from main to UN-3883-Optimize-DB-cron-queries-causing-high-DB-load August 31, 2026 15:37
…into UN-3972-index-file-execution-status-created-at
…ape with tests

The suite runs with --no-migrations, so 0007 is never executed in CI. Regenerating it
with makemigrations, or dropping atomic = False / CONCURRENTLY while tidying, would land
a plain AddIndex — a SHARE lock held for the whole build on a 3.4 GB table that takes
live inserts — with every test still green.

Five DB-free assertions on the migration module and the model's Meta.indexes: non-atomic,
concurrent in both directions, the INVALID-index guard present, AddIndex confined to
state_operations, and model/migration agreement.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGZBF68CShem3pbUJM2tBc
…-causing-high-DB-load' into UN-3972-index-file-execution-status-created-at
@sonarqubecloud

sonarqubecloud Bot commented Sep 1, 2026

Copy link
Copy Markdown

@kirtimanmishrazipstack

Copy link
Copy Markdown
Contributor Author

@greptile-apps migration order is revised. Review again.

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.

1 participant