baldur.adapters.sql — Framework-Free SQL Adapter (DB-API 2.0)
Generic repository base plus priority-1 SQL-backed implementations of Baldur's core repositories. Works with any DB-API 2.0 driver (psycopg2, mysql-connector-python, stdlib sqlite3) — selected by DSN scheme.
sql
Framework-free SQL adapter (DB-API 2.0).
Provides a generic repository base plus priority-1 SQL-backed implementations of Baldur's core repositories. Works with any DB-API 2.0 driver — psycopg2, mysql-connector-python, or the stdlib sqlite3 — selected by DSN scheme.
Status: Public
GenericSQLRepository
GenericSQLRepository(
get_connection: Callable[[], Any],
*,
dialect: SQLDialect | None = None,
autocommit_delegated: bool | None = None,
schema: (
tuple[str, int, Callable[[SQLDialect], list[str]]]
| None
) = None
)
DB-API 2.0 repository helpers.
Subclasses inherit this class plus a domain-specific ABC
(FailedOperationRepository etc.). The base exposes helpers only
— no ABC method has a default implementation here, so there is no
MRO ambiguity.
Connection ownership: get_connection is a user-supplied
callable. Baldur does not own a pool. Each helper borrows a
connection via the callable and relies on the callable's
close() / return-to-pool semantics. Common implementations:
get_connection = lambda: psycopg2.connect(DSN)— direct.get_connection = engine.raw_connection— SQLAlchemy pool.get_connection = lambda: pgbouncer_pool.getconn()— external pooler.
SchemaVersionManager
SchemaVersionManager(
get_connection: Callable[[], Any],
*,
dialect: SQLDialect
)
Owns the baldur_schema_version bookkeeping table.
Repos call ensure(repo_name, version, ddl_statements) during
first use. DDL runs exactly once per (repo_name, version) pair per
database — subsequent calls are no-ops.
SQLEventJournalRepository
SQLEventJournalRepository(
get_connection: Callable[[], Any],
*,
dialect: SQLDialect | None = None,
autocommit_delegated: bool | None = None,
max_query_limit: int = 10000
)
SQLFailedOperationRepository
SQLFailedOperationRepository(
get_connection: Callable[[], Any],
*,
dialect: SQLDialect | None = None,
autocommit_delegated: bool | None = None
)
Bases: GenericSQLRepository, FailedOperationRepository
DB-API 2.0 backed DLQ repository.
count_created_in_window
count_created_in_window(
start: datetime, end: datetime
) -> int
Count rows whose created_at is in the inclusive [start, end].
Backed by idx_baldur_dlq_created_at — a range seek, not a scan.
find_replayable_page
find_replayable_page(
*,
max_retries: int,
domain: str | None = None,
failure_type: str | None = None,
source: str | None = None,
limit: int = 100,
cursor: str | None = None
) -> ReplayablePage
Keyset-paged replayable selection over idx_baldur_dlq_status_domain.
The seek binds a rebuilt datetime through _dt_to_db, never a
rendered timestamp: sqlite stores created_at as TEXT in the
driver's own space-separated form, which sorts below the ISO T
form, so a string comparison silently matches nothing — and an empty
page is exactly how a caller learns the queue is drained.
source lives inside the JSON payload, so it is the one residual
applied in Python; the loop keeps fetching windows until it has
limit matches or has examined REPLAY_SELECTION_MAX_SCAN rows.
Each window re-seeks from the row the previous one ended on, so a row
another drainer resolves mid-walk cannot shift the members behind it
past the next window's start.
get_facet_counts
get_facet_counts(
*, status: str | None = None, domain: str | None = None
) -> dict[str, dict[str, int]]
Faceted status×domain counts via GROUP BY.
by_status is scoped by domain; by_domain is scoped by
status. GROUP BY drops zero-count buckets structurally.
The domain-scoped by_status (WHERE domain GROUP BY status) is a
covering scan over idx_baldur_dlq_status_domain; the status-scoped
by_domain (WHERE status GROUP BY domain) is a prefix seek on the
same composite. Both exact, both fine on the cold operator read path.
try_acquire_for_replay
try_acquire_for_replay(
id: str, max_retries: int, force: bool = False
) -> FailedOperationData | None
Atomically flip PENDING → REPLAYING if retry budget remains.
Uses a conditional UPDATE as the concurrency guard. cursor.rowcount
0 means this worker won the race; the row is then re-read within the same transaction so no other writer can delete or mutate it between the claim and the DTO return.
force=True is the operator cap-override: it widens the WHERE status
set to {PENDING, REQUIRES_REVIEW}, drops the retry_count < max_retries
bound, resets retry_count to a fresh budget (1), and stamps the
metadata history scar into the JSON payload — all inside the same
transaction so the SELECT→UPDATE claim stays race-free against a
concurrent sweep. See FailedOperationRepository.try_acquire_for_replay.
get_compressed_entry
get_compressed_entry(
entry_id: str,
) -> DLQCompressedEntry | None
Return a single compressed entry by id, or None if absent.
A primary-key point read on the id VARCHAR column — proportional
to matches, like every SQL compressed query.
get_compressed_entries_before
get_compressed_entries_before(
*,
status: str,
before: datetime,
limit: int = 100,
offset: int = 0,
after: datetime | None = None
) -> list[DLQCompressedEntry]
Query compressed entries in a cutoff window, oldest first.
The (status, compressed_at) index serves both bounds and the order.
update_compressed_status
update_compressed_status(
entry_id: str, new_status: str
) -> bool
Transition compressed entry lifecycle status.
Stamps the matching timestamp column alongside the status, as the
memory and Redis adapters do. STALE -> ARCHIVED is driven off
stale_at, so an unstamped transition would strand the entry.
SQLRecoverySessionArchiveRepository
SQLRecoverySessionArchiveRepository(
get_connection: Callable[[], Any],
*,
dialect: SQLDialect | None = None,
autocommit_delegated: bool | None = None
)
Bases: GenericSQLRepository, RecoverySessionArchiveRepository
DB-API 2.0 backed recovery session archive repository.
SQLSecurityIncidentRepository
SQLSecurityIncidentRepository(
get_connection: Callable[[], Any],
*,
dialect: SQLDialect | None = None,
autocommit_delegated: bool | None = None
)
Bases: GenericSQLRepository, SecurityIncidentRepository
DB-API 2.0 backed security incident repository.
SQLStatisticsRepository
SQLStatisticsRepository(
get_connection: Callable[[], Any],
*,
dialect: SQLDialect | None = None,
autocommit_delegated: bool | None = None
)
Bases: GenericSQLRepository, StatisticsRepositoryInterface
DB-API 2.0 backed statistics repository.
Reads the baldur_dlq table directly and does not own a table —
schema bootstrap is skipped. The circuit-breaker methods read a table
Baldur never writes (CB state stays in memory or Redis) and return
empty results when it is absent.
sql_transaction
sql_transaction(conn: Any) -> Any
Suspend repo-scoped auto-commit for the duration of the block.
Usage::
with sql_transaction(conn):
dlq_repo.create(...)
postmortem_repo.save(...)
# single commit (or rollback on exception) applies to both.
All repositories whose get_connection returns conn during
the block skip their per-call commit. The context manager itself
issues the final commit, or rollback on exception.