fix(v2-scheduler): avoid restart loops when scheduler is disabled
This commit is contained in:
@ -59,6 +59,8 @@ DAILY_ORCHESTRATION_INTERVAL_SECONDS=86400
|
||||
# Future optional scheduler loop settings (not enabled in base v2 runtime)
|
||||
SCHEDULER_ENABLED=0
|
||||
SCHEDULER_INTERVAL_SECONDS=900
|
||||
# When scheduler is disabled but container is started, keep it idle (avoid restart loops)
|
||||
SCHEDULER_DISABLED_SLEEP_SECONDS=300
|
||||
|
||||
# API safeguards (read-only API is optional)
|
||||
API_THROTTLE_ANON=100/hour
|
||||
|
||||
@ -282,6 +282,7 @@ Notes:
|
||||
- image: `registry.younerd.org/hoopscout/scheduler:${APP_IMAGE_TAG:-latest}`
|
||||
- command: `/app/scripts/scheduler.sh`
|
||||
- interval: `DAILY_ORCHESTRATION_INTERVAL_SECONDS`
|
||||
- disabled idle interval: `SCHEDULER_DISABLED_SLEEP_SECONDS`
|
||||
|
||||
### Scheduler entrypoint/runtime expectations
|
||||
|
||||
@ -290,6 +291,7 @@ Notes:
|
||||
- scheduler is disabled unless:
|
||||
- compose `scheduler` profile is started
|
||||
- `SCHEDULER_ENABLED=1`
|
||||
- if scheduler service is started while disabled (`SCHEDULER_ENABLED=0`), it does not exit; it enters idle sleep mode to avoid restart loops with `restart: unless-stopped`
|
||||
- this keeps default runtime simple while supporting daily automation
|
||||
|
||||
### LBA extractor assumptions and limitations (MVP)
|
||||
|
||||
@ -75,6 +75,10 @@ services:
|
||||
dockerfile: Dockerfile
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
SCHEDULER_ENABLED: ${SCHEDULER_ENABLED:-0}
|
||||
SCHEDULER_DISABLED_SLEEP_SECONDS: ${SCHEDULER_DISABLED_SLEEP_SECONDS:-300}
|
||||
DAILY_ORCHESTRATION_INTERVAL_SECONDS: ${DAILY_ORCHESTRATION_INTERVAL_SECONDS:-86400}
|
||||
command: /app/scripts/scheduler.sh
|
||||
depends_on:
|
||||
postgres:
|
||||
|
||||
@ -2,8 +2,16 @@
|
||||
set -e
|
||||
|
||||
if [ "${SCHEDULER_ENABLED:-0}" != "1" ]; then
|
||||
echo "Scheduler disabled (SCHEDULER_ENABLED=${SCHEDULER_ENABLED:-0}). Exiting."
|
||||
exit 0
|
||||
DISABLED_SLEEP="${SCHEDULER_DISABLED_SLEEP_SECONDS:-300}"
|
||||
if [ "${DISABLED_SLEEP}" -lt 30 ]; then
|
||||
echo "SCHEDULER_DISABLED_SLEEP_SECONDS must be >= 30"
|
||||
exit 1
|
||||
fi
|
||||
echo "Scheduler disabled (SCHEDULER_ENABLED=${SCHEDULER_ENABLED:-0}). Entering idle mode with ${DISABLED_SLEEP}s sleep."
|
||||
while true; do
|
||||
echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] Scheduler disabled; sleeping for ${DISABLED_SLEEP}s."
|
||||
sleep "${DISABLED_SLEEP}"
|
||||
done
|
||||
fi
|
||||
|
||||
INTERVAL="${DAILY_ORCHESTRATION_INTERVAL_SECONDS:-${SCHEDULER_INTERVAL_SECONDS:-86400}}"
|
||||
|
||||
43
tests/test_scheduler_operational_safety.py
Normal file
43
tests/test_scheduler_operational_safety.py
Normal file
@ -0,0 +1,43 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _repo_root() -> Path:
|
||||
return Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
def test_scheduler_disabled_mode_stays_alive_without_exit_loop():
|
||||
env = os.environ.copy()
|
||||
env["SCHEDULER_ENABLED"] = "0"
|
||||
env["SCHEDULER_DISABLED_SLEEP_SECONDS"] = "30"
|
||||
|
||||
process = subprocess.Popen(
|
||||
["sh", "scripts/scheduler.sh"],
|
||||
cwd=_repo_root(),
|
||||
env=env,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
)
|
||||
try:
|
||||
time.sleep(1.0)
|
||||
assert process.poll() is None
|
||||
finally:
|
||||
process.terminate()
|
||||
process.wait(timeout=5)
|
||||
|
||||
|
||||
def test_scheduler_compose_service_is_profile_gated():
|
||||
compose_text = (_repo_root() / "docker-compose.yml").read_text(encoding="utf-8")
|
||||
assert 'profiles: ["scheduler"]' in compose_text
|
||||
assert "restart: unless-stopped" in compose_text
|
||||
|
||||
|
||||
def test_scheduler_script_declares_idle_disabled_behavior():
|
||||
scheduler_script = (_repo_root() / "scripts/scheduler.sh").read_text(encoding="utf-8")
|
||||
assert "Entering idle mode" in scheduler_script
|
||||
assert "SCHEDULER_DISABLED_SLEEP_SECONDS" in scheduler_script
|
||||
Reference in New Issue
Block a user