--- type: operations title: Cron Lifecycle description: How entrypoint.sh validates env, renders /etc/cron.d/tenbackward from RUN_AT/TZ, and hands off to cron -f. tags: [cron, entrypoint, ops] timestamp: 2026-08-04T17:51:00Z --- # Purpose `entrypoint.sh` is the first process inside the container. Its job is to refuse to boot when something is wrong with env config and to materialise a cron file from the templated values. # Sequence 1. Set `DEBIAN_FRONTEND=noninteractive`. 2. Set `TZ` (default `Europe/Berlin`) and link `/etc/localtime` if `/usr/share/zoneinfo/${TZ}` exists and `/etc/localtime` does not. 3. Iterate over `required_vars`. Any empty variable aborts with `ERROR: missing required environment variable(s): ...` and exits `1`. The current required set is listed in [Environment Variable Setup](/operations/environment-setup.md). 4. Validate `RUN_AT` against `^([01][0-9]|2[0-3]):[0-5][0-9]$`. Invalid input exits `1` with `ERROR: RUN_AT='X' must be in HH:MM (24-hour) format`. 5. Render `/etc/cron.d/tenbackward` into a `mktemp` file with: ```cron SHELL=/bin/bash PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin TZ=${TZ} ${minute} ${hour} * * * cd /app && /usr/local/bin/python -m tenbackward >> /app/data/cron.log 2>&1 ``` 6. Install the rendered file with mode `0644`, root:root. 7. Run `crontab/install-cron.sh /etc/cron.d/tenbackward`. The helper refuses files that still contain the `__RUN_AT__` placeholder and files that do not start with an `^[A-Z_]+=` cron env line. 8. Print a one-line confirmation: `tenbackward: starting cron (RUN_AT=..., TZ=...)`. 9. `exec cron -f`. # Output Files | Path | Owner / Mode | Purpose | |------------------------------|--------------|------------------------------------------------------| | `/etc/cron.d/tenbackward` | root / 0644 | The rendered cron file. | | `/app/data/cron.log` | container user / append | `python -m tenbackward` stdout+stderr. | | `/app/data/posted.json` | container user / rw | Persisted state from `tenbackward.state`. | # Cron Helpers | File | Purpose | |---------------------------------|------------------------------------------------------------------------| | `crontab/tenbackward.cron` | Static template (env + PATH) shipped in the image. | | `crontab/install-cron.sh` | Validates and installs a rendered cron file with mode 0644. | # Operator Recipes * **Trigger a manual run** without waiting for the cron tick: ```bash docker compose exec tenbackward /usr/local/bin/python -m tenbackward ``` * **Inspect the rendered cron file** (the file the container actually installed): ```bash docker compose exec tenbackward cat /etc/cron.d/tenbackward ``` * **Tail the structured logs** produced by the bot: ```bash docker compose exec tenbackward tail -n 100 /app/data/cron.log ``` Expect one JSON object per line (`startup`, optional `run_complete`, or `pipeline_error` / `pipeline_failed`). # Build Script Notes `build.sh` now `cd`s into its own script directory (so it works no matter where it is invoked from) and, when possible, symlinks itself to `/usr/local/bin/build.sh` so the build can also be run as a plain `build.sh` command inside the build context. The symlink is a best-effort `|| true`, so a read-only filesystem will not break the build. # Related * [Environment Variable Setup](/operations/environment-setup.md) * [Pipeline Runner](/architecture/pipeline-runner.md) * [Logging & Run Summary](/architecture/logging.md)