Serialize concurrent datasource publications

This commit is contained in:
2026-08-04 12:48:37 +02:00
parent 067c8273b6
commit 4053543816
5 changed files with 117 additions and 4 deletions
+45 -1
View File
@@ -7,7 +7,7 @@ from collections.abc import Mapping, Sequence
from dataclasses import dataclass, replace
from typing import Any, cast
from sqlalchemy import exists, func, or_, select
from sqlalchemy import exists, func, or_, select, text
from sqlalchemy.orm import Session
from govoplan_core.audit.logging import audit_event
@@ -98,6 +98,12 @@ class SqlDatasourceProvider:
) -> DatasourcePublicationResult:
db, api_principal = _publication_context(session, principal)
prepared = _prepare_publication(request)
_lock_publication_identity(
db,
tenant_id=api_principal.tenant_id,
producer_module=prepared.producer_module,
idempotency_key=prepared.idempotency_key,
)
existing = _existing_publication_result(
db,
tenant_id=api_principal.tenant_id,
@@ -1649,6 +1655,44 @@ def _validate_publication_identity(
)
def _publication_lock_key(
*,
tenant_id: str,
producer_module: str,
idempotency_key: str,
) -> int:
payload = (
f"govoplan.datasources.publication\0{tenant_id}\0"
f"{producer_module}\0{idempotency_key}"
).encode("utf-8")
return int.from_bytes(
hashlib.sha256(payload).digest()[:8],
"big",
signed=True,
)
def _lock_publication_identity(
session: Session,
*,
tenant_id: str,
producer_module: str,
idempotency_key: str,
) -> None:
if session.get_bind().dialect.name != "postgresql":
return
session.execute(
text("SELECT pg_advisory_xact_lock(:key)"),
{
"key": _publication_lock_key(
tenant_id=tenant_id,
producer_module=producer_module,
idempotency_key=idempotency_key,
)
},
)
def _existing_publication_result(
session: Session,
*,