feat: execute durable archive transfers
This commit is contained in:
@@ -268,6 +268,113 @@ class ClientStore:
|
||||
).fetchall()
|
||||
return [dict(row) for row in rows]
|
||||
|
||||
def record_job_event(
|
||||
self,
|
||||
*,
|
||||
job_id: str,
|
||||
definition_json: str,
|
||||
event_id: str,
|
||||
event_json: str,
|
||||
state: str,
|
||||
revision: int,
|
||||
sequence: int,
|
||||
committed: bool,
|
||||
) -> dict[str, object]:
|
||||
definition = _canonical(json.loads(definition_json))
|
||||
event = _canonical(json.loads(event_json))
|
||||
with self._connect() as connection:
|
||||
connection.execute("BEGIN IMMEDIATE")
|
||||
existing_event = connection.execute(
|
||||
"""
|
||||
SELECT job_id, sequence, event_json
|
||||
FROM events WHERE event_id = ?
|
||||
""",
|
||||
(event_id,),
|
||||
).fetchone()
|
||||
if existing_event:
|
||||
if (
|
||||
existing_event["job_id"] != job_id
|
||||
or existing_event["sequence"] != sequence
|
||||
or existing_event["event_json"] != event
|
||||
):
|
||||
raise JobConflict(
|
||||
"job event ID was reused with different content"
|
||||
)
|
||||
return dict(existing_event)
|
||||
existing_sequence = connection.execute(
|
||||
"""
|
||||
SELECT event_id, event_json FROM events
|
||||
WHERE job_id = ? AND sequence = ?
|
||||
""",
|
||||
(job_id, sequence),
|
||||
).fetchone()
|
||||
if existing_sequence:
|
||||
if existing_sequence["event_json"] != event:
|
||||
raise JobConflict(
|
||||
"job event sequence has conflicting content"
|
||||
)
|
||||
return dict(existing_sequence)
|
||||
job = connection.execute(
|
||||
"""
|
||||
SELECT definition_json, revision, last_event_sequence,
|
||||
committed
|
||||
FROM jobs WHERE job_id = ?
|
||||
""",
|
||||
(job_id,),
|
||||
).fetchone()
|
||||
if job and job["definition_json"] != definition:
|
||||
raise JobConflict("job definition is immutable")
|
||||
if job and (
|
||||
revision < job["revision"]
|
||||
or sequence <= job["last_event_sequence"]
|
||||
or (job["committed"] and not committed)
|
||||
):
|
||||
raise JobConflict("job event cursor cannot move backwards")
|
||||
connection.execute(
|
||||
"""
|
||||
INSERT INTO jobs (
|
||||
job_id, definition_json, state, revision,
|
||||
last_event_sequence, committed
|
||||
) VALUES (?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(job_id) DO UPDATE SET
|
||||
state = excluded.state,
|
||||
revision = excluded.revision,
|
||||
last_event_sequence = excluded.last_event_sequence,
|
||||
committed = excluded.committed
|
||||
""",
|
||||
(
|
||||
job_id, definition, state, revision, sequence,
|
||||
int(committed),
|
||||
),
|
||||
)
|
||||
connection.execute(
|
||||
"""
|
||||
INSERT INTO events (
|
||||
event_id, job_id, sequence, event_json
|
||||
) VALUES (?, ?, ?, ?)
|
||||
""",
|
||||
(event_id, job_id, sequence, event),
|
||||
)
|
||||
row = connection.execute(
|
||||
"SELECT * FROM events WHERE event_id = ?", (event_id,)
|
||||
).fetchone()
|
||||
return dict(row)
|
||||
|
||||
def job_event_rows(
|
||||
self, job_id: str, after_sequence: int = 0
|
||||
) -> list[dict[str, object]]:
|
||||
with self._connect() as connection:
|
||||
rows = connection.execute(
|
||||
"""
|
||||
SELECT event_id, job_id, sequence, event_json
|
||||
FROM events
|
||||
WHERE job_id = ? AND sequence > ?
|
||||
ORDER BY sequence
|
||||
""",
|
||||
(job_id, after_sequence),
|
||||
).fetchall()
|
||||
return [dict(row) for row in rows]
|
||||
|
||||
def begin_route_attempt(
|
||||
self,
|
||||
command_id: str,
|
||||
|
||||
Reference in New Issue
Block a user