Implement authorized live event replay

This commit is contained in:
ms2k 2026-07-17 23:08:28 +09:00
commit 06a7ac56b7

View file

@ -183,6 +183,12 @@ impl DeletionService {
json!({ "job_id": job_id, "deletion_operation_id": operation_id }),
)
.await?;
enqueue(
tx,
"deletion.updated",
json!({ "job_id": job_id, "operation_id": operation_id }),
)
.await?;
let operation = load_operation_in_tx(tx, operation_id.as_str()).await?;
Ok(HardDeleteOutcome {
mutation: LifecycleMutation::Changed,
@ -224,6 +230,7 @@ impl DeletionService {
) -> Result<Option<DeleteClaim>, DeletionError> {
let claim_token = new_id('c')?;
let claim_seconds = duration_seconds(self.config.claim_ttl)?;
let mut tx = self.pool.begin().await?;
let row = sqlx::query_as::<_, ClaimRow>(
"WITH candidate AS (
SELECT i.item_id
@ -257,19 +264,29 @@ impl DeletionService {
.bind(operation_id.as_str())
.bind(claim_token.as_str())
.bind(claim_seconds)
.fetch_optional(&self.pool)
.fetch_optional(tx.as_mut())
.await?;
if row.is_some() {
sqlx::query(
let job_id: Option<String> = sqlx::query_scalar(
"UPDATE deletion_operations
SET state = 'running', problem_class = NULL, problem_message = NULL,
updated_at = now()
WHERE operation_id = $1 AND state <> 'completed'",
WHERE operation_id = $1 AND state NOT IN ('running', 'completed')
RETURNING job_id",
)
.bind(operation_id.as_str())
.execute(&self.pool)
.fetch_optional(tx.as_mut())
.await?;
if let Some(job_id) = job_id {
enqueue(
&mut tx,
"deletion.updated",
json!({ "job_id": job_id, "operation_id": operation_id }),
)
.await?;
}
}
tx.commit().await?;
row.map(ClaimRow::into_claim).transpose()
}
@ -377,7 +394,7 @@ impl DeletionService {
.await?;
let completed = finalize_if_empty(
&mut tx,
&OpaqueId::parse(job_id).map_err(durable_effect)?,
&OpaqueId::parse(&job_id).map_err(durable_effect)?,
&claim.operation_id,
now,
)
@ -393,6 +410,12 @@ impl DeletionService {
.bind(now)
.execute(tx.as_mut())
.await?;
enqueue(
&mut tx,
"deletion.updated",
json!({ "job_id": job_id, "operation_id": claim.operation_id }),
)
.await?;
}
tx.commit().await?;
Ok(if completed {
@ -433,6 +456,17 @@ impl DeletionService {
.bind(message)
.execute(tx.as_mut())
.await?;
let job_id: String =
sqlx::query_scalar("SELECT job_id FROM deletion_operations WHERE operation_id = $1")
.bind(claim.operation_id.as_str())
.fetch_one(tx.as_mut())
.await?;
enqueue(
&mut tx,
"deletion.updated",
json!({ "job_id": job_id, "operation_id": claim.operation_id }),
)
.await?;
tx.commit().await?;
Ok(())
}
@ -793,7 +827,7 @@ async fn finalize_if_empty(
if remaining {
return Ok(false);
}
sqlx::query(
let operation_changed = sqlx::query(
"UPDATE deletion_operations
SET state = 'completed', problem_class = NULL, problem_message = NULL,
updated_at = $2, completed_at = $2
@ -803,6 +837,14 @@ async fn finalize_if_empty(
.bind(now)
.execute(tx.as_mut())
.await?;
if operation_changed.rows_affected() == 1 {
enqueue(
tx,
"deletion.updated",
json!({ "job_id": job_id, "operation_id": operation_id }),
)
.await?;
}
let changed = sqlx::query(
"UPDATE jobs
SET lifecycle = 'hard_deleted', revision = revision + 1, updated_at = $3