概要
メインタイムラインページにおいて、ブログ記事がほとんど表示されない問題が発生していました。ブログ専用タイムラインでは全記事が正常に表示されていたため、メインタイムライン側に複数の構造的な問題があることが判明しました。
問題の内容
タイムラインは、ノートやログといった短文の投稿と、ブログ記事を時系列で統合して表示する機能を持っています。
しかし、メインタイムラインでは複数の問題が重なり、ブログ記事がほぼ表示されない状態になっていました。
原因1: 設定値のデフォルトが低すぎた
各ブログソースから取得する件数のデフォルトが 1 に設定されていました。さらに、データベースにも古い設定値 1 が保存されたままになっており、コード側のデフォルト値を変更してもデータベースの値が優先されるため、修正が反映されない構造的な問題がありました。
原因2: ブログエントリの日付パースがCF Workersで不安定だった
タイムラインの表示順序を決める日付パース処理において、ノートやログでは parseDateToTimestamp() ヘルパー関数(手動正規表現パース + Date.UTC() による決定論的変換)を使用していましたが、ブログエントリだけは new Date() を直接使用していました。
Cloudflare WorkersのV8ランタイムでは、タイムゾーンなしの日付文字列(例: "2026-02-21T09:00:00")の解釈が不安定で、NaN を返す可能性がありました。NaN になったブログエントリは sortTimestamp = 0(エポック時刻)として扱われ、タイムラインの最下部に追いやられていました。
原因3: D1スラグベースの重複排除が過度にブロックしていた
内部ブログ記事はD1データベースとContent Collections(静的ファイル)の2箇所から取得されます。重複を避けるためD1のスラグ一覧と照合して排除する仕組みを採用していましたが、D1のスラグ一覧の取得に成功しても記事データの取得に失敗した場合、Content Collectionsの記事が「D1にあるから不要」と判定されて全てスキップされていました。
原因4: 自己参照RSS除外がフォールバックを遮断していた
内部ブログのRSS URL(arismmn.pages.dev/blog/rss.xml)を外部RSS一覧から除外する修正を入れましたが、Content CollectionsがSSR環境で動作しない場合に、唯一のフォールバックソースまで遮断してしまう問題がありました。
修正内容
設定値の恒久対策
- 設定ファイルのデフォルト値:
1→50 - メインページ・無限スクロールAPI:
Math.max(設定値, 50)で最低50件を保証 - タイムライン関数の引数デフォルト値:
1→50
日付パースの修正
- ブログエントリの日付変換を
parseDateToTimestamp()に統一: ノート・ログと同じ安全な変換方式をブログエントリにも適用。CF Workers V8でNaNになるケースを根本的に解消
重複排除ロジックの修正
- D1スラグベースの排除を撤廃: link URLベースの重複排除に一本化。D1スラグが残っていてもContent Collections記事がブロックされない
- link URLベースの重複排除を改善: 同一URLの記事が複数ソースから取得された場合、より新しい・有効な日付を持つエントリを優先
- 自己参照RSSの条件付き除外: Content Collectionsが正常動作(1件以上取得)している場合のみ
arismmn.pages.devのRSSをスキップ。Content Collectionsが0件の場合はフォールバックとして許可
学んだこと
- Cloudflare Workers V8 での
new Date()の挙動はNode.jsと異なり、タイムゾーンなし文字列で NaN を返す場合がある。Date.UTC()を使用して手動パースする方が安全 - 複数のデータソース間の重複排除は、最も単純で確実な方法(link URLベース)に一本化すべき。中間ステップでのスラグベース排除は障害点を増やすだけ
- フォールバック戦略は連鎖的に設計する必要がある。A→Bのフォールバックを設ける際、Bを除外する条件にはAの成否を含めるべき