Shift Planner Jobs

Scheduler modul pro automaticke vyhodnoceni zamykani smen.

Co dela

  • scheduler spousti job auto_shift_lock.py podle AUTO_SHIFT_LOCK_CRON v conf/shift-planner-jobs.conf
  • job vyhodnocuje interval dnes .. dnes+N dni pro vsechny sklady (AUTO_SHIFT_LOCK_LOOKAHEAD_DAYS v conf/shift-planner-jobs.conf, default 30)
  • auto-lock je povolen pouze tam, kde sp-shift-lock-YYYY-MM.csv obsahuje auto_shift_lock_enabled = 1 (chybne/chybejici zaznamy se berou jako 1)
  • "cerveny den" odpovida UI logice: planned_hours > expected_hours + 100
  • pokud selze nacitani vstupnich dat (API/DB), cele kolo vyhodnoceni se preskoci (AUTO_SHIFT_LOCK_ROUND_SKIPPED)
  • pokud je expected_hours <= 0, den se nikdy nevyhodnoti jako kandidat na lock (AUTO_SHIFT_LOCK_SKIP reason=expected_hours_non_positive)
  • v DRY-RUN modu (AUTO_SHIFT_LOCK_DRY_RUN=1) nic nezamyka, pouze loguje kandidaty na zamknuti (AUTO_SHIFT_LOCK_DRY_RUN)
  • v LIVE modu (AUTO_SHIFT_LOCK_DRY_RUN=0) opravdu vola lock API a zamyka smeny (AUTO_SHIFT_LOCK_LIVE)
  • po uspesnem LIVE zamceni umi poslat WAHA notifikaci do skupiny (AUTO_SHIFT_LOCK_NOTIFY_* + AUTO_SHIFT_LOCK_WAHA_* v conf/shift-planner-jobs.conf)
  • bezi v Docker kontejneru pres supercronic
  • script pise pouze do stdout
  • entrypoint.sh smeruje stdout/stderr hlavniho procesu kontejneru do LOG_FILE
  • healthcheck je heartbeat-based, ne HTTP endpoint
  • runtime conf mount: /home/agent/shift-planner/conf -> /app/conf
  • produkcni shift-planner-jobs.conf v /home/agent/shift-planner/conf je server-managed runtime konfigurace; deploy ji neprepisuje
  • planned_hours API pouziva PLANNED_HOURS_METHOD=POST a bere Basic auth z PLANNED_HOURS_AUTH v conf/shift-planner-jobs.conf
  • expected_hours a shift locks z CME DB vyzaduji /app/data/cme-db.ini

Scheduler

  • AUTO_SHIFT_LOCK_CRON v conf/shift-planner-jobs.conf
  • vychozi hodnota * * * * * -> beh kazdou minutu

Log file

  • default: /app/logs/shift-planner-jobs.log
  • v produkci pres mount: /home/agent/shift-planner/logs/shift-planner-jobs.log
  • v DEV: ../target/logs/shift-planner-jobs.log
  • rotace po 100 MB na shift-planner-jobs.0001.log, shift-planner-jobs.0002.log, ...
  • dulezite log radky:
  • AUTO_SHIFT_LOCK_ROUND_SKIPPED ... -> kolo vyhodnoceni bylo preskoceno kvuli chybe nacitani dat
  • AUTO_SHIFT_LOCK_SKIP reason=expected_hours_non_positive ... -> den ma nulovy/neplatny expected a nebude zamknut
  • AUTO_SHIFT_LOCK_DRY_RUN ... -> smeny, ktere by se zamkly
  • AUTO_SHIFT_LOCK_NOTIFY_DRY_RUN ... -> text WAHA notifikace, ktery by se v live poslal
  • AUTO_SHIFT_LOCK_LIVE ... -> smeny, ktere byly realne zamceny
  • AUTO_SHIFT_LOCK_LIVE_FAILED ... -> pokus o zamceni selhal
  • AUTO_SHIFT_LOCK_NOTIFY_SENT ... -> WAHA notifikace byla odeslana
  • AUTO_SHIFT_LOCK_NOTIFY_FAILED ... -> WAHA notifikaci se nepodarilo odeslat
  • AUTO_SHIFT_LOCK_RESULT ... -> souhrn behu

Monitoring

  • kontejner ma restart: unless-stopped
  • compose healthcheck cte heartbeat stav ze souboru HEALTH_STATUS_FILE
  • scheduler zapise bootstrap health stav hned pri startu kontejneru, aby sluzba nezustavala dlouho ve stavu starting
  • nove kolo scheduleru zapise heartbeat hned na zacatku behu (status=running)
  • healthy healthcheck znamena, ze scheduler stale zije a heartbeat neni zastaraly
  • interní status ok znamena, ze posledni beh probehl bez provozni chyby
  • interní status degraded znamena, ze scheduler bezi, ale posledni kolo bylo preskoceno kvuli zavislosti nebo konfiguraci
  • interní status running znamena, ze kolo prave bezi
  • unhealthy healthcheck znamena typicky:
  • fatalni pád jobu (fatal_error)
  • nevalidni chybejici heartbeat soubor
  • zastaraly heartbeat
  • vychozi HEALTH_MAX_AGE_SECONDS je 3600; pokud pouzijete jeste ridsi cron, upravte ho vys

WAHA notifikace po zamceni

Konfigurace je v conf/shift-planner-jobs.conf:

  • AUTO_SHIFT_LOCK_WAHA_BASE_URL - WAHA base URL (napr. https://waha.mathbox.90.cz)
  • AUTO_SHIFT_LOCK_WAHA_API_KEY - API key pro WAHA (X-Api-Key)
  • AUTO_SHIFT_LOCK_WAHA_SESSION - WAHA session (default)
  • AUTO_SHIFT_LOCK_NOTIFY_GROUP_CHAT_ID - cilova WhatsApp skupina (...@g.us)
  • AUTO_SHIFT_LOCK_NOTIFY_TEMPLATE - text zpravy
  • AUTO_SHIFT_LOCK_NOTIFY_TIMEOUT_SECONDS - HTTP timeout

Poznamky:

  • v LIVE rezimu bez AUTO_SHIFT_LOCK_NOTIFY_GROUP_CHAT_ID se zamykani provede, ale notifikace se neposle (AUTO_SHIFT_LOCK_NOTIFY_DISABLED reason=missing_config).
  • v pouzite WAHA edici nelze API key vytvaret v dashboardu; klic se nastavuje mimo dashboard.

Vychozi sablona:

Směny na den {} ve skladu {} byly zamčeny, protože počet hodin registrovaných brigádníků {} přesáhl o 100 počet hodin, které na směnu odhadujeme {}.

Placeholdery pro AUTO_SHIFT_LOCK_NOTIFY_TEMPLATE:

  • {} #1 = business date (YYYY-MM-DD)
  • {} #2 = warehouse name
  • {} #3 = planned (registered) hours
  • {} #4 = expected hours
  • named placeholders: {shift}, {business_date}, {warehouse_name}, {warehouse_id}, {cme_id}, {planovac_den_id}, {planned_hours}, {expected_hours}, {threshold_hours}, {buffer_hours}

Lokalni spusteni

./scripts/start-shift-planner-jobs.sh

Explicitne dry-run:

./scripts/start-shift-planner-jobs.sh --dry-run

Live rezim (ostry beh):

./scripts/start-shift-planner-jobs.sh --live

Okamzite testovaci spusteni:

./scripts/run-shift-planner-jobs-now.sh

Okamzite ostre spusteni:

./scripts/run-shift-planner-jobs-now.sh --live

Stop:

./scripts/stop-shift-planner-jobs.sh

Po spusteni scheduleru muzete log sledovat napr.:

tail -f target/logs/shift-planner-jobs.log

WAHA test (group id + send)

Test utility script:

python shift-planner-jobs/jobs/nudge/waha_group_test.py --help

List all WhatsApp groups for session default:

python shift-planner-jobs/jobs/nudge/waha_group_test.py groups

List groups filtered by name:

python shift-planner-jobs/jobs/nudge/waha_group_test.py groups --name "Sklad"

Send test message by exact chatId:

python shift-planner-jobs/jobs/nudge/waha_group_test.py send \
  --chat-id "1203630XXXXXXXXX@g.us" \
  --text "Test zprava ze shift-planner-jobs"

Send test message by group name (script first resolves group id):

python shift-planner-jobs/jobs/nudge/waha_group_test.py send \
  --group-name "Sklad" \
  --text "Test zprava ze shift-planner-jobs"

Send test message with user mention:

python shift-planner-jobs/jobs/nudge/waha_group_test.py send \
  --group-name "Testovaci" \
  --text "Ahoj @420123456789" \
  --mention "+420123456789"

If WAHA requires auth, set API key:

export WAHA_API_KEY="..."

Script defaultne pouziva serverovou WAHA URL:

python shift-planner-jobs/jobs/nudge/waha_group_test.py \
  --base-url "https://waha.mathbox.90.cz" \
  groups

Troubleshooting

  • AUTO_SHIFT_LOCK_NOTIFY_DISABLED reason=missing_config missing_fields=group_chat_id znamena chybejici AUTO_SHIFT_LOCK_NOTIFY_GROUP_CHAT_ID v conf/shift-planner-jobs.conf.
  • Pokud je AUTO_SHIFT_LOCK_LIVE action=lock a neni AUTO_SHIFT_LOCK_NOTIFY_SENT, hledej AUTO_SHIFT_LOCK_NOTIFY_FAILED (WAHA auth, session, URL, timeout).
  • Pokud je candidate_count=0, smerodatny je souhrn v AUTO_SHIFT_LOCK_SCAN_FINISHED (over_capacity_slots, already_locked_slots, lock_candidates, expected_hours_non_positive_slots).
  • Pokud je AUTO_SHIFT_LOCK_ROUND_SKIPPED, v tom behu se nic nezamyka (ochrana proti lockum s nekompletnimi daty).

Shift lock API test

Lock/unlock shift via API (uses X-API-KEY; Basic auth optional):

./shift-planner-jobs/jobs/nudge/lock_shift.py 8878 true --x-api-key "xxx"
./shift-planner-jobs/jobs/nudge/lock_shift.py 8878 false --x-api-key "xxx"

Print outgoing HTTP request (headers + body):

./shift-planner-jobs/jobs/nudge/lock_shift.py 8878 true --x-api-key "xxx" --debug-request