feat: empty CRON_SCHEDULE keeps container alive for manual docker exec
Three container lifetime modes via CRON_SCHEDULE: unset — run once on startup, exit empty string — sleep infinity; use docker exec -it winnow winnow cron expression — run on startup, then on schedule This replaces the need for a separate MANUAL_MODE env var. The empty string is a natural "I want the container alive but unscheduled" signal. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -148,7 +148,15 @@ See [compose.yml](compose.yml) for the full annotated example.
|
|||||||
|
|
||||||
### Scheduling Behaviour
|
### Scheduling Behaviour
|
||||||
|
|
||||||
On startup the container always runs once immediately. If `CRON_SCHEDULE` is set, it then starts a scheduler that fires on the defined interval, keeping the process (and loaded models) alive between runs. Without `CRON_SCHEDULE` the container exits after the first run.
|
`CRON_SCHEDULE` controls container lifetime:
|
||||||
|
|
||||||
|
| `CRON_SCHEDULE` value | Behaviour |
|
||||||
|
| :-- | :-- |
|
||||||
|
| *(unset)* | Run once on startup, then exit |
|
||||||
|
| *(empty string)* | Stay alive, run nothing — trigger manually with `docker exec -it winnow winnow` |
|
||||||
|
| Cron expression | Run on startup, then repeat on schedule |
|
||||||
|
|
||||||
|
In scheduled mode the process (and loaded models) stays resident between runs. In manual mode the container idles indefinitely with `sleep infinity` — useful when you want to trigger runs interactively on demand without pulling a new container each time.
|
||||||
|
|
||||||
The first run after a fresh install downloads the embedding models (~1-2 GB). Subsequent runs use the cached models from the mounted volume and start immediately.
|
The first run after a fresh install downloads the embedding models (~1-2 GB). Subsequent runs use the cached models from the mounted volume and start immediately.
|
||||||
|
|
||||||
@@ -217,7 +225,7 @@ The first run after a fresh install downloads the embedding models (~1-2 GB). Su
|
|||||||
|
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
| :--- | :--- | :--- |
|
| :--- | :--- | :--- |
|
||||||
| `CRON_SCHEDULE` | *(unset)* | Cron expression for recurring runs — unset exits after first run |
|
| `CRON_SCHEDULE` | *(unset)* | Unset = run once and exit; empty = stay alive for manual `docker exec`; cron expression = scheduled |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -48,10 +48,14 @@ services:
|
|||||||
# - RESET_PERSON=John # Clear uploaded+rejected history for one person
|
# - RESET_PERSON=John # Clear uploaded+rejected history for one person
|
||||||
|
|
||||||
# ── Scheduling ────────────────────────────────────────────────────────
|
# ── Scheduling ────────────────────────────────────────────────────────
|
||||||
# Cron expression (unset = run once and exit)
|
# CRON_SCHEDULE controls container lifetime:
|
||||||
|
# unset — run once on startup, then exit
|
||||||
|
# empty string — stay alive, run nothing; trigger manually with:
|
||||||
|
# docker exec -it winnow winnow
|
||||||
|
# cron expression — run on startup, then on schedule
|
||||||
|
# - CRON_SCHEDULE= # Manual mode (keep alive, no auto-run)
|
||||||
# - CRON_SCHEDULE=0 3 * * 0 # Every Sunday at 3 AM
|
# - CRON_SCHEDULE=0 3 * * 0 # Every Sunday at 3 AM
|
||||||
# - CRON_SCHEDULE=0 3 1 * * # First of every month
|
# - CRON_SCHEDULE=0 3 1 * * # First of every month
|
||||||
# - CRON_SCHEDULE=*/30 * * * * # Every 30 minutes
|
|
||||||
volumes:
|
volumes:
|
||||||
# Replace with absolute paths on your host, e.g. /opt/winnow/models
|
# Replace with absolute paths on your host, e.g. /opt/winnow/models
|
||||||
- /path/to/winnow/models:/models
|
- /path/to/winnow/models:/models
|
||||||
|
|||||||
+10
-3
@@ -2,11 +2,19 @@
|
|||||||
set -e
|
set -e
|
||||||
export PYTHONUNBUFFERED=1
|
export PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
# 1. Run the job immediately on startup
|
# CRON_SCHEDULE controls container lifetime:
|
||||||
|
# unset — run once and exit
|
||||||
|
# empty string — stay alive, run nothing (use: docker exec -it winnow winnow)
|
||||||
|
# cron expression — run immediately, then on schedule
|
||||||
|
|
||||||
|
if [ "${CRON_SCHEDULE+isset}" = "isset" ] && [ -z "$CRON_SCHEDULE" ]; then
|
||||||
|
echo "▶ CRON_SCHEDULE is empty — manual mode. Use 'docker exec -it winnow winnow' to run."
|
||||||
|
exec sleep infinity
|
||||||
|
fi
|
||||||
|
|
||||||
echo "▶ Running on startup..."
|
echo "▶ Running on startup..."
|
||||||
/app/.venv/bin/winnow
|
/app/.venv/bin/winnow
|
||||||
|
|
||||||
# 2. If a schedule exists, start the scheduler
|
|
||||||
if [ -n "${CRON_SCHEDULE:-}" ]; then
|
if [ -n "${CRON_SCHEDULE:-}" ]; then
|
||||||
echo "▶ CRON_SCHEDULE set to: $CRON_SCHEDULE"
|
echo "▶ CRON_SCHEDULE set to: $CRON_SCHEDULE"
|
||||||
echo "▶ Switching to scheduled mode..."
|
echo "▶ Switching to scheduled mode..."
|
||||||
@@ -14,4 +22,3 @@ if [ -n "${CRON_SCHEDULE:-}" ]; then
|
|||||||
else
|
else
|
||||||
echo "▶ No schedule set, exiting."
|
echo "▶ No schedule set, exiting."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user