DataTalksClub / DataTalksClub/website

Set an explicit gunicorn worker timeout in the website entrypoint

Open
#304 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug infra operations P2 testing
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 90 pair to the Gunicorn command in the web) case
    of target-owned entrypoint.sh.
  • Extend core.source_policy.validate_gunicorn_entrypoint so it parses that
    web command and requires exactly one numeric --timeout value 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
    real entrypoint.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_SECONDS and 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 Dockerfile change or courses/tests/test_deploy_config.py;
    the website's deployment contract is entrypoint.sh plus core.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_SECONDS override 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's web) Gunicorn command contains exactly one literal
    --timeout 90; the worker) command is unchanged and no Dockerfile CMD is
    used as the source of truth.
  • validate_gunicorn_entrypoint extracts/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-selected uv-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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.