fix: publish schedules after creation watermark
This commit is contained in:
+13
-4
@@ -21,7 +21,7 @@ from wf_scheduling.history import FileScheduleHistoryRecorder, HistoryEntry
|
||||
from wf_scheduling.models import OccurrenceRecord, Schedule
|
||||
from wf_scheduling.occurrences import occurrence_id
|
||||
from wf_scheduling.prepare import PreparationRejected, SchedulePreparer
|
||||
from wf_scheduling.store import StaleScheduleRevisionError
|
||||
from wf_scheduling.store import ScheduleExistsError, StaleScheduleRevisionError
|
||||
|
||||
from .models import (
|
||||
JsonProjector,
|
||||
@@ -207,11 +207,20 @@ class WorkflowScheduleApi:
|
||||
}
|
||||
)
|
||||
self._validate_definition(schedule)
|
||||
stored = store.create_schedule(schedule)
|
||||
# Creation never backfills time before the revision: the consumed
|
||||
# watermark starts at creation so catch-up only ever covers
|
||||
# downtime after this revision, never pre-creation instants.
|
||||
# watermark starts at creation so catch-up only ever covers downtime
|
||||
# after this revision, never pre-creation instants. Check the id
|
||||
# before this write so a duplicate create cannot overwrite the
|
||||
# existing schedule's watermark; publishing the schedule last keeps
|
||||
# a failed watermark write invisible to the poller.
|
||||
try:
|
||||
store.get_schedule(schedule_id)
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
raise ScheduleExistsError(f"schedule id already exists: {schedule_id!r}")
|
||||
store.save_consumed(schedule_id, now)
|
||||
stored = store.create_schedule(schedule)
|
||||
return _PROJECT_SCHEDULE(stored.model_dump(mode="json"))
|
||||
|
||||
async def get_schedule(self, *, schedule_id: str) -> ScheduleResult:
|
||||
|
||||
@@ -528,6 +528,26 @@ async def test_create_initializes_consumed_no_backfill(tmp_path: Path) -> None:
|
||||
assert consumed is not None and consumed >= created_at
|
||||
|
||||
|
||||
async def test_create_watermark_failure_does_not_publish_schedule(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
"""A failed creation watermark cannot expose a backfillable schedule."""
|
||||
api, sched_store, _ = _fault_harness(tmp_path / "torn_create")
|
||||
sched_store.armed = True
|
||||
|
||||
with pytest.raises(OSError, match="injected consumed failure"):
|
||||
await api.create_schedule(
|
||||
schedule_id="s",
|
||||
deployment_id="dep.personal",
|
||||
trigger=_cron(),
|
||||
misfire="latest",
|
||||
)
|
||||
|
||||
with pytest.raises(KeyError):
|
||||
sched_store.get_schedule("s")
|
||||
assert sched_store.get_consumed("s") is None
|
||||
|
||||
|
||||
async def test_update_watermark_failure_leaves_revision(tmp_path: Path) -> None:
|
||||
api, sched_store, _ = _fault_harness(tmp_path / "torn_update")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user