Skip to content

Fix RedisMessageQueue race condition#532

Merged
dahlia merged 6 commits intofedify-dev:mainfrom
sij411:fix/redismq
Jan 24, 2026
Merged

Fix RedisMessageQueue race condition#532
dahlia merged 6 commits intofedify-dev:mainfrom
sij411:fix/redismq

Conversation

@sij411
Copy link
Contributor

@sij411 sij411 commented Jan 23, 2026

Summary

  • Fixed a race condition in RedisMessageQueue.listen() where pub/sub notifications could be missed if enqueue() was called immediately after listen() started
  • The message handler was attached inside an async callback, allowing a timing window where messages could be published before the handler was ready
  • Added deterministic regression test using mock Redis to reproduce the bug 100% of the time

Test plan

  • Run deno test --allow-all packages/redis/src/mq.race.test.ts - deterministic regression tests pass
  • Run deno test --allow-all packages/redis/src/mq.test.ts with Redis - integration test passes (requires REDIS_URL env)
  • Pre-commit hooks pass (lint, fmt, types)

Fixes #515

🤖 Generated with Claude Code

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @sij411, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves a critical race condition within the RedisMessageQueue's listen() method. Previously, messages could be lost due to a timing issue where the message handler was not yet active when a message was published. The fix ensures that the message handler is fully established before the listen() method proceeds, guaranteeing reliable message delivery. A dedicated, deterministic test case has been introduced to prevent future regressions of this specific issue.

Highlights

  • Race Condition Fix: Addressed a race condition in RedisMessageQueue.listen() where pub/sub notifications could be missed if enqueue() was called immediately after listen() started.
  • Root Cause Identified: The race condition was caused by the message handler being attached inside an async callback, creating a timing window where messages could be published before the handler was ready.
  • Solution Implemented: The listen() method now awaits the Redis subscription before synchronously attaching the message handler, ensuring no notifications are missed.
  • New Regression Test: A new deterministic regression test (mq.race.test.ts) has been added using a mock Redis client to reliably reproduce the bug and verify the fix.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@sij411
Copy link
Contributor Author

sij411 commented Jan 23, 2026

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively addresses a critical race condition in the RedisMessageQueue.listen() method, where pub/sub notifications could be missed. The fix correctly ensures that the message handler is attached synchronously after the Redis subscription is established, preventing messages from being lost during the timing window. The addition of a comprehensive and deterministic regression test suite, including a mock Redis client, is highly commendable and provides strong verification of the fix. The CHANGES.md entry clearly explains the issue and its resolution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request addresses a race condition in the RedisMessageQueue.listen() method, where pub/sub notifications could be missed if enqueue() was called immediately after listen() started. The fix involves awaiting the subscription before attaching the message handler, ensuring that no messages are missed. The pull request includes a deterministic regression test using mock Redis to reproduce the bug and verify the fix. The changes look good and the tests are well-written.

The message handler was attached inside an async callback, allowing
a timing window where pub/sub notifications could be missed if
enqueue() was called immediately after listen() started.

The fix awaits subscribe() and attaches the handler synchronously.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@sij411 sij411 marked this pull request as draft January 23, 2026 17:30
sij411 and others added 2 commits January 24, 2026 14:17
The unsubscribe() call was async but not awaited, causing
"Connection is closed" error when disconnect() was called
while unsubscribe() was still pending.

The original code didn't have unsubscribe() in the abort
handler - disconnect() handles cleanup.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@codecov
Copy link

codecov bot commented Jan 24, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

Files with missing lines Coverage Δ
packages/redis/src/mq.ts 90.14% <100.00%> (+1.98%) ⬆️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@sij411 sij411 marked this pull request as ready for review January 24, 2026 05:49
@dahlia dahlia added type/bug Something isn't working type/test Testing related driver/redis Redis driver (@fedify/redis) labels Jan 24, 2026
@dahlia dahlia merged commit 7f2bb1d into fedify-dev:main Jan 24, 2026
30 of 31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

driver/redis Redis driver (@fedify/redis) type/bug Something isn't working type/test Testing related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RedisMessageQueue test intermittently times out in CI

2 participants