Skip to content

fix: Redis/Dragonfly connection resilience and job ID collisions - #284

Merged
sasagar merged 4 commits into
devfrom
fix/issue-281-redis-resilience
Oct 14, 2026
Merged

sasagar merged 4 commits into
devfrom
fix/issue-281-redis-resilience

Conversation

@sasagar

@sasagar sasagar commented Oct 13, 2026

Copy link
Copy Markdown
Member

Closes #281

#274 で backend が実際に Dragonfly へ接続するようになったことで表に出た問題を、まとめて直します(/code-review の指摘 1〜7)。

変更内容

接続の扱い(新規ファイル lib/redis.ts にまとめ、キャッシュとキューの両方から使う)

  • 再接続をあきらめない: 再接続の間隔は少しずつ延ばし、上限は 5 秒にしました。以前は約 0.6 秒で再接続をやめていたので、Dragonfly が再起動するとワーカーが止まったままになっていました。
  • 起動時の待ち方: 最初の接続エラーで失敗とせず、最大 15 秒まで接続できるのを待ちます。アプリの起動は初期化の完了を待たない作りなので、起動が遅くなることはありません。
  • ログ: 接続が切れたときに warn を 1 回、復帰したときに info を 1 回出します。正常に終了するときは何も出しません。
  • 共通化: 接続先 URL を決める処理(REDIS_URL → DRAGONFLY_URL → localhost)と protocol: 2 の設定を 1 か所にまとめ、2 つのファイルの重複をなくしました。
  • キャッシュ: 接続に失敗したとき、裏で再接続を続けないように切断するようにしました。

ジョブ ID

  • 32 ビットのハッシュをやめ、d- + SHA-256 の先頭 128 ビット(16 進数)にしました。別々の配信が同じ ID になって捨てられることがなくなり、数字だけの ID(BullMQ が拒否する)もできなくなります。
  • ジョブ ID の計算方法が変わるだけなので、すでにキューに入っているジョブに影響はありません。

compose / env

  • 3 つの compose ファイルから --cache_mode=true を外しました。これで BullMQ のキーが追い出されなくなります。キャッシュは全部 TTL 付きで保存しているので、キャッシュが消えずにたまり続けることもありません。
  • docker/compose.yml: backend は Dragonfly が healthy になってから起動するようにしました(service_healthy)。
  • .env.example: REDIS_URL をコメントアウトしました。例からコピーした .env が、compose の DRAGONFLY_URL より優先されてしまうのを防ぐためです。

依存

  • 使われなくなった @simplewebauthn/types を削除し、AuthenticatorTransport を @simplewebauthn/server から import するようにしました。

本番の K8s は --cache_mode を使っておらず、.env.example も使っていないので、本番に関係するのは「接続の扱い」と「ジョブ ID」の 2 つです。

確認したこと

  • typecheck、lint、format:check はエラーなし。ユニットテストは 1027 件すべて通過しました(数字だけの ID ができないことを確かめるテストを 1 件追加)。
  • 手元の Dragonfly 1.35 のコンテナを使って確認しました。
    1. backend を先に起動し、3 秒後に Dragonfly を起動 → キューが有効になり、配信はキューで処理された
    2. Dragonfly を止めて 4 秒後に起動し直す → warn と info が 1 回ずつ出て、backend を再起動せずに次の配信がキューで処理された

https://claude.ai/code/session_01Y29fBeRP344FME6de48wUv

- Add lib/redis.ts with shared URL resolution, protocol: 2 and a
  never-give-up reconnect strategy (capped at 5s) for both the cache
  adapter and the delivery queue
- Wait up to 15s for the first ready event instead of failing on the
  first connection error, so a late Dragonfly start no longer disables
  the queue and cache for the process lifetime
- Log a warning once per outage and an info message on recovery
- Generate job IDs from a SHA-256 digest with a d- prefix: no
  collisions between deliveries and never integer-like (rejected by
  BullMQ)

Claude-Session: https://claude.ai/code/session_01Y29fBeRP344FME6de48wUv
#281)

- Drop --cache_mode=true so Dragonfly never evicts queue keys; every
  cache entry already sets a TTL
- Start the backend only after Dragonfly is healthy
- Comment out REDIS_URL in .env.example so a copied .env does not
  override the DRAGONFLY_URL set by compose and the devcontainer

Claude-Session: https://claude.ai/code/session_01Y29fBeRP344FME6de48wUv
@simplewebauthn/server v14 exports AuthenticatorTransport itself.

Claude-Session: https://claude.ai/code/session_01Y29fBeRP344FME6de48wUv
@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 15 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: Love-Rox/rox/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: fec127bc-f93d-435b-9b7c-184a48d763e0
📥 Commits

Reviewing files that changed from the base of the PR and between b78fc9a and 17c814a.

⛔ Files ignored due to path filters: 1
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing: 11
  • .devcontainer/compose.yml
  • .env.example
  • docker/compose.dev.yml
  • docker/compose.yml
  • packages/backend/package.json
  • packages/backend/src/adapters/cache/DragonflyCacheAdapter.ts
  • packages/backend/src/lib/redis.ts
  • packages/backend/src/services/PasskeyService.ts
  • packages/backend/src/services/ap/ActivityDeliveryQueue.ts
  • packages/backend/src/tests/unit/ActivityDeliveryQueue.test.ts
  • packages/backend/src/tests/unit/redis.test.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

The startup timeout error included the raw REDIS_URL/DRAGONFLY_URL,
which can contain a password and is logged at warn level.

Claude-Session: https://claude.ai/code/session_01Y29fBeRP344FME6de48wUv
@sasagar

sasagar commented Oct 14, 2026

Copy link
Copy Markdown
Member Author

追加のコミット(17c814a): 起動時のタイムアウトのエラーメッセージに、Redis の URL がそのまま入っていました。URL にパスワードが含まれていると warn ログに出てしまうので、ユーザー名とパスワードを *** に置き換えるようにし、ユニットテストを 4 件追加しました(コミット後のセキュリティレビューの指摘)。

@sasagar
sasagar merged commit 6483e0e into dev Oct 14, 2026
11 checks passed
@sasagar
sasagar deleted the fix/issue-281-redis-resilience branch October 14, 2026 00:03
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.

1 participant