Add worker delivery acceptance probe

This commit is contained in:
2026-08-03 00:20:51 +02:00
parent 435b924fd9
commit 21c1fa49b6
4 changed files with 113 additions and 2 deletions
+72
View File
@@ -4,6 +4,7 @@ from datetime import datetime, timedelta, timezone
from importlib.metadata import PackageNotFoundError, version
import logging
import os
import time
from celery import Celery
from celery.signals import (
@@ -110,6 +111,14 @@ celery.conf.update(
worker_prefetch_multiplier=1,
task_acks_late=True,
task_reject_on_worker_lost=True,
task_track_started=True,
broker_transport_options={
"visibility_timeout": settings.celery_visibility_timeout_seconds,
},
result_backend_transport_options={
"visibility_timeout": settings.celery_visibility_timeout_seconds,
},
visibility_timeout=settings.celery_visibility_timeout_seconds,
beat_schedule={
"calendar-outbox-every-minute": {
"task": "govoplan.calendar.dispatch_outbox",
@@ -308,6 +317,69 @@ def ping():
return "pong"
@celery.task(
bind=True,
name="govoplan.worker.acceptance",
max_retries=1,
acks_late=True,
reject_on_worker_lost=True,
track_started=True,
)
def worker_acceptance_probe(
task,
probe_id: str,
*,
mode: str = "complete",
delay_seconds: float = 0.0,
track_delivery: bool = False,
):
"""Exercise broker delivery semantics without touching business data."""
if mode not in {"complete", "retry_once"}:
raise ValueError(f"Unsupported worker acceptance mode: {mode}")
normalized_probe_id = str(probe_id).strip()
if not normalized_probe_id or len(normalized_probe_id) > 120:
raise ValueError("Worker acceptance probe_id must contain 1-120 characters")
bounded_delay = max(0.0, min(float(delay_seconds), 120.0))
delivery_count = _worker_acceptance_delivery_count(
task,
normalized_probe_id,
) if track_delivery else None
task.update_state(
state="PROGRESS",
meta={
"phase": "started",
"probe_id": normalized_probe_id,
"retries": int(task.request.retries or 0),
"delivery_count": delivery_count,
},
)
if mode == "retry_once" and int(task.request.retries or 0) == 0:
raise task.retry(countdown=0.2)
if bounded_delay:
time.sleep(bounded_delay)
delivery_info = task.request.delivery_info or {}
return {
"probe_id": normalized_probe_id,
"mode": mode,
"retries": int(task.request.retries or 0),
"redelivered": bool(delivery_info.get("redelivered")),
"delivery_count": delivery_count,
}
def _worker_acceptance_delivery_count(task, probe_id: str) -> int:
client = getattr(task.backend, "client", None)
if client is None:
raise RuntimeError(
"Worker acceptance delivery tracking requires a Redis result backend"
)
key = f"govoplan:worker-acceptance:{probe_id}"
count = int(client.incr(key))
client.expire(key, 60 * 60)
return count
def _platform_registry() -> PlatformRegistry:
raw_enabled_modules = load_startup_enabled_modules(settings.enabled_modules)
candidate_modules = startup_candidate_module_ids(
+6
View File
@@ -115,6 +115,12 @@ class Settings(BaseSettings):
migration_track: str = Field(default="release", alias="GOVOPLAN_MIGRATION_TRACK")
redis_url: str = Field(default="redis://redis:6379/0", alias="REDIS_URL")
celery_enabled: bool = Field(default=False, alias="CELERY_ENABLED")
celery_visibility_timeout_seconds: int = Field(
default=3600,
ge=30,
le=7 * 24 * 60 * 60,
alias="CELERY_VISIBILITY_TIMEOUT_SECONDS",
)
s3_endpoint_url: str = Field(default="http://garage:3900", alias="S3_ENDPOINT_URL")
s3_region: str = Field(default="garage", alias="S3_REGION")