pg queue/tx/notify dedupe + doc truth-telling: job_from_row has one owner (queue.rs, tx.rs imports it) and get_job_tx reuses live_columns()/dead_columns() instead of inlining the 18-column lists — the contract-pinned Job shape now has exactly one decode owner (ADR-012 §2); sweep_expired's doc states the moved + retention-deleted sum in the in_tx multi-statement frame (the sum the SQLite twin returns — the doc was the only liar); notify.rs's closed-store listen error routes through the shared database_error helper; bridge_capacity() is a const with its rationale doc carried. No behavior change — identical SQL strings, error shapes, and capacity. (task pg-fix-dedupe-cleanup, review 002 minor notes + Finding 6 queue bullet)
This commit is contained in:
1 parent
12d0497b1c
commit
40625090f6
4 files changed
+61
-77
No files matched your search
+14
-61
@@ -84,10 +84,11 @@ use serde_json::Value;
|
||||
use tokio::runtime::Handle;
|
||||
|
||||
use alkstore::{
|
||||
BoxedFuture, EnqueueOpts, Error, Job, JobState, Result, StreamEvent, TxHandle,
|
||||
validate_local_name, validate_shared_name,
|
||||
BoxedFuture, EnqueueOpts, Error, Job, Result, StreamEvent, TxHandle, validate_local_name,
|
||||
validate_shared_name,
|
||||
};
|
||||
|
||||
use crate::queue::{dead_columns, job_from_row, live_columns};
|
||||
use crate::resolution::{
|
||||
ResolvedEnqueue, outbox_backing_queue_name, outbox_default_stamps, plain_queue_default_stamps,
|
||||
resolve_enqueue_opts, stamps_with_override,
|
||||
@@ -471,13 +472,9 @@ impl TxHandle for PgTxHandle {
|
||||
let row = client
|
||||
.query_opt(
|
||||
&format!(
|
||||
"SELECT id, queue, 'dead', payload, priority, run_at, attempts,
|
||||
max_attempts, worker_id, claimed_at, claim_expires_at,
|
||||
created_at, expires_at, visibility_timeout_s,
|
||||
backoff_base_s, dead_letter_retention_s,
|
||||
last_error, died_at
|
||||
FROM {} WHERE id = $1 AND queue = $2",
|
||||
self.table(tables::DEAD)
|
||||
"SELECT {dead} FROM {deadt} WHERE id = $1 AND queue = $2",
|
||||
dead = dead_columns(),
|
||||
deadt = self.table(tables::DEAD)
|
||||
),
|
||||
&[&job_id, &queue],
|
||||
)
|
||||
@@ -489,13 +486,9 @@ impl TxHandle for PgTxHandle {
|
||||
let row = client
|
||||
.query_opt(
|
||||
&format!(
|
||||
"SELECT id, queue, state, payload, priority, run_at, attempts,
|
||||
max_attempts, worker_id, claimed_at, claim_expires_at,
|
||||
created_at, expires_at, visibility_timeout_s,
|
||||
backoff_base_s, dead_letter_retention_s,
|
||||
NULL::text, NULL::bigint
|
||||
FROM {} WHERE id = $1 AND queue = $2",
|
||||
self.table(tables::JOB)
|
||||
"SELECT {live} FROM {jobt} WHERE id = $1 AND queue = $2",
|
||||
live = live_columns(),
|
||||
jobt = self.table(tables::JOB)
|
||||
),
|
||||
&[&job_id, &queue],
|
||||
)
|
||||
@@ -678,48 +671,8 @@ impl Drop for PgTxHandle {
|
||||
}
|
||||
}
|
||||
|
||||
/// Decode a job row (the uniform 18-column shape — the dead-table
|
||||
/// select carries `last_error`/`died_at`; the live one binds NULLs)
|
||||
/// into the contract value (`Job::from_row` — the `#[doc(hidden)]`
|
||||
/// constructor, ADR-021 §2's field list of record). Malformed rows map
|
||||
/// to `Error::Codec` (the decode-side posture guard).
|
||||
fn job_from_row(row: &tokio_postgres::Row) -> Result<Job> {
|
||||
let state = match row.get::<_, Option<&str>>(2) {
|
||||
Some("pending") => JobState::Pending,
|
||||
Some("processing") => JobState::Processing,
|
||||
Some("dead") => JobState::Dead,
|
||||
other => {
|
||||
return Err(Error::Codec(format!(
|
||||
"job row state must be pending|processing|dead, got {other:?}"
|
||||
)));
|
||||
}
|
||||
};
|
||||
let payload: Option<Vec<u8>> = row
|
||||
.try_get(3)
|
||||
.map_err(|e| Error::Codec(format!("job row payload must be bytea: {e}")))?;
|
||||
Ok(Job::from_row(
|
||||
row.get(0),
|
||||
row.get(1),
|
||||
state,
|
||||
payload.unwrap_or_default(),
|
||||
row.get(4),
|
||||
row.get(5),
|
||||
row.get(6),
|
||||
row.get(7),
|
||||
row.get(8),
|
||||
row.get(9),
|
||||
row.get(10),
|
||||
row.get(11),
|
||||
row.get(12),
|
||||
row.get(13),
|
||||
row.get(14),
|
||||
row.get(15),
|
||||
row.get(16),
|
||||
row.get(17),
|
||||
))
|
||||
}
|
||||
|
||||
// The stream-page decode (`stream_events_from_rows`) lives in
|
||||
// `stream.rs` — the one decode owner the tx reads and the auto-commit
|
||||
// reads share (the `stream` field mapping and the `Codec` posture
|
||||
// guard live once; ADR-012 §2's one-owner rule).
|
||||
// The row decodes ride one owner each: the stream-page decode
|
||||
// (`stream_events_from_rows`) lives in `stream.rs`, the job-row
|
||||
// decode (`job_from_row` + the select column lists) in `queue.rs` —
|
||||
// the one decode owners the tx reads and the auto-commit reads share
|
||||
// (ADR-012 §2's one-owner rule).
|
||||
Reference in new issue
Block a user