Skip to content

blog: remove em dashes from SKIP LOCKED post - #8080

Merged
nurul3101 merged 1 commit into
mainfrom
blog/skip-locked-em-dash-cleanup
Jul 17, 2026
Merged

blog: remove em dashes from SKIP LOCKED post#8080
nurul3101 merged 1 commit into
mainfrom
blog/skip-locked-em-dash-cleanup

Conversation

@nurul3101

@nurul3101 nurul3101 commented Jul 17, 2026

Copy link
Copy Markdown
Member

Punctuation-only follow-up to #8079, which merged while this pass was in flight. Replaces every em dash in the post with a comma, colon, period, or parentheses per author style. The demo's log separator changed from an em dash to a hyphen, and the expected-output block is a fresh captured run with the new separator, so the shown output stays a real run. No content changes.

Summary by CodeRabbit

  • Documentation
    • Revised the article’s wording, punctuation, and structure for improved clarity.
    • Expanded explanations of database readiness checks, concurrent workers, retries, crash recovery, and idempotency.
    • Updated guidance on when to use a dedicated queue and common job-recovery approaches.
    • Refined the embedded demo, example output, recap, and FAQ content.

Punctuation-only pass per author preference. The demo's log separator
changed from an em dash to a hyphen; the expected-output block is a
fresh captured run with the new separator.
@vercel

vercel Bot commented Jul 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
blog Ready Ready Preview, Comment Jul 17, 2026 11:26am
docs Ready Ready Preview, Comment Jul 17, 2026 11:26am
eclipse Ready Ready Preview, Comment Jul 17, 2026 11:26am
site Ready Ready Preview, Comment Jul 17, 2026 11:26am

Request Review

@nurul3101 nurul3101 self-assigned this Jul 17, 2026
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The PostgreSQL job queue article received editorial revisions covering queue concepts, worker behavior, retry and crash recovery, dedicated queue guidance, FAQs, recap text, and matching demo output.

Changes

PostgreSQL job queue article

Layer / File(s) Summary
Article framing and queue concepts
apps/blog/content/blog/you-dont-need-a-job-queue-postgres-already-has-skip-locked/index.mdx
Introductory and queue-concept explanations were reworded, including concurrency, indexing, dead-letter handling, and database setup.
Worker behavior and recovery explanation
apps/blog/content/blog/you-dont-need-a-job-queue-postgres-already-has-skip-locked/index.mdx
The demo failure log and output were synchronized, while worker readiness, SKIP LOCKED contention, retries, crash recovery, and deployment text were clarified.
Dedicated queue guidance and recap
apps/blog/content/blog/you-dont-need-a-job-queue-postgres-already-has-skip-locked/index.mdx
Dedicated queue recommendations, FAQ answers, transactional enqueueing, and recovery tradeoff text were revised.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • prisma/web#8079: Updates the same PostgreSQL job queue article and its embedded demo logging/output.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: a punctuation-only edit removing em dashes from the SKIP LOCKED blog post.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@nurul3101
nurul3101 merged commit 3b39d56 into main Jul 17, 2026
13 of 16 checks passed
@nurul3101
nurul3101 deleted the blog/skip-locked-em-dash-cleanup branch July 17, 2026 11:25
@argos-ci

argos-ci Bot commented Jul 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
default (Inspect) ✅ No changes detected - Jul 17, 2026, 11:32 AM

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@apps/blog/content/blog/you-dont-need-a-job-queue-postgres-already-has-skip-locked/index.mdx`:
- Line 421: In the pg-boss paragraph, update the phrase “needs outgrow” to
“needs to outgrow,” preserving the surrounding sentence and link unchanged.
- Line 401: The blog’s email deduplication guidance must not imply that writing
an emails_sent row after sending is sufficient. Update the discussion around the
queue’s at-least-once semantics to prefer a provider-enforced idempotency key,
or describe a durable send/retry state machine that explicitly handles crashes
between sending and recording success.
- Line 92: Update the partial-index discussion in the blog post to limit index
churn to updates that remove or rewrite entries matching the status = 'pending'
predicate, rather than claiming every status flip creates a dead index entry.
Retain the point that PostgreSQL relies on autovacuum/vacuum to clean obsolete
index entries.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5b3c5c72-47dc-4183-b5f6-c59899da397a

📥 Commits

Reviewing files that changed from the base of the PR and between 3dac0d2 and 1d4057c.

📒 Files selected for processing (1)
  • apps/blog/content/blog/you-dont-need-a-job-queue-postgres-already-has-skip-locked/index.mdx

```

The partial index only covers pending rows, so the claim query doesn't wade through the pile of completed jobs. It still relies on autovacuum keeping up every status flip leaves a dead index entry behind, a limit we'll come back to.
The partial index only covers pending rows, so the claim query doesn't wade through the pile of completed jobs. It still relies on autovacuum keeping up: every status flip leaves a dead index entry behind, a limit we'll come back to.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Scope the partial-index churn claim to pending transitions.

“Every status flip” is too broad: a runningdone transition does not remove a row from the pending-only index. Describe churn as occurring when updates remove or rewrite entries covered by the status = 'pending' predicate. PostgreSQL cleans obsolete index entries through vacuum. (postgresql.org)

Proposed wording
- It still relies on autovacuum keeping up: every status flip leaves a dead index entry behind, a limit we'll come back to.
+ It still relies on autovacuum keeping up: updates that remove a row from the pending predicate or rewrite its indexed values leave dead index entries behind, a limit we'll come back to.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
The partial index only covers pending rows, so the claim query doesn't wade through the pile of completed jobs. It still relies on autovacuum keeping up: every status flip leaves a dead index entry behind, a limit we'll come back to.
The partial index only covers pending rows, so the claim query doesn't wade through the pile of completed jobs. It still relies on autovacuum keeping up: updates that remove a row from the pending predicate or rewrite its indexed values leave dead index entries behind, a limit we'll come back to.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/blog/content/blog/you-dont-need-a-job-queue-postgres-already-has-skip-locked/index.mdx`
at line 92, Update the partial-index discussion in the blog post to limit index
churn to updates that remove or rewrite entries matching the status = 'pending'
predicate, rather than claiming every status flip creates a dead index entry.
Retain the point that PostgreSQL relies on autovacuum/vacuum to clean obsolete
index entries.

Source: MCP tools

The alternative holds the claim inside an open transaction for the length of the job, so a crash rolls the row back automatically. That costs a pinned connection per job, undoes the `attempts` increment (a job that crashes its worker retries forever), and holds back vacuum on a busy queue.

Either way, this queue delivers at least once, not exactly onceno recovery scheme escapes that. A crash after the work but before the `done` update, a janitor reset of a slow worker, even a connection blip between finishing a job and recording it: each can run a job's side effect twice. Write handlers so that running them twice is safe. For the welcome email that opened this post, that means a dedupe key: an `emails_sent` row written on success and checked before sending, or an idempotency key passed to the email provider, so a repeat run finds the work already done and skips it. The same move covers any side effect give it a key, check the key first.
Either way, this queue delivers at least once, not exactly once; no recovery scheme escapes that. A crash after the work but before the `done` update, a janitor reset of a slow worker, even a connection blip between finishing a job and recording it: each can run a job's side effect twice. Write handlers so that running them twice is safe. For the welcome email that opened this post, that means a dedupe key: an `emails_sent` row written on success and checked before sending, or an idempotency key passed to the email provider, so a repeat run finds the work already done and skips it. The same move covers any side effect: give it a key, check the key first.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not present a post-send success row as sufficient deduplication.

If the email is sent and the process crashes before emails_sent is written, the retry finds no marker and sends the email again. Prefer a provider-enforced idempotency key, or describe a durable state machine whose send/retry protocol explicitly handles this crash window.

Proposed wording
- that means a dedupe key: an `emails_sent` row written on success and checked before sending, or an idempotency key passed to the email provider, so a repeat run finds the work already done and skips it.
+ that means an idempotency key enforced by the email provider, or a durable deduplication state machine designed for crash recovery. A success row written after sending alone does not prevent duplicates.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Either way, this queue delivers at least once, not exactly once; no recovery scheme escapes that. A crash after the work but before the `done` update, a janitor reset of a slow worker, even a connection blip between finishing a job and recording it: each can run a job's side effect twice. Write handlers so that running them twice is safe. For the welcome email that opened this post, that means a dedupe key: an `emails_sent` row written on success and checked before sending, or an idempotency key passed to the email provider, so a repeat run finds the work already done and skips it. The same move covers any side effect: give it a key, check the key first.
Either way, this queue delivers at least once, not exactly once; no recovery scheme escapes that. A crash after the work but before the `done` update, a janitor reset of a slow worker, even a connection blip between finishing a job and recording it: each can run a job's side effect twice. Write handlers so that running them twice is safe. For the welcome email that opened this post, that means an idempotency key enforced by the email provider, or a durable deduplication state machine designed for crash recovery. A success row written after sending alone does not prevent duplicates. The same move covers any side effect: give it a key, check the key first.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/blog/content/blog/you-dont-need-a-job-queue-postgres-already-has-skip-locked/index.mdx`
at line 401, The blog’s email deduplication guidance must not imply that writing
an emails_sent row after sending is sufficient. Update the discussion around the
queue’s at-least-once semantics to prefer a provider-enforced idempotency key,
or describe a durable send/retry state machine that explicitly handles crashes
between sending and recording success.

- **Queue features as a product.** Rate limiting, per-queue concurrency caps, job priorities, repeatable jobs: [BullMQ](https://bullmq.io) ships all of it. Rebuilding it on a jobs table is possible and rarely worth it.

There's also a middle path: [pg-boss](https://github.com/timgit/pg-boss) is this exact pattern`SKIP LOCKED` on a Postgres table packaged as a library with retries, scheduling, and retention policies already written. If your queue needs outgrow a hand-rolled table but your throughput still fits in Postgres, reach for it before reaching for a broker.
There's also a middle path: [pg-boss](https://github.com/timgit/pg-boss) is this exact pattern, `SKIP LOCKED` on a Postgres table, packaged as a library with retries, scheduling, and retention policies already written. If your queue needs outgrow a hand-rolled table but your throughput still fits in Postgres, reach for it before reaching for a broker.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the missing infinitive.

Change “needs outgrow” to “needs to outgrow.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/blog/content/blog/you-dont-need-a-job-queue-postgres-already-has-skip-locked/index.mdx`
at line 421, In the pg-boss paragraph, update the phrase “needs outgrow” to
“needs to outgrow,” preserving the surrounding sentence and link unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants