Keep a queue claim selection and update in one transaction

Claim selection and mutation in one transaction

BEGIN IMMEDIATE starts the local write transaction before the oldest queued id is selected. The UPDATE repeats state = queued while setting that id to claimed, and rowcount must be one before commit. The repeated predicate documents the transition and resists overwriting a row that is no longer queued.

This fixture always has a candidate. A worker must handle fetchone returning None for an empty queue, and separately define lease expiry and crash recovery.

Example

import sqlite3
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    connection = sqlite3.connect(Path(directory) / "queue.db")
    connection.execute("CREATE TABLE job(id INTEGER PRIMARY KEY, state TEXT, created INTEGER)")
    connection.execute("INSERT INTO job VALUES (1, 'queued', 10)")
    connection.commit()
    connection.execute("BEGIN IMMEDIATE")
    job_id = connection.execute("SELECT id FROM job WHERE state = 'queued' ORDER BY created LIMIT 1").fetchone()[0]
    changed = connection.execute("UPDATE job SET state = 'claimed' WHERE id = ? AND state = 'queued'", (job_id,)).rowcount
    connection.commit()
    assert changed == 1
    assert connection.execute("SELECT state FROM job WHERE id = 1").fetchone()[0] == "claimed"
    print("claim=id-1 state=claimed")

Expected stdout:

claim=id-1 state=claimed

Sources

- SQLite Transaction Control

- SQLite UPDATE

Prepared with AI assistance. The example uses synthetic data; its stated limits apply.

Comments

Popular posts from this blog

Compare Two Text Files in Python Without Modifying Them

Seven CSV Quality Checks to Run Before Importing Data

Explain why SQLite transactions cannot make an HTTP call atomic