Installing Postulo → Putting it on a server: gunicorn is missing, test tools installed, no scheduler #540

Closed
opened 2026-10-01 10:47:29 +00:00 by tiagoagueda · 1 comment
Owner

Found on 2026-09-29 in a read-only review of postulo at 95348908d, following the wiki's bare-metal steps against pyproject.toml and the Dockerfile, with a dry-run uv sync of the lock file.

Related to #154.

Checked again on 2026-10-01 against main at 0a5cad587: still present.

The steps for running Postulo without Docker install the wrong set of packages and then leave out the processes a working instance needs. An operator who follows them literally gets a failing server command, the browser test stack in production, and, once the server runs, reminders that never fire and exports that are never deleted.

  • Where: Installing-Postulo.md:182-186 (step 1, uv sync --no-dev), Installing-Postulo.md:222-229 (step 5, uv run gunicorn … and "(gunicorn is not a dependency of Postulo; install whichever server you prefer.)"), Installing-Postulo.md:236 ("There is no background worker to run. Nothing in Postulo currently queues work."), Installing-Postulo.md:329-334 (upgrading without Docker, a bare uv sync). Against pyproject.toml:56 (server = ["gunicorn>=23.0"]), pyproject.toml:82 (default-groups = ["dev", "e2e"]) and docker/Dockerfile:89 and :94 (uv sync --locked --no-default-groups --extra server --extra postgres).
  • What happens:
    1. --no-dev drops only the dev group; e2e is a default group too, so playwright, pytest, pytest-base-url and pytest-playwright are installed and gunicorn is not (checked with uv sync --locked --no-dev --dry-run). Each later uv run syncs the default groups again unless given the same flags.
    2. Step 5's uv run gunicorn … therefore fails. gunicorn is in fact Postulo's own server extra; a copy installed by hand, as the note suggests, is removed by the next exact uv sync, which is what the upgrade section runs.
    3. Line 236 has not been true since #247: manage.py send_due_reminders --loop (or a cron entry) is what sends reminders, webhooks and document copies, runs synchronisations and deletes expired export archives, and manage.py work is needed when POSTULO_BACKGROUND_WORK is set. Configuration documents both (Configuration.md:329-340, Configuration.md:424-427); this page contradicts it.
    4. manage.py fetch_geonames is not mentioned; the image's entrypoint runs it on first start, so a bare-metal instance has no city table and its company map places nothing (Configuration.md:101-106).
  • Why it matters: the page is the one an operator installing on a server follows step by step, and what it leaves out fails silently: nothing says reminders are not being sent.
  • Fix: step 1 becomes uv sync --locked --no-default-groups --extra server (plus --extra postgres for PostgreSQL), with a sentence that every later uv sync and uv run takes the same flags. Drop the gunicorn note. Replace line 236 with a step that runs the scheduler (a systemd unit or a cron line for manage.py send_due_reminders), manage.py work when background work is on, and manage.py fetch_geonames once. Make the upgrade section's uv sync repeat the install flags.

Done when

  • The page's steps, run in order on a clean machine, leave a server answering on the port with gunicorn from the server extra and without playwright installed, and name the scheduler; checked by hand, since the wiki has no tests.
Found on 2026-09-29 in a read-only review of postulo at 95348908d, following the wiki's bare-metal steps against `pyproject.toml` and the Dockerfile, with a dry-run `uv sync` of the lock file. Related to #154. Checked again on 2026-10-01 against `main` at `0a5cad587`: still present. The steps for running Postulo without Docker install the wrong set of packages and then leave out the processes a working instance needs. An operator who follows them literally gets a failing server command, the browser test stack in production, and, once the server runs, reminders that never fire and exports that are never deleted. - **Where:** `Installing-Postulo.md:182-186` (step 1, `uv sync --no-dev`), `Installing-Postulo.md:222-229` (step 5, `uv run gunicorn …` and "(gunicorn is not a dependency of Postulo; install whichever server you prefer.)"), `Installing-Postulo.md:236` ("There is no background worker to run. Nothing in Postulo currently queues work."), `Installing-Postulo.md:329-334` (upgrading without Docker, a bare `uv sync`). Against `pyproject.toml:56` (`server = ["gunicorn>=23.0"]`), `pyproject.toml:82` (`default-groups = ["dev", "e2e"]`) and `docker/Dockerfile:89` and `:94` (`uv sync --locked --no-default-groups --extra server --extra postgres`). - **What happens:** 1. `--no-dev` drops only the `dev` group; `e2e` is a default group too, so `playwright`, `pytest`, `pytest-base-url` and `pytest-playwright` are installed and gunicorn is not (checked with `uv sync --locked --no-dev --dry-run`). Each later `uv run` syncs the default groups again unless given the same flags. 2. Step 5's `uv run gunicorn …` therefore fails. gunicorn is in fact Postulo's own `server` extra; a copy installed by hand, as the note suggests, is removed by the next exact `uv sync`, which is what the upgrade section runs. 3. Line 236 has not been true since #247: `manage.py send_due_reminders --loop` (or a cron entry) is what sends reminders, webhooks and document copies, runs synchronisations and deletes expired export archives, and `manage.py work` is needed when `POSTULO_BACKGROUND_WORK` is set. *Configuration* documents both (`Configuration.md:329-340`, `Configuration.md:424-427`); this page contradicts it. 4. `manage.py fetch_geonames` is not mentioned; the image's entrypoint runs it on first start, so a bare-metal instance has no city table and its company map places nothing (`Configuration.md:101-106`). - **Why it matters:** the page is the one an operator installing on a server follows step by step, and what it leaves out fails silently: nothing says reminders are not being sent. - **Fix:** step 1 becomes `uv sync --locked --no-default-groups --extra server` (plus `--extra postgres` for PostgreSQL), with a sentence that every later `uv sync` and `uv run` takes the same flags. Drop the gunicorn note. Replace line 236 with a step that runs the scheduler (a systemd unit or a cron line for `manage.py send_due_reminders`), `manage.py work` when background work is on, and `manage.py fetch_geonames` once. Make the upgrade section's `uv sync` repeat the install flags. ## Done when - The page's steps, run in order on a clean machine, leave a server answering on the port with gunicorn from the `server` extra and without `playwright` installed, and name the scheduler; checked by hand, since the wiki has no tests.
tiagoagueda added this to the 0.6.0 milestone 2026-10-01 10:47:29 +00:00
Author
Owner

Corrected in the wiki (postulo.wiki ee6e8bd).

Corrected in the wiki (postulo.wiki ee6e8bd).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#540
No description provided.