fix: add concurrency validation for Ecto projections - #33
Conversation
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughThe PR adds comprehensive documentation for Ecto projections covering architecture, idempotency mechanisms, and configuration patterns. It restructures existing how-to guides with updated examples reflecting new module naming conventions and domain events. Additionally, concurrency validation logic is introduced to enforce a maximum concurrency of 1, with guidance to use batch_size instead. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
28ad85a to
b0ab1e7
Compare
84a91ca to
40caf96
Compare
40caf96 to
a5d8d74
Compare
5754362 to
c9a8230
Compare
c9a8230 to
ac8df89
Compare
ac8df89 to
78890f4
Compare
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
78890f4 to
ca4f988
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
lib/commanded/projections/ecto.ex (2)
89-117: Critical: Mutual exclusivity check also misses:subscription_opts[:concurrency].Same issue as
validate_concurrency_compatibility/1- this function only checks top-level:concurrency. This allows:use Commanded.Projections.Ecto, batch_size: 10, subscription_opts: [concurrency: 10] # Should error but passes!Apply this diff:
@doc false def validate_mutual_exclusivity(opts) do batch_size = Keyword.get(opts, :batch_size) - concurrency = Keyword.get(opts, :concurrency) + top_level = Keyword.get(opts, :concurrency) + nested = opts |> Keyword.get(:subscription_opts, []) |> Keyword.get(:concurrency) + concurrency = top_level || nested
131-159: Critical: Validation misses:concurrencyin:subscription_opts.The function only checks top-level
:concurrencybut doesn't validateopts[:subscription_opts][:concurrency]. Users following Commanded's event handler patterns can set concurrency within subscription_opts, completely bypassing this validation.This allows dangerous configurations like:
use Commanded.Projections.Ecto, batch_size: 10, subscription_opts: [concurrency: 4] # Silently bypasses validation!Apply this diff to check both locations:
@doc false def validate_concurrency_compatibility(opts) do - concurrency = Keyword.get(opts, :concurrency) + top_level = Keyword.get(opts, :concurrency) + nested = opts |> Keyword.get(:subscription_opts, []) |> Keyword.get(:concurrency) + concurrency = top_level || nested case concurrency do
🧹 Nitpick comments (1)
guides/howtos/building-read-models-with-ecto.md (1)
206-239: Consider using headings instead of bold text for options.The bold text for "Option 1:", "Option 2:", etc. could be converted to level-4 headings (####) for better document structure. This would also resolve the markdownlint warnings.
Example:
-**Option 1: Static schema prefix** +#### Option 1: Static schema prefixHowever, the current formatting is acceptable and may better suit the guide's structure.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
guides/explanations/ecto-projections.md(1 hunks)guides/explanations/read-model-projections.md(1 hunks)guides/howtos/building-read-models-with-ecto.md(1 hunks)guides/howtos/ecto-projections-getting-started.md(1 hunks)lib/commanded/projections/ecto.ex(4 hunks)test/projections/ecto_projection_test.exs(1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
guides/howtos/building-read-models-with-ecto.md
206-206: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
216-216: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
229-229: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
267-267: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
290-290: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Quality Assurance (1.18.x, 27)
🔇 Additional comments (6)
guides/howtos/ecto-projections-getting-started.md (1)
75-75: LGTM!The updated documentation references provide clear navigation to both practical examples and architectural details.
guides/explanations/ecto-projections.md (2)
92-123: Excellent explanation of the concurrency limitation.The timeline diagram clearly illustrates the race condition and data loss scenario. The guidance to use
:batch_sizeinstead provides a practical alternative.
61-91: LGTM!The batch processing section clearly explains the workflow, benefits, and trade-offs. The step-by-step breakdown is particularly helpful for understanding the mechanism.
lib/commanded/projections/ecto.ex (1)
64-79: LGTM!The concurrency limitation documentation is clear and provides actionable guidance. The warning block effectively communicates the data loss risk.
guides/howtos/building-read-models-with-ecto.md (1)
1-365: LGTM!The guide updates provide concrete, practical examples with realistic domain events and module names. The restructured content with batch processing, error handling, and multi-tenancy examples significantly improves the guide's utility.
guides/explanations/read-model-projections.md (1)
7-7: LGTM!The updated references provide comprehensive navigation to all three relevant documentation resources.
Note
Adds compile-time validation blocking :concurrency > 1 for Ecto projections (with clearer errors and batch compatibility), updates guides, and adds tests.
lib/commanded/projections/ecto.ex)::concurrencyvalidation (validate_concurrency_compatibility/1), rejecting values > 1 and invalid types; allowconcurrency: 1.batch_sizewithconcurrency: 1; error when:concurrency > 1with/without:batch_size.:batch_size.__using__/1; improve error messages.guides/explanations/ecto-projections.md(architecture, idempotency, batching, no-concurrency rationale).test/projections/ecto_projection_test.exs):concurrency: 1, absence of option, rejection of> 1, mutual exclusivity withbatch_size, and invalid values (atom, string, list, 0, negative).:batch_sizealternative).Written by Cursor Bugbot for commit ca4f988. This will update automatically on new commits. Configure here.