79 lines
2.7 KiB
Python
79 lines
2.7 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import signal
|
|
import socket
|
|
import uuid
|
|
|
|
from app.config import load_settings
|
|
from app.crm import CrmClient
|
|
from app.domain import full_jitter_delay
|
|
from app.engine import RetryableWorkflow, WorkflowEngine
|
|
from app.repository import Repository
|
|
|
|
|
|
async def worker_main() -> None:
|
|
settings = load_settings()
|
|
if not settings.enabled:
|
|
return
|
|
assert settings.database_url and settings.crm_rest_webhook_url and settings.portal_host
|
|
repository = Repository(settings.database_url.get_secret_value(), settings.db_pool_size)
|
|
crm = CrmClient(
|
|
settings.crm_rest_webhook_url.get_secret_value(),
|
|
settings.portal_host,
|
|
settings.http_timeout_sec,
|
|
)
|
|
engine = WorkflowEngine(repository, crm, settings)
|
|
stop = asyncio.Event()
|
|
loop = asyncio.get_running_loop()
|
|
for event in (signal.SIGINT, signal.SIGTERM):
|
|
try:
|
|
loop.add_signal_handler(event, stop.set)
|
|
except NotImplementedError:
|
|
pass
|
|
worker_id = f"{socket.gethostname()}:{uuid.uuid4()}"
|
|
try:
|
|
while not stop.is_set():
|
|
tasks = await repository.claim_tasks(
|
|
worker_id, settings.claim_size, settings.lease_seconds
|
|
)
|
|
webhooks = await repository.claim_webhooks(
|
|
worker_id, settings.claim_size, settings.lease_seconds
|
|
)
|
|
rebind_ids = await repository.pending_rebind_ids(settings.claim_size)
|
|
if not tasks and not webhooks and not rebind_ids:
|
|
try:
|
|
await asyncio.wait_for(stop.wait(), timeout=1)
|
|
except TimeoutError:
|
|
continue
|
|
for task in tasks:
|
|
if stop.is_set():
|
|
break
|
|
await engine.process(task)
|
|
for item in webhooks:
|
|
if stop.is_set():
|
|
break
|
|
try:
|
|
await engine.process_webhook(item)
|
|
except RetryableWorkflow as exc:
|
|
delay = exc.retry_after or full_jitter_delay(
|
|
item.attempt_count + 1,
|
|
settings.retry_base_seconds,
|
|
settings.retry_max_seconds,
|
|
)
|
|
await repository.retry_webhook(item, exc.code, delay)
|
|
for request_id in rebind_ids:
|
|
if stop.is_set():
|
|
break
|
|
try:
|
|
await engine.process_rebind(request_id)
|
|
except RetryableWorkflow:
|
|
continue
|
|
finally:
|
|
await crm.close()
|
|
await repository.close()
|
|
|
|
|
|
def run() -> None:
|
|
asyncio.run(worker_main())
|