Skip to content

fix(edxapp): source Granian concurrency per install from stack config - #5636

Open
blarghmatey wants to merge 2 commits into
mainfrom
tmacey/granian-per-install-stack-config
Open

fix(edxapp): source Granian concurrency per install from stack config#5636
blarghmatey wants to merge 2 commits into
mainfrom
tmacey/granian-per-install-stack-config

Conversation

@blarghmatey

Copy link
Copy Markdown
Member

What are the relevant tickets?

tk-stage-3-adopt-new-granian-defaults-for-mitxonlin-16de40, project wp-granian-configuration-overhaul-expose-blocking-t-3debc2. Follows #5607.

Description (What does this do?)

k8s_resources.py is shared by four Open edX installs (mitx, mitx-staging, mitxonline, xpro), so a concurrency value written there is written for all four at once. That is how the 2026-08-26 CMS regression reached mitxonline Studio. Per #5607's post-mortem, the rollout cut per-pod backpressure 8x (2 workers x 64 to 1 x 16), APISIX p95/p99 reached the 60s histogram ceiling, and Tempo placed 30-59s ahead of a Django span that itself took 0.2-1.1s. granian_connections_active for mitxonline CMS pinned at 15-16 through that window and has been back at 50 (p99, 3d) since the rollback.

#5607 mitigated it by restoring the holding pins in shared code. That is correct for mitxonline and collateral damage for the other two: mitx and mitx-staging CMS have run 1 worker x 8 threads since 2026-08-24T17:18Z and would be dragged back to 2 workers on their next deploy.

Both webapps now read edxapp:k8s_granian.{lms,cms} from stack config, alongside the existing k8s_replicas and k8s_resources. The key is required rather than defaulted, so an install's concurrency is readable in its own stack file and a new install has to state a value rather than inherit whatever was last written into shared code.

install LMS CMS
mitx, mitx-staging 1 x 8, backpressure 16 1 x 8, backpressure 16
mitxonline, xpro 2 x 32, backpressure 64 2 x 32, backpressure 64

Every value matches what is live as of 2026-08-28, read from the container args on applications-production and residential-production.

How can this be tested?

pulumi preview against each Production stack:

  • mitxonline.Production: 238 unchanged, zero changes. The holding pins are preserved exactly.
  • mitx.Production: 3 Deployment updates (--disable-prefetch, from fix(edxapp): add --disable-prefetch to all celery workers to fix KEDA scaling #5598) plus 2 RDS alarm deletions. No Granian arg diff. Previewing the same stack against origin/main instead shows a 4th Deployment update, on CMS: [7]: "1" => "2" (workers), --runtime-mode mt reinserted, blocking-threads 8 => 32, backpressure 16 => 64, workers-max-rss 1843 => 921. That is the collateral revert this PR prevents.
  • mitx-staging.Production: a Vault mount option update, 3 --disable-prefetch, 2 RDS alarm deletions. No Granian arg diff.
  • xpro.Production: previews cleanly and renders --blocking-threads 32 --backpressure 64. Its 127 changes are dominated by the pre-existing ~6-month drift on that stack (it still runs the hand-rolled xpro-production-edxapp-{cms,lms}-webapp Deployments), unrelated to this PR.

pre-commit run over the changed files passes, mypy included.

Additional notes

mitx CMS does touch its backpressure ceiling of 16, for 52 minutes out of 3 days (granian_connections_active >= 16, 1m resolution), with a peak granian_blocking_queue of 5 and zero container restarts. mitx-staging CMS: 33 minutes, peak queue 0. Healthy, but the ceiling is the signal to watch if authoring traffic on either grows.

Raising mitxonline off the holding pins still needs concurrency sizing that accounts for burst shape, plus a scaling or alerting signal that sees connection saturation -- CPU and request rate did not.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HgKWpUsasvv1pLGBDhyBo5

k8s_resources.py is shared by mitx, mitx-staging, mitxonline and xpro, so a
concurrency value written there is written for all four at once. That is how
the 2026-08-26 CMS regression reached mitxonline Studio: defaults sized against
a 0.25 rps authoring instance dropped per-pod backpressure 8x, pods pinned at
16 active connections, and APISIX p95/p99 hit the 60s ceiling while Django
spans stayed at 0.2-1.1s.

#5607 restored the holding pins in shared code, which also un-does mitx and
mitx-staging CMS on their next deploy -- both have run 1 worker x 8 threads
since 2026-08-24T17:18Z with a peak blocking queue of 5 and 0, and zero
container restarts over 3 days. Verified by preview: on origin/main,
mitx.Production shows a 4th Deployment update reinserting --runtime-mode mt
and workers 1->2 on CMS; with this change it does not.

Both webapps now read edxapp:k8s_granian.{lms,cms}, required rather than
defaulted, alongside k8s_replicas and k8s_resources. An install's concurrency
is readable in its own stack file, and a new install has to state a value
rather than inherit whatever was last written into shared code.

mitx and mitx-staging take 1 x 8 / backpressure 16; mitxonline and xpro take
the pre-overhaul 2 x 32 / backpressure 64. Every value matches what is live as
of 2026-08-28. pulumi preview: mitxonline.Production 238 unchanged, 0 changes;
mitx.Production and mitx-staging.Production show no Granian arg diff.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HgKWpUsasvv1pLGBDhyBo5
Copilot AI balanced review requested due to automatic review settings August 28, 2026 15:34

Copilot AI 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.

Pull request overview

Moves Open edX LMS and CMS Granian concurrency from shared code into per-stack configuration, preserving install-specific production capacity.

Changes:

  • Requires separate LMS and CMS Granian settings.
  • Configures all 12 edxapp stacks with appropriate concurrency.
  • Documents the rollout and operational rationale.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
Pulumi.xpro.QA.yaml Adds xpro QA concurrency pins.
Pulumi.xpro.Production.yaml Adds xpro production concurrency pins.
Pulumi.xpro.CI.yaml Adds xpro CI concurrency pins.
Pulumi.mitxonline.QA.yaml Adds mitxonline QA concurrency pins.
Pulumi.mitxonline.Production.yaml Preserves production holding pins.
Pulumi.mitxonline.CI.yaml Adds mitxonline CI concurrency pins.
Pulumi.mitx.QA.yaml Adds CMS settings alongside LMS settings.
Pulumi.mitx.Production.yaml Preserves tuned mitx concurrency.
Pulumi.mitx.CI.yaml Adds tuned CMS concurrency.
Pulumi.mitx-staging.QA.yaml Adds tuned CMS concurrency.
Pulumi.mitx-staging.Production.yaml Preserves tuned staging concurrency.
Pulumi.mitx-staging.CI.yaml Adds tuned CMS concurrency.
k8s_resources.py Sources both webapps’ Granian configuration per stack.
granian-configuration-overhaul.md Records the per-install design and rollout status.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/ol_infrastructure/applications/edxapp/Pulumi.xpro.CI.yaml Outdated
Comment thread src/ol_infrastructure/applications/edxapp/Pulumi.xpro.QA.yaml Outdated
Comment thread src/ol_infrastructure/applications/edxapp/Pulumi.xpro.Production.yaml Outdated
The comment was copied from mitxonline, so it attributed mitxonline's
measurements -- LMS p99 17.7, the 2026-08-26 CMS backpressure saturation --
to xpro, which has neither. xpro-openedx still runs the hand-rolled
pre-OLApplicationK8s Deployments and emits no granian_* series at all, so
its pins are retained for want of a measurement, not because of one.

Values unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HgKWpUsasvv1pLGBDhyBo5
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