Files
comunidadhll/ai/tasks/done/TASK-092-single-writer-locking-for-automation-workers.md
2026-03-25 12:07:11 +01:00

3.4 KiB

TASK-092-single-writer-locking-for-automation-workers

Goal

Imponer una coordinacion de single-writer entre todos los procesos del backend que escriben sobre el mismo SQLite compartido, evitando colisiones entre automatizaciones y ejecuciones manuales y sustituyendo errores opacos de database is locked por una coordinacion controlada y mensajes claros.

Context

Actualmente pueden coincidir sobre el mismo volumen /app/data:

  • historical-runner
  • player_event_worker
  • rcon-historical-worker
  • ejecuciones manuales via docker compose exec backend ...

Aunque WAL y busy_timeout ayudan, no garantizan una operativa limpia si varios writers largos arrancan a la vez. Hace falta una politica de exclusion mutua a nivel de proceso/job, no solo a nivel SQLite.

Scope

Backend y orquestacion minima/documentacion. Sin cambios en frontend.

Desired Design

Implementar un unico lock compartido para todos los writers que tocan el mismo SQLite.

Ese lock debe:

  • vivir bajo el storage compartido en /app/data o una ruta derivada del storage_path
  • ser comun para:
    • app.historical_runner
    • app.historical_ingestion
    • app.player_event_worker
    • app.rcon_historical_worker
  • adquirirse al principio de cada run writer-oriented
  • liberarse siempre aunque haya excepcion
  • incluir metadata visible del holder:
    • proceso/comando
    • started_at
    • host/container si es viable
  • tener espera configurable con timeout y poll interval
  • fallar con error claro cuando no pueda adquirir el lock dentro del timeout
  • evitar dependencias nuevas si es posible

Steps

  1. Crear una utilidad comun de writer lock compartido para el backend.
  2. Aplicarla a:
    • historical_ingestion manual
    • historical_runner
    • player_event_worker
    • rcon_historical_worker
  3. Asegurarte de que el lock cubre la ejecucion writer-oriented completa, no solo una sentencia aislada.
  4. Exponer configuracion/env para:
    • lock timeout
    • poll interval
  5. Añadir mensajes de error/estado legibles cuando el lock este ocupado.
  6. Mantener las rutas HTTP read-only fuera de este lock.
  7. Actualizar docker-compose.yml solo si es necesario para dejar la operativa alineada.
  8. Actualizar backend/README.md con runbook claro:
    • que writers comparten lock
    • como hacer una pasada manual
    • que pasa si el lock esta ocupado
    • como convivir con automatizaciones sin parar contenedores salvo necesidad excepcional

Constraints

  • No tocar frontend.
  • No convertir esto en un rediseño total del scheduler.
  • No romper los workers ya existentes.
  • No bloquear las rutas HTTP de lectura.
  • No ampliar el alcance funcional del read model RCON.
  • Debe quedar claro que la solucion principal es single-writer coordination, no solo subir retries.

Validation

  • Existe un lock compartido real para los writers.
  • historical_runner, historical_ingestion, player_event_worker y rcon_historical_worker lo usan.
  • Si dos writers coinciden, no se produce un fallo opaco de SQLite; hay espera controlada o error claro de lock ocupado.
  • python -m compileall app pasa.
  • Las CLIs principales siguen respondiendo con --help.
  • La repo queda consistente.

Expected Files

  • uno o varios utilitarios nuevos bajo backend/app/
  • backend/app/historical_runner.py
  • backend/app/historical_ingestion.py
  • backend/app/player_event_worker.py
  • backend/app/rcon_historical_worker.py
  • docker-compose.yml si hace falta
  • backend/README.md