`async_count` が `limit(0)` のとき Promise を返さない不具合を修正

rails/rails

Post.limit(0).async_countActiveRecord::Promise ではなく生の整数 0 を返していたバグが修正されました。これにより、async_count の戻り値の型が常に Promise であるという契約が保たれます。

背景

execute_simple_calculationlimit(0) 高速パスが、非同期処理のラップより先に早期リターンしていたことが原因です。async_countActiveRecord::Promise を返すと文書化されていますが、limit_value == 0 の条件を満たすと整数 0 がそのまま返されていました。その結果、呼び出し元が Integer を受け取るケースが生じ、valuethenpending? といった Promise のメソッドが使えない状態になっていました。

PR 本文によれば、この問題は矛盾する非同期集計(contradicted async aggregations)の早期リターンで修正されたケースと同種のものです。limit(0) という別の高速パスにも同じ不整合が残っていた形です。

技術的な変更

execute_simple_calculationlimit(0) 早期リターン箇所が、非同期モードの場合に Promise::Complete を返すよう1行修正されました。

変更前:

return 0 if limit_value == 0

変更後:

return @async ? Promise::Complete.new(0) : 0 if limit_value == 0

@async フラグで同期・非同期を分岐し、同期の count は従来通り整数 0 を即時返します。非同期の async_count では Promise::Complete.new(0) を返すことで、値が確定済みの Promise としてラップされます。これにより、DBへのクエリを発行しないというパフォーマンス上の高速パスは維持しつつ、インターフェースの一貫性が確保されます。

テストは既存の test_count_should_shortcut_with_limit_zero を拡張し、assert_no_queries ブロック内に assert_async_equal 0, accounts.async_count を追加しています。ノークエリであるという期待はそのまま維持されており、Promise の値が 0 であることも同時に検証します。

設計判断

既存の高速パスを壊さずに型の契約を満たすという方針が採られました。

Promise::Complete は値が既に確定している Promise を表すクラスです。DB アクセスなしに結果が自明な limit(0) のケースでは、非同期処理をスケジュールせず即座に完了済みの Promise を構築することが、「ノークエリ」という最適化と「必ず Promise を返す」というインターフェース契約の両立に最も適しています。@async フラグによる1行の三項演算子で済む最小限の変更であり、既存の同期パスには一切影響を与えません。

まとめ

limit(0) という特殊ケースで async_countPromise を返さないという型契約の破れが、1行の修正で解消されました。Promise::Complete を使って確定済みの結果をラップするパターンは、非同期インターフェースの一貫性を保つ上で参考になる設計判断です。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
84d296f5

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文、背景、技術的な変更、設計判断、まとめの各要素が揃っており、「総論→各論→結論」の構成が明確で素晴らしいです。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライト、PR番号のリンク記法共に正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

ActiveRecordの内部実装に関する用語が適切に使用されており、専門知識を持つエンジニアという対象読者に適合しています。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論から始まる構成になっており、段落もトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が遵守されています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

コード変更とファイルパスがDiff情報と完全に一致しています。テストコードの変更に関する説明も正確です。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

PR情報で言及されている `ActiveRecord::Promise` や、Diffから読み取れる `Promise::Complete` などの技術用語が正確に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

バグの原因、修正内容、修正による効果(高速パスの維持)など、すべての技術的な説明がPR情報とDiffによって裏付けられており、正確です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張がPRのDescriptionやDiffの内容に基づいており、ハルシネーションは見られません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#57501)が正確に記載・リンクされています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトルはPRの主題「Return a completed promise for async_count with limit(0)」を的確に要約しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

PR情報に記載のないバージョン情報やリリース予定などの外部知識の追記はなく、提供された情報に忠実です。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

「...返していたバグが修正されました」など、過去の事象として時間表現が正確に使われています。