fix(backend): enableFanoutTimeline トグル時のタイムライン取りこぼし問題を修正#17548
Draft
fruitriin wants to merge 3 commits into
Draft
fix(backend): enableFanoutTimeline トグル時のタイムライン取りこぼし問題を修正#17548fruitriin wants to merge 3 commits into
fruitriin wants to merge 3 commits into
Conversation
トグル直後に Redis 上の list:* キャッシュと DB が不整合になりノートが取りこぼされる問題を、過渡期フラグ `fanoutTimelineActive` の導入で解消する。トグルされた瞬間に active=false にしてデータプレーンを FTTL から切り離し、BullMQ ジョブで Redis を purge してから active=true に書き戻す。過渡期中の `enableFanoutTimeline` 再変更は 409 (FANOUT_TIMELINE_TRANSITION_IN_PROGRESS) で拒否し、管理画面の UI も同期して disable する。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #17548 +/- ##
===========================================
+ Coverage 15.14% 22.63% +7.49%
===========================================
Files 248 1164 +916
Lines 12412 39879 +27467
Branches 4214 11082 +6868
===========================================
+ Hits 1880 9028 +7148
- Misses 8241 24773 +16532
- Partials 2291 6078 +3787 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Contributor
|
このPRによるapi.jsonの差分 差分はこちら--- base
+++ head
@@ -9902,6 +9902,9 @@
"enableFanoutTimeline": {
"type": "boolean"
},
+ "fanoutTimelineActive": {
+ "type": "boolean"
+ },
"enableFanoutTimelineDbFallback": {
"type": "boolean"
},
@@ -10215,6 +10218,7 @@
"manifestJsonOverride",
"policies",
"enableFanoutTimeline",
+ "fanoutTimelineActive",
"enableFanoutTimelineDbFallback",
"perLocalUserUserTimelineCacheMax",
"perRemoteUserUserTimelineCacheMax",
@@ -19836,6 +19840,16 @@
"$ref": "#/components/schemas/Error"
},
"examples": {
+ "FANOUT_TIMELINE_TRANSITION_IN_PROGRESS": {
+ "value": {
+ "error": {
+ "message": "A fanout timeline toggle is currently being applied. Please wait until the purge job completes before changing enableFanoutTimeline again.",
+ "code": "FANOUT_TIMELINE_TRANSITION_IN_PROGRESS",
+ "id": "65b9b26a-700c-41ea-96f7-96b9a7902301",
+ "httpStatusCode": 409
+ }
+ }
+ },
"INVALID_PARAM": {
"value": {
"error": { |
Contributor
Backend memory usage comparisonBefore GC
After GC
After Request
|
1 task
4 tasks
3 点の修正:
1. update-meta で `ps.enableFanoutTimeline` が現状と同値のときに `set` が空になり、`metaService.update({})` が空 SET の UPDATE を発行して 500 を返していた。`set.enableFanoutTimeline = ps.enableFanoutTimeline` を常に入れて回避。
2. 過渡期判定を「`!fanoutTimelineActive`」から「`enableFanoutTimeline !== fanoutTimelineActive` (= 乖離している状態)」に変更。stable な OFF/OFF からの ON 化が拒否されなくなる。frontend のトグル disable 判定も同じ条件に揃える。
3. test-server エントリでは BullMQ ワーカーが未起動なので、`FTT toggle purge` describe で `startJobQueue()` を beforeAll で起動して purge ジョブを完走させる。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ion を防ぐ `moderationLogService.log` は内部で `await insert()` する async メソッドだが、admin/update-meta では fire-and-forget で呼ばれていた。INSERT が FK 違反等で失敗すると Unhandled Promise Rejection になり、E2E テストランナー (vitest) が落ちる。FTT トグル追加で update-meta の呼び出し回数が増え、in-flight log が cleanup と衝突して CI が失敗していたため、ここで await する。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
管理画面で
enableFanoutTimelineを ON → OFF → ON のように切り替えると、 OFF 期間中の投稿が Redis 上のキャッシュリスト (list:homeTimeline:*等) に乗らないまま、 ON 復帰後の新規投稿だけが Redis 先頭に追加される。 これにより Redis 上の時系列にギャップが生じ、 タイムライン API のレスポンスから OFF 期間の投稿が永久に取りこぼされていた。admin/update-metaでenableFanoutTimelineの値が変化したとき、FanoutTimelineService.purgeAllで Redis 上のlist:*キーを一括削除するように変更した。削除後の Redis は空になるが、 タイムライン取得側 (
FanoutTimelineEndpointService) はnoteIds.length === 0を検知してshouldFallbackToDb=true経路で DB に直行するため、 結果として DB から自然に再構築 される。 そのあとの新規投稿は通常通り Redis に積み上がる。追加した API
FanoutTimelineServiceに以下のメソッドを追加:SCANでカーソル回しているため、 リスト数が多くても Redis サーバーをブロックしない。admin/update-metaの変更点Why
enableFanoutTimelineのトグル操作は管理画面から 1 クリックでできる 通常の運用操作 (FTT の挙動調査、 障害対応、 一時メンテ等で行われる)。 現状の実装では、 このトグル前後に投稿された OFF 期間中のノート が Redis 上のキャッシュリストに乗らず、 ON 復帰後の新規投稿との間に Redis 上で時系列ギャップが生じる。そして取得側の
FanoutTimelineEndpointServiceの最終 DB フォールバックは、 DB クエリの境界として Redis 上の最古 ID を使うため、 中間ギャップに該当するノートを補完できない (ギャップ範囲が DB クエリの対象外になる)。 結果、 ユーザーから「過去のノートが TL に表示されない」 「ページネーションで深掘りしても出てこない」 という障害が起きる。本 PR はトグル時に Redis をパージすることで、 Redis 上にギャップが残らないようにし、 取得側のロジックを変更せず根本的に解消する。
詳細・再現手順・関連 PR は Issue #fruitriin#38 参照。
Additional info (optional)
Tests added
packages/backend/test/e2e/timelines.tsに新 describe ブロックFTT toggle purgeを追加 (2 ケース):notes/timelineで全 15 件が返ることを確認channels/timelineを検証ローカル動作確認
ローカル dev サーバーに修正を当てて手動で実証:
admin/update-meta { enableFanoutTimeline: false }を叩くadmin/update-meta { enableFanoutTimeline: true }で ON に戻すnotes/timeline limit=20→ DB から 20 件正しく取得 ✓channels/timeline limit=20→ DB から 20 件正しく取得 ✓Trade-off
SCANの範囲:list:*で全 FTT キーを対象にする。 アンテナタイムライン (list:antennaTimeline:*) も含まれるが、 アンテナ TL endpoint は別実装で Redis 状態の影響を受ける挙動を持つため、 整合性向上の観点でこれも初期化する方が安全と判断。Affected endpoints / services
packages/backend/src/core/FanoutTimelineService.ts:purgeAll()メソッド追加packages/backend/src/server/api/endpoints/admin/update-meta.ts:enableFanoutTimelineトグル時にpurgeAll()を呼ぶRelated
PR #17549 と本 PR は独立に merge 可能。 両方入れば「トグル時に Redis をパージ」 (本 PR) + 「万一 Redis ギャップが残っても取得側で補完」 の二重防御になる。
Checklist