DataTalksClub / DataTalksClub/website
Set an explicit gunicorn worker timeout in the website entrypoint
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 0
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
Set an explicit gunicorn worker timeout in the website entrypoint
PM-groomed specification
Reviewed 2026-09-02 against origin/main at
2d3c28d1b8d1c2f3844f47f664945b42849d5eb9 (tree
f7af08192c09361a3d064e8f8282b11d568ff211). This is an XS target-native
deployment hardening issue. It is independent of the unrelated dirty local
worktree edits and does not authorize provider or production changes.
Product outcome
The web branch of the website's target-owned entrypoint.sh gives Gunicorn
an explicit 90-second worker timeout. A slow configured outbound call therefore
reaches its own bounded client timeout first and can follow its ordinary safe
failure path instead of being killed at Gunicorn's implicit 30-second default.
The value is evidence-based: the largest currently configured application
outbound timeout is Datamailer's 60 seconds, and the selected 90 seconds adds a
10-second completion/logging margin. This matches the reviewed CMP precedent in
e49c575ce3f567cc14a8f66a89d3ccaca3bfe2f4 without copying CMP files.
Current outbound-timeout inventory
| Surface | Configured timeout | Runtime relevance |
|---|---|---|
course_management/datamailer/client.py (DATAMAILER_TIMEOUT_SECONDS, default from website/settings/base.py) |
60s | Largest application HTTP client; deployment currently leaves the Datamailer URL/API key disabled. An explicit future environment override above 80s is outside this issue and must be reviewed together with the deployment timeout contract. |
content_sync/course_repository_sync.py GitHub codeload fetch |
30s | Durable content-sync job/worker, not the Gunicorn web request path; included to show it is below 90s. |
courses/validators/custom_url_validators.py injected HEAD/GET transport |
3s | Controlled/test transport only; production callers intentionally perform no synchronous user-controlled HTTP. |
course_management/observability/cloudwatch_dashboard.py |
connect 1s/read 3s | Staff Studio dashboard request; below 90s. |
| S3 development-content transport | none explicitly configured | Management-command transport; its SDK default is not a reviewed bound and is a separate hardening concern, not a reason to invent a Gunicorn value. |
CI, E2E, deployment probes, local Git subprocesses, and test harness timeouts
are tooling/process budgets, not application outbound clients served by this
entrypoint. The website has no Relay client yet; the specifications require
future Relay network work to run only after commit through a durable worker.
Scope
- Add the literal
--timeout 90pair to the Gunicorn command in theweb)case
of target-ownedentrypoint.sh. - Extend
core.source_policy.validate_gunicorn_entrypointso it parses that
web command and requires exactly one numeric--timeoutvalue of 90; a
missing, duplicated, malformed, interpolated, or lower timeout fails closed.
Existing access-log privacy checks remain unchanged. - Add a focused regression to the existing source-policy test that reads the
realentrypoint.sh, checks the parser, and mutates/removes the timeout to
prove rejection. The regression must derive the safety assertion from
course_management.datamailer.client.DEFAULT_TIMEOUT_SECONDSand assert
gunicorn_timeout >= DEFAULT_TIMEOUT_SECONDS + 10, so a future change to the
reviewed Datamailer default cannot silently invalidate the relationship.
Explicit non-goals
- Do not copy CMP's
Dockerfilechange orcourses/tests/test_deploy_config.py;
the website's deployment contract isentrypoint.shpluscore.source_policy. - No Dockerfile/CMP source-pin/adoption-manifest change, container command
redesign, worker/job retry change, or new timeout environment variable. - No change to Datamailer enablement, client behavior, Relay integration,
email purpose/sender, S3/CloudWatch/URL-validator timeout policy, business
semantics, provider/network calls, production data, deployment, commit, or
push. - A deploy-time
DATAMAILER_TIMEOUT_SECONDSoverride above 80 seconds is not
silently accepted by this issue; it requires a separately reviewed change to
the timeout contract/value.
Dependencies and ownership
This issue is target-owned and independently implementable. #305/#50 own the
Datamailer disablement/retirement and future Relay boundary; they are related
coordination, not prerequisites. No owner decision is required for this
fixed, source-evidenced 90-second hardening.
Acceptance criteria
-
entrypoint.sh'sweb)Gunicorn command contains exactly one literal
--timeout 90; theworker)command is unchanged and no Dockerfile CMD is
used as the source of truth. -
validate_gunicorn_entrypointextracts/parses the web command and fails
closed for absent, duplicate, malformed, interpolated, or lower timeout
values while preserving the existing access-log privacy contract. - The focused regression proves the real command passes, each timeout
mutation fails, and the parsed 90 seconds is at least the current
Datamailer default plus the 10-second margin. It also proves the reviewed
30/3-second application client bounds do not exceed the selected value. -
make migrations-check, the focused Django/source-policy tests, and the
graph-selecteduv-backed quality/type/CI/container checks pass. No
migration is expected; a discovered model or deployment-schema change stops
the issue for re-grooming. - The engineer leaves an uncommitted frozen handoff with exact base/head,
plan digest, changed-file list, tests, and the timeout inventory. The
independent tester recomputes the plan and verifies all criteria before PM
acceptance.
Verification plan and browser evidence
This is an internal entrypoint/source-policy change with no product-page or
rendered error-surface change. The tester runs focused Django and applicable
control-plane/container checks plus the graph-selected backend Playwright tier;
screenshots are not_applicable only when the recomputed graph confirms no
render inputs changed. No browser/provider/network session is needed for the
acceptance claim.
After tester PASS, PM posts product acceptance. Only then may the engineer
create a focused commit with Closes #304; the orchestrator performs the
normal local no-ff merge/push and on-call observes resulting CI. No pull
request, deployment, or live send is part of this issue.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the web) command in entrypoint.sh and core.source_policy.validate_gunicorn_entrypoint, then locate the existing source-policy regression that reads the real entrypoint. Add the literal timeout contract and focused mutation checks, deriving the safety assertion from course_management.datamailer.client.DEFAULT_TIMEOUT_SECONDS. Run the focused Django/source-policy tests and the listed migrations, quality, type, CI, and container checks; done means all acceptance criteria pass without changing the worker command.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, shell
- Domain
- backend, devops
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100