Add durable external-effect runtime identity

This commit is contained in:
2026-08-03 03:47:41 +02:00
parent 6c2940aebc
commit 01f91154e0
9 changed files with 186 additions and 7 deletions
+13
View File
@@ -4377,6 +4377,7 @@ class ApiSmokeTests(unittest.TestCase):
with SessionLocal() as session:
job = session.query(CampaignJob).filter(CampaignJob.campaign_version_id == version_id).one()
job_id = job.id
generated_eml = self._stored_campaign_eml(job)
sent = self.client.post(
@@ -4398,6 +4399,18 @@ class ApiSmokeTests(unittest.TestCase):
self.assertTrue(raw_filename)
captured_eml = (_TEST_ROOT / "mock-mailbox" / "messages" / str(raw_filename)).read_bytes()
self.assertEqual(captured_eml, generated_eml)
with SessionLocal() as session:
operation = (
session.query(RecoveryOperation)
.filter(
RecoveryOperation.operation_type
== "external-channel-delivery",
RecoveryOperation.resource_id == job_id,
)
.one()
)
self.assertEqual(operation.status, RecoveryStatus.SUCCEEDED.value)
self.assertTrue(verify_recovery_evidence_chain(session, operation.id))
def test_send_now_rejects_modified_generated_eml_before_delivery(self) -> None:
headers, _ = self._login()
+23
View File
@@ -115,6 +115,29 @@ def test_same_fence_cannot_start_duplicate_running_operation() -> None:
engine.dispose()
def test_verified_provider_rejection_is_terminal_without_recovery() -> None:
engine, factory = _fixture()
try:
started = _start(factory, _identity("worker-1", "incarnation-1"))
assert started.operation is not None
started.operation.reject(
summary="Provider definitively rejected the request",
evidence={
"verified": True,
"provider_outcome": "rejected",
"checks": {"provider_response": "definitive-rejection"},
},
)
with factory() as session:
operation = session.get(RecoveryOperation, started.operation_id)
assert operation is not None
assert operation.status == RecoveryStatus.REJECTED.value
assert operation.completed_at is not None
assert verify_recovery_evidence_chain(session, operation.id)
finally:
engine.dispose()
def test_other_runtime_cannot_use_an_active_fence() -> None:
engine, factory = _fixture()
try:
+54 -3
View File
@@ -6,6 +6,8 @@ from types import SimpleNamespace
from govoplan_core.core.runtime_coordination import (
RuntimeCoordinationError,
RuntimeIdentity,
bind_process_runtime_identity,
process_runtime_identity,
)
from govoplan_core.server.runtime_agent import RuntimeNodeAgent
@@ -64,6 +66,32 @@ def test_api_runtime_agent_fails_readiness_on_heartbeat_error() -> None:
assert agent.coordination_healthy is True
def test_process_runtime_identity_is_explicit_and_replaceable() -> None:
from govoplan_core.core import runtime_coordination
previous = runtime_coordination._process_runtime_identity
identity = RuntimeIdentity(
installation_id="installation-1",
node_id="api-1",
incarnation="incarnation-1",
role="api",
software_version="0.1.14",
composition_hash="a" * 64,
)
try:
bind_process_runtime_identity(None)
try:
process_runtime_identity()
except RuntimeCoordinationError:
pass
else: # pragma: no cover - assertion branch
raise AssertionError("An unbound process identity must fail closed")
bind_process_runtime_identity(identity)
assert process_runtime_identity() is identity
finally:
bind_process_runtime_identity(previous)
def test_worker_disables_consumers_without_reclaiming_stale_identity(
monkeypatch,
) -> None:
@@ -127,8 +155,19 @@ def test_worker_disables_consumers_without_reclaiming_stale_identity(
def test_worker_child_replaces_inherited_database_pool(monkeypatch) -> None:
from govoplan_core import celery_app
from govoplan_core.core import runtime_coordination
calls: list[tuple[str, bool]] = []
previous_process_identity = runtime_coordination._process_runtime_identity
previous_worker_identity = celery_app._worker_identity
inherited = RuntimeIdentity(
installation_id="installation-1",
node_id="parent-worker",
incarnation="parent-incarnation",
role="worker",
software_version="0.1.14",
composition_hash="a" * 64,
)
monkeypatch.setattr(
celery_app,
"configure_database",
@@ -136,7 +175,19 @@ def test_worker_child_replaces_inherited_database_pool(monkeypatch) -> None:
(url, dispose_previous)
),
)
try:
celery_app._worker_identity = inherited
bind_process_runtime_identity(inherited)
celery_app._reset_worker_process_database()
celery_app._reset_worker_process_database()
assert calls == [(celery_app.settings.database_url, True)]
assert calls == [(celery_app.settings.database_url, True)]
assert celery_app._worker_identity is None
try:
process_runtime_identity()
except RuntimeCoordinationError:
pass
else: # pragma: no cover - assertion branch
raise AssertionError("A worker child must discard inherited authority")
finally:
celery_app._worker_identity = previous_worker_identity
bind_process_runtime_identity(previous_process_identity)