Skip to content

Add loom-based concurrency tests for push queues#360

Merged
leynos merged 5 commits intomainfrom
codex/implement-loom-concurrency-testing-with-unit-tests
Sep 17, 2025
Merged

Add loom-based concurrency tests for push queues#360
leynos merged 5 commits intomainfrom
codex/implement-loom-concurrency-testing-with-unit-tests

Conversation

@leynos
Copy link
Copy Markdown
Owner

@leynos leynos commented Sep 15, 2025

Summary

  • instrument PushHandle internals for loom by reusing std::sync arcs while swapping mutex and atomic types under cfg(loom)
  • add loom-focused tests for drop handling and queue-full errors in tests/advanced/concurrency_loom.rs and register the binary via Cargo.toml
  • document the new coverage in the async messaging design note and mark the roadmap item complete

Testing

  • make fmt
  • make lint
  • make test
  • RUSTFLAGS="--cfg loom" cargo test --features advanced-tests --test concurrency_loom
  • make nixie

https://chatgpt.com/codex/tasks/task_e_68c8353cf8dc8322badf7955fd73ff46

Summary by Sourcery

Introduce loom-based concurrency testing for PushQueues by instrumenting PushHandle, adding loom-specific tests, updating build config, and documenting the changes

New Features:

  • Add a PushHandleProbe under cfg(loom) to expose dead-letter queue drop counters for exhaustive interleaving checks

Build:

  • Add loom dependency under cfg(loom) and register the concurrency_loom test binary in Cargo.toml

Documentation:

  • Document loom-based probe and concurrency test suite in the asynchronous messaging design note
  • Mark loom concurrency testing milestone as complete in the roadmap

Tests:

  • Implement loom-focused concurrency tests for drop counter resets and deterministic queue-full errors in tests/advanced/concurrency_loom.rs

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Sep 15, 2025

Reviewer's Guide

This PR instruments PushHandle internals for loom-based testing by exposing a drop counter probe, introduces comprehensive loom concurrency tests for drop handling and queue-full errors (registered in Cargo.toml), and updates the design docs and roadmap to reflect the new coverage.

Class diagram for PushHandle and PushHandleProbe loom instrumentation

classDiagram
    class PushHandleInner {
        +dlq_drops: AtomicUsize
    }
    class PushHandle {
        +from_arc(arc: Arc<PushHandleInner<F>>): Self
        +probe(): PushHandleProbe<F> [loom only]
    }
    class PushHandleProbe {
        +dlq_drop_count(): usize
        inner: Arc<PushHandleInner<F>>
    }
    PushHandleInner <|-- PushHandle
    PushHandle "1" -- "1" PushHandleProbe: probe() [loom only]
    PushHandleProbe "1" -- "1" PushHandleInner: inner
Loading

File-Level Changes

Change Details Files
Instrument PushHandle for loom with an internal probe
  • Define PushHandleProbe under cfg(loom)
  • Implement dlq_drop_count() to read the atomic drop counter
  • Add probe() method to PushHandle to return the probe
src/push/queues/handle.rs
Add loom-based concurrency tests and register them
  • Rewrite tests/advanced/concurrency_loom.rs to use loom::model and loom threads
  • Add tests for DLQ drop counter reset and queue-full error determinism
  • Register the new concurrency_loom test and loom dependency in Cargo.toml
tests/advanced/concurrency_loom.rs
Cargo.toml
Document loom coverage in design note and roadmap
  • Add loom-based concurrency verification section in async messaging design docs
  • Mark loom-based testing item complete in the roadmap
docs/asynchronous-outbound-messaging-design.md
docs/roadmap.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Sep 15, 2025

Note

Other AI code review bot(s) detected

CodeRabbit 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.

Summary by CodeRabbit

  • New Features

    • None.
  • Tests

    • Added a loom-based concurrency test suite to deterministically validate queue fullness and DLQ accounting, replacing earlier async runtime tests.
  • Documentation

    • Expanded asynchronous outbound messaging design with loom verification details, probes, and a conceptual SessionRegistry for session discovery, including diagrams and examples.
    • Updated the roadmap to mark loom-based concurrency testing as complete.
  • Chores

    • Introduced conditional loom dependency and test configuration to enable loom-gated runs without affecting non-loom builds.

Walkthrough

Add a loom-gated dependency and test target, introduce loom-only sync re-exports and a PushHandle probe API, add a public SessionRegistry using Weak refs, and replace advanced concurrency tests with loom-based deterministic interleavings.

Changes

Cohort / File(s) Summary
Build configuration (loom gating)
Cargo.toml
Add [target.'cfg(loom)'.dependencies] loom = "0.7.2" and a [[test]] entry for tests/advanced/concurrency_loom.rs with required-features = ["advanced-tests"]; preserve non-loom/dev deps.
Push queues sync & probe
src/push/queues/mod.rs, src/push/queues/handle.rs
Add cfg(loom)/cfg(not(loom)) sync re-export module; introduce loom-only PushHandleProbe<F> holding Arc<PushHandleInner<F>>, PushHandle::probe() and dlq_drop_count() (SeqCst). Non-loom behaviour unchanged.
Session registry API
docs/asynchronous-outbound-messaging-design.md, src/... (design doc references)
Document and add public SessionRegistry<F> (internally DashMap<ConnectionId, Weak<PushHandleInner<F>>>) with get, insert, remove, active_handles APIs and lazy cleanup semantics.
Advanced loom tests (rewritten)
tests/advanced/concurrency_loom.rs
Replace Tokio-based tests with loom-based tests: concurrent_drops_reset_dlq_counter(#[case] priority), concurrent_queue_full_errors_are_reported, dlq_probe_ignores_absent_channel, dlq_probe_reports_zero_when_dlq_idle; gate by cfg(loom) and advanced-tests.
Docs / roadmap
docs/asynchronous-outbound-messaging-design.md, docs/roadmap.md
Add loom-based verification documentation and PushHandle probe description; mark loom-based concurrency testing as complete in roadmap.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant T1 as Loom Thread 1
  participant T2 as Loom Thread 2
  participant PQ as PushQueues
  participant DLQ as Dead-Letter Queue
  participant Probe as PushHandleProbe (loom)

  rect rgba(230,245,255,0.25)
    note over T1,T2: Loom explores interleavings
    T1->>PQ: try_push(msg1)
    T2->>PQ: try_push(msg2)
    alt Queue full -> error
      PQ-->>T1: Err(QueueFull)
      PQ-->>T2: Err(QueueFull)
    else Drop routed to DLQ
      PQ->>DLQ: enqueue dropped frame
      PQ->>Probe: increment dlq_drops (SeqCst)
    end
  end

  note right of Probe: Tests read Probe.dlq_drop_count() for assertions
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

Loom threads tug at race and time,
A probe counts drops in steady rhyme.
Weak refs watch sessions come and go,
Tests pin interleaves to and fro.
Docs tick done — the weave will show.

Act as an automated reviewer: list files with loom-gated changes and highlight any API additions that require documentation updates. 

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed Approve the title as it succinctly and accurately summarises the primary change: adding loom-based concurrency tests for push queues and associated instrumentation. Keep the title unchanged because it is concise, specific, and focused on the main change without noise. Use the PR description to surface any additional implementation details or references.
Description Check ✅ Passed Approve the description as it directly matches the changeset by describing loom instrumentation, new tests, Cargo.toml updates, and documentation changes. Keep the included test commands and summary because they aid reviewers and enable reproducing the loom-gated tests locally. Attach CI logs or test output in the PR conversation when available to demonstrate the loom-gated tests passed.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/implement-loom-concurrency-testing-with-unit-tests

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5dedb91 and 4bce3c9.

📒 Files selected for processing (1)
  • docs/asynchronous-outbound-messaging-design.md (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
docs/**/*.md

📄 CodeRabbit inference engine (docs/documentation-style-guide.md)

docs/**/*.md: Use British English based on the Oxford English Dictionary (en-oxendict) for documentation text.
The word "outwith" is acceptable in documentation.
Keep US spelling when used in an API, for example color.
Use the Oxford comma in documentation text.
Treat company names as collective nouns in documentation (e.g., "Lille Industries are expanding").
Write headings in sentence case in documentation.
Use Markdown headings (#, ##, ###, etc.) in order without skipping levels.
Follow markdownlint recommendations for Markdown files.
Provide code blocks and lists using standard Markdown syntax.
Always provide a language identifier for fenced code blocks; use plaintext for non-code text.
Use - as the first level bullet and renumber lists when items change.
Prefer inline links using [text](url) or angle brackets around the URL; avoid reference-style links like [foo][bar].
Ensure blank lines before and after bulleted lists and fenced blocks in Markdown.
Ensure tables have a delimiter line below the header row in Markdown.
Expand any uncommon acronym on first use, for example, Continuous Integration (CI).
Wrap paragraphs at 80 columns in documentation.
Wrap code at 120 columns in documentation.
Do not wrap tables in documentation.
Use sequentially numbered footnotes referenced with [^1] and place definitions at the end of the file.
Where it adds clarity, include Mermaid diagrams in documentation.
When embedding figures, use ![alt text](path/to/image) and provide concise alt text describing the content.
Add a brief description before each Mermaid diagram in documentation for screen readers.

Document examples showing how to deprecate old message versions gracefully

docs/**/*.md: Use docs/ markdown as the source of truth for requirements and decisions
Proactively update docs/ when requirements, dependencies, or architecture change
Documentation must use en-GB-oxendict spelling and grammar (LICENSE name exempt)

When long lines are warranted in ...

Files:

  • docs/asynchronous-outbound-messaging-design.md
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: Markdown paragraphs and bullet points must be wrapped at 80 columns
Markdown code blocks must be wrapped at 120 columns
Do not wrap tables and headings in Markdown
Use dashes (-) for list bullets in Markdown
Use GitHub-flavoured Markdown footnotes ([^1])

Files:

  • docs/asynchronous-outbound-messaging-design.md

⚙️ CodeRabbit configuration file

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-GB-oxendict (-ize / -our) spelling and grammar
  • Headings must not be wrapped.
  • Documents must start with a level 1 heading
  • Headings must correctly increase or decrease by no more than one level at a time
  • Use GitHub-flavoured Markdown style for footnotes and endnotes.
  • Numbered footnotes must be numbered by order of appearance in the document.

Files:

  • docs/asynchronous-outbound-messaging-design.md
docs/**

📄 CodeRabbit inference engine (docs/wireframe-1-0-detailed-development-roadmap.md)

docs/**: Document async-stream as the canonical way to create streams imperatively
Write comprehensive user guides for Duplex Messaging & Pushes, Streaming Responses, and Message Fragmentation with runnable examples

Files:

  • docs/asynchronous-outbound-messaging-design.md
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build-test
  • GitHub Check: Sourcery review
🔇 Additional comments (3)
docs/asynchronous-outbound-messaging-design.md (3)

481-491: Loom subsection reads correctly; keep as-is.

Comply with docs rules: en‑GB spelling, sentence‑case heading level, Oxford comma, no first/second‑person, and 80‑column wrapping. Language identifiers and blank lines around fenced blocks are correct in this subsection.


493-501: Example code is clear and scoped under cfg(loom).

The illustrative snippet imports the probe type via its public path and shows probe() and dlq_drop_count() usage succinctly. No changes needed.


481-506: Verify loom-gated PushHandleProbe, PushHandle::probe(), and the concurrency_loom test.

Cargo.toml shows loom entries but the previous rg run errored; run the corrected checks below and paste the output.

#!/usr/bin/env bash
set -euo pipefail

echo "=== Cargo.toml: loom entries ==="
if [ -f Cargo.toml ]; then
  grep -nE "^\s*loom\s*=" Cargo.toml || true
  grep -n "cfg(loom)" Cargo.toml || true
else
  echo "Cargo.toml not found at repo root"
fi

echo "=== Search for PushHandleProbe struct and cfg(loom) near it ==="
python3 - <<'PY'
import os,re
root='.'
probe_struct=re.compile(r'\bstruct\s+PushHandleProbe\b')
cfg_attr=re.compile(r'\#\s*\[\s*cfg\s*\(\s*loom\s*\)\s*\]')
impl_push=re.compile(r'\bimpl\b[^{]*\bPushHandle\b')
probe_fn=re.compile(r'\bfn\s+probe\b|\bprobe\s*\(')
found_struct=False
found_probe=False
found_test=False
for dirpath,dirnames,filenames in os.walk(root):
    parts = dirpath.split(os.sep)
    if 'target' in parts or '.git' in parts:
        continue
    for fname in filenames:
        if not fname.endswith('.rs'):
            continue
        path=os.path.join(dirpath,fname)
        try:
            text=open(path,encoding='utf-8',errors='ignore').read()
        except:
            continue
        if probe_struct.search(text):
            found_struct=True
            print("STRUCT:",path)
            lines=text.splitlines()
            for i,line in enumerate(lines):
                if 'struct PushHandleProbe' in line:
                    start=max(0,i-5)
                    end=i+3
                    print('\\n'.join(lines[start:end]))
                    break
            idx = None
            for i,line in enumerate(lines):
                if 'struct PushHandleProbe' in line:
                    idx=i; break
            if idx is not None:
                before = '\\n'.join(lines[max(0,idx-5):idx])
                if cfg_attr.search(before):
                    print("Found #[cfg(loom)] within 5 lines before struct")
        if impl_push.search(text):
            for m in impl_push.finditer(text):
                snippet=text[m.end():m.end()+1200]
                if probe_fn.search(snippet):
                    print("PROBE_METHOD in impl PushHandle:",path)
                    found_probe=True
        if fname == 'concurrency_loom.rs' or 'concurrency_loom' in text:
            print("POSSIBLE_TEST:",path)
            found_test=True

print("SUMMARY: PushHandleProbe:", found_struct, "probe():", found_probe, "concurrency_loom:", found_test)
PY

echo "=== Check Cargo [[test]] registration (optional) ==="
grep -n '^\[\[test\]\]' Cargo.toml || true
grep -n "concurrency_loom" Cargo.toml || true

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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

codescene-delta-analysis[bot]

This comment was marked as outdated.

sourcery-ai[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bde29c3 and 2cae82e.

📒 Files selected for processing (6)
  • Cargo.toml (2 hunks)
  • docs/asynchronous-outbound-messaging-design.md (1 hunks)
  • docs/roadmap.md (1 hunks)
  • src/push/queues/handle.rs (2 hunks)
  • src/push/queues/mod.rs (1 hunks)
  • tests/advanced/concurrency_loom.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
Cargo.toml

📄 CodeRabbit inference engine (AGENTS.md)

Cargo.toml: Use explicit version ranges in Cargo.toml; keep dependencies up to date
All dependencies in Cargo.toml must use caret (^) SemVer-compatible requirements (e.g., "1.2.3")
Forbid wildcard (*) and open-ended (>=) versions; use ~ only with a specific documented reason

Files:

  • Cargo.toml
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Use precise names; boolean names should start with is/has/should
Use en-GB-oxendict spelling and grammar in comments
Function documentation must include clear examples; test documentation should omit redundant examples
Keep code files ≤ 400 lines; split long switch/dispatch logic by feature; move large test data to external files
Disallow Clippy warnings
Fix warnings emitted during tests in code rather than silencing them
Extract helper functions for long functions; adhere to separation of concerns and CQRS
Group related parameters into meaningful structs when functions have many parameters
Consider using Arc for large error returns to reduce data size
Each Rust module must begin with a module-level //! comment describing purpose and utility
Document public APIs with Rustdoc /// comments to enable cargo doc generation
Prefer immutable data; avoid unnecessary mut
Handle errors with Result instead of panicking where feasible
Avoid unsafe code unless necessary and document any usage clearly
Place function attributes after doc comments
Do not use return in single-line functions
Use predicate functions for conditional criteria with more than two branches
Do not silence lints except as a last resort
Lint suppressions must be tightly scoped and include a clear reason
Prefer #[expect(..)] over #[allow(..)] for lints
Prefer .expect() over .unwrap()
Use concat!() to combine long string literals rather than escaping newlines
Prefer single-line function bodies where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) })
Prefer semantic error enums deriving std::error::Error via thiserror for inspectable conditions

Files:

  • src/push/queues/mod.rs
  • tests/advanced/concurrency_loom.rs
  • src/push/queues/handle.rs

⚙️ CodeRabbit configuration file

**/*.rs: * Seek to keep the cyclomatic complexity of functions no more than 12.

  • Adhere to single responsibility and CQRS

  • Place function attributes after doc comments.

  • Do not use return in single-line functions.

  • Move conditionals with >2 branches into a predicate function.

  • Avoid unsafe unless absolutely necessary.

  • Every module must begin with a //! doc comment that explains the module's purpose and utility.

  • Comments and docs must follow en-GB-oxendict (-ize / -our) spelling and grammar

  • Lints must not be silenced except as a last resort.

    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.

  • Use rstest fixtures for shared setup and to avoid repetition between tests.

  • Replace duplicated tests with #[rstest(...)] parameterised cases.

  • Prefer mockall for mocks/stubs.

  • Prefer .expect() over .unwrap()

  • Ensure that any API or behavioural changes are reflected in the documentation in docs/

  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/

  • Files must not exceed 400 lines in length

    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such

    • For testing of functionality depending upon environment variables, dependency injection and the mockable crate are the preferred option.
    • If mockable cannot be used, env mutations in tests ...

Files:

  • src/push/queues/mod.rs
  • tests/advanced/concurrency_loom.rs
  • src/push/queues/handle.rs
{src,tests}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Write unit and behavioural tests for new functionality

Files:

  • src/push/queues/mod.rs
  • tests/advanced/concurrency_loom.rs
  • src/push/queues/handle.rs
docs/**/*.md

📄 CodeRabbit inference engine (docs/documentation-style-guide.md)

docs/**/*.md: Use British English based on the Oxford English Dictionary (en-oxendict) for documentation text.
The word "outwith" is acceptable in documentation.
Keep US spelling when used in an API, for example color.
Use the Oxford comma in documentation text.
Treat company names as collective nouns in documentation (e.g., "Lille Industries are expanding").
Write headings in sentence case in documentation.
Use Markdown headings (#, ##, ###, etc.) in order without skipping levels.
Follow markdownlint recommendations for Markdown files.
Provide code blocks and lists using standard Markdown syntax.
Always provide a language identifier for fenced code blocks; use plaintext for non-code text.
Use - as the first level bullet and renumber lists when items change.
Prefer inline links using [text](url) or angle brackets around the URL; avoid reference-style links like [foo][bar].
Ensure blank lines before and after bulleted lists and fenced blocks in Markdown.
Ensure tables have a delimiter line below the header row in Markdown.
Expand any uncommon acronym on first use, for example, Continuous Integration (CI).
Wrap paragraphs at 80 columns in documentation.
Wrap code at 120 columns in documentation.
Do not wrap tables in documentation.
Use sequentially numbered footnotes referenced with [^1] and place definitions at the end of the file.
Where it adds clarity, include Mermaid diagrams in documentation.
When embedding figures, use ![alt text](path/to/image) and provide concise alt text describing the content.
Add a brief description before each Mermaid diagram in documentation for screen readers.

Document examples showing how to deprecate old message versions gracefully

docs/**/*.md: Use docs/ markdown as the source of truth for requirements and decisions
Proactively update docs/ when requirements, dependencies, or architecture change
Documentation must use en-GB-oxendict spelling and grammar (LICENSE name exempt)

When long lines are warranted in ...

Files:

  • docs/roadmap.md
  • docs/asynchronous-outbound-messaging-design.md
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: Markdown paragraphs and bullet points must be wrapped at 80 columns
Markdown code blocks must be wrapped at 120 columns
Do not wrap tables and headings in Markdown
Use dashes (-) for list bullets in Markdown
Use GitHub-flavoured Markdown footnotes ([^1])

Files:

  • docs/roadmap.md
  • docs/asynchronous-outbound-messaging-design.md

⚙️ CodeRabbit configuration file

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-GB-oxendict (-ize / -our) spelling and grammar
  • Headings must not be wrapped.
  • Documents must start with a level 1 heading
  • Headings must correctly increase or decrease by no more than one level at a time
  • Use GitHub-flavoured Markdown style for footnotes and endnotes.
  • Numbered footnotes must be numbered by order of appearance in the document.

Files:

  • docs/roadmap.md
  • docs/asynchronous-outbound-messaging-design.md
docs/**

📄 CodeRabbit inference engine (docs/wireframe-1-0-detailed-development-roadmap.md)

docs/**: Document async-stream as the canonical way to create streams imperatively
Write comprehensive user guides for Duplex Messaging & Pushes, Streaming Responses, and Message Fragmentation with runnable examples

Files:

  • docs/roadmap.md
  • docs/asynchronous-outbound-messaging-design.md
tests/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

tests/**/*.rs: Use rstest fixtures for shared setup
Replace duplicated tests with #[rstest(...)] parameterised cases
Prefer mockall for mocks/stubs

Files:

  • tests/advanced/concurrency_loom.rs
🧬 Code graph analysis (1)
tests/advanced/concurrency_loom.rs (4)
tests/connection_actor_errors.rs (1)
  • queues (30-36)
src/push/queues/mod.rs (2)
  • builder (115-115)
  • new (92-109)
tests/support.rs (1)
  • builder (8-10)
src/push/queues/handle.rs (2)
  • probe (74-78)
  • dlq_drop_count (66-66)
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Sourcery review
🔇 Additional comments (9)
docs/roadmap.md (1)

177-178: Roadmap item completion confirmed.

The Phase 5 loom-based concurrency testing item has been correctly marked as complete, aligning with the implementation in tests/advanced/concurrency_loom.rs.

Cargo.toml (2)

113-116: Test configuration looks good.

The new concurrency_loom test entry is properly configured with the correct path and required features.


71-73: Approve: loom version consistency verified

Both entries use loom = "0.7.2" (Cargo.toml lines 52 and 72). No action required.

src/push/queues/mod.rs (1)

9-20: Conditional compilation structure is correct.

The cfg-gated imports properly separate loom and non-loom synchronisation primitives whilst maintaining Arc availability in both configurations.

src/push/queues/handle.rs (2)

3-21: Well-structured loom instrumentation.

The conditional sync module elegantly abstracts synchronisation primitives between loom and standard implementations, maintaining API compatibility whilst enabling deterministic concurrency testing.


56-67: Probe API provides clean testing interface.

The PushHandleProbe struct and its dlq_drop_count() method offer a minimal, focused API for loom-based verification without polluting the production interface.

tests/advanced/concurrency_loom.rs (3)

1-10: Module documentation accurately describes test scope.

The documentation clearly explains the purpose of these loom-based tests and their focus on DLQ accounting and queue-full error handling.


12-59: Robust DLQ counter reset verification.

The test effectively validates that the DLQ drop counter resets after reaching the logging threshold, with proper deterministic verification of dropped frames.


61-97: Queue-full error handling properly tested.

The test correctly verifies that concurrent producers receive QueueFull errors when attempting to push to a full queue with ReturnErrorIfFull policy.

Comment thread docs/asynchronous-outbound-messaging-design.md
Comment thread src/push/queues/handle.rs
Comment thread tests/advanced/concurrency_loom.rs
codescene-delta-analysis[bot]

This comment was marked as outdated.

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
docs/asynchronous-outbound-messaging-design.md (1)

483-491: Remove first‑person pronouns per docs style; rephrase the loom subsection.

Align with the docs guidelines and avoid “we”.

- To reason about concurrent producers we added a loom-specific probe to
- `PushHandle`. The probe exposes the dead-letter queue drop counter when tests
+ To reason about concurrent producers, a loom-specific probe was added to
+ `PushHandle`. The probe exposes the dead-letter queue drop counter when tests
   are compiled with `--cfg loom`. The `tests/advanced/concurrency_loom.rs` suite
   drives `PushHandle::try_push` from multiple `loom::thread`s to assert that drop
   counts reset after the logging threshold across both priority queues, that
   queue-full errors remain deterministic, and that the probe reports zero when
   the DLQ is absent or idle. This keeps the production API unchanged whilst
   enabling exhaustive interleaving checks during the advanced test workflow.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2cae82e and 20b9d57.

📒 Files selected for processing (3)
  • docs/asynchronous-outbound-messaging-design.md (1 hunks)
  • src/push/queues/handle.rs (2 hunks)
  • tests/advanced/concurrency_loom.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Use precise names; boolean names should start with is/has/should
Use en-GB-oxendict spelling and grammar in comments
Function documentation must include clear examples; test documentation should omit redundant examples
Keep code files ≤ 400 lines; split long switch/dispatch logic by feature; move large test data to external files
Disallow Clippy warnings
Fix warnings emitted during tests in code rather than silencing them
Extract helper functions for long functions; adhere to separation of concerns and CQRS
Group related parameters into meaningful structs when functions have many parameters
Consider using Arc for large error returns to reduce data size
Each Rust module must begin with a module-level //! comment describing purpose and utility
Document public APIs with Rustdoc /// comments to enable cargo doc generation
Prefer immutable data; avoid unnecessary mut
Handle errors with Result instead of panicking where feasible
Avoid unsafe code unless necessary and document any usage clearly
Place function attributes after doc comments
Do not use return in single-line functions
Use predicate functions for conditional criteria with more than two branches
Do not silence lints except as a last resort
Lint suppressions must be tightly scoped and include a clear reason
Prefer #[expect(..)] over #[allow(..)] for lints
Prefer .expect() over .unwrap()
Use concat!() to combine long string literals rather than escaping newlines
Prefer single-line function bodies where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) })
Prefer semantic error enums deriving std::error::Error via thiserror for inspectable conditions

Files:

  • src/push/queues/handle.rs
  • tests/advanced/concurrency_loom.rs

⚙️ CodeRabbit configuration file

**/*.rs: * Seek to keep the cyclomatic complexity of functions no more than 12.

  • Adhere to single responsibility and CQRS

  • Place function attributes after doc comments.

  • Do not use return in single-line functions.

  • Move conditionals with >2 branches into a predicate function.

  • Avoid unsafe unless absolutely necessary.

  • Every module must begin with a //! doc comment that explains the module's purpose and utility.

  • Comments and docs must follow en-GB-oxendict (-ize / -our) spelling and grammar

  • Lints must not be silenced except as a last resort.

    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.

  • Use rstest fixtures for shared setup and to avoid repetition between tests.

  • Replace duplicated tests with #[rstest(...)] parameterised cases.

  • Prefer mockall for mocks/stubs.

  • Prefer .expect() over .unwrap()

  • Ensure that any API or behavioural changes are reflected in the documentation in docs/

  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/

  • Files must not exceed 400 lines in length

    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such

    • For testing of functionality depending upon environment variables, dependency injection and the mockable crate are the preferred option.
    • If mockable cannot be used, env mutations in tests ...

Files:

  • src/push/queues/handle.rs
  • tests/advanced/concurrency_loom.rs
{src,tests}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Write unit and behavioural tests for new functionality

Files:

  • src/push/queues/handle.rs
  • tests/advanced/concurrency_loom.rs
tests/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

tests/**/*.rs: Use rstest fixtures for shared setup
Replace duplicated tests with #[rstest(...)] parameterised cases
Prefer mockall for mocks/stubs

Files:

  • tests/advanced/concurrency_loom.rs
docs/**/*.md

📄 CodeRabbit inference engine (docs/documentation-style-guide.md)

docs/**/*.md: Use British English based on the Oxford English Dictionary (en-oxendict) for documentation text.
The word "outwith" is acceptable in documentation.
Keep US spelling when used in an API, for example color.
Use the Oxford comma in documentation text.
Treat company names as collective nouns in documentation (e.g., "Lille Industries are expanding").
Write headings in sentence case in documentation.
Use Markdown headings (#, ##, ###, etc.) in order without skipping levels.
Follow markdownlint recommendations for Markdown files.
Provide code blocks and lists using standard Markdown syntax.
Always provide a language identifier for fenced code blocks; use plaintext for non-code text.
Use - as the first level bullet and renumber lists when items change.
Prefer inline links using [text](url) or angle brackets around the URL; avoid reference-style links like [foo][bar].
Ensure blank lines before and after bulleted lists and fenced blocks in Markdown.
Ensure tables have a delimiter line below the header row in Markdown.
Expand any uncommon acronym on first use, for example, Continuous Integration (CI).
Wrap paragraphs at 80 columns in documentation.
Wrap code at 120 columns in documentation.
Do not wrap tables in documentation.
Use sequentially numbered footnotes referenced with [^1] and place definitions at the end of the file.
Where it adds clarity, include Mermaid diagrams in documentation.
When embedding figures, use ![alt text](path/to/image) and provide concise alt text describing the content.
Add a brief description before each Mermaid diagram in documentation for screen readers.

Document examples showing how to deprecate old message versions gracefully

docs/**/*.md: Use docs/ markdown as the source of truth for requirements and decisions
Proactively update docs/ when requirements, dependencies, or architecture change
Documentation must use en-GB-oxendict spelling and grammar (LICENSE name exempt)

When long lines are warranted in ...

Files:

  • docs/asynchronous-outbound-messaging-design.md
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: Markdown paragraphs and bullet points must be wrapped at 80 columns
Markdown code blocks must be wrapped at 120 columns
Do not wrap tables and headings in Markdown
Use dashes (-) for list bullets in Markdown
Use GitHub-flavoured Markdown footnotes ([^1])

Files:

  • docs/asynchronous-outbound-messaging-design.md

⚙️ CodeRabbit configuration file

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-GB-oxendict (-ize / -our) spelling and grammar
  • Headings must not be wrapped.
  • Documents must start with a level 1 heading
  • Headings must correctly increase or decrease by no more than one level at a time
  • Use GitHub-flavoured Markdown style for footnotes and endnotes.
  • Numbered footnotes must be numbered by order of appearance in the document.

Files:

  • docs/asynchronous-outbound-messaging-design.md
docs/**

📄 CodeRabbit inference engine (docs/wireframe-1-0-detailed-development-roadmap.md)

docs/**: Document async-stream as the canonical way to create streams imperatively
Write comprehensive user guides for Duplex Messaging & Pushes, Streaming Responses, and Message Fragmentation with runnable examples

Files:

  • docs/asynchronous-outbound-messaging-design.md
🧬 Code graph analysis (1)
tests/advanced/concurrency_loom.rs (2)
src/push/queues/mod.rs (2)
  • builder (115-115)
  • new (92-109)
src/push/queues/handle.rs (2)
  • probe (78-82)
  • dlq_drop_count (66-66)
🔍 Remote MCP Deepwiki

Summary of additional repo/docs context relevant to reviewing PR #360 (loom instrumentation + SessionRegistry)

  • Cargo/test changes

    • Cargo.toml: adds a cfg(loom) dependency entry for loom and registers a new test binary [[test]] concurrency_loom (tests/advanced/concurrency_loom.rs; required-features = ["advanced-tests"]). Reviewer action: confirm there are no conflicting/duplicate loom entries or version mismatches (dev-deps vs target.'cfg(loom)') and that CI will run the test with RUSTFLAGS="--cfg loom".
  • PushHandle / loom probe instrumentation

    • A loom-only PushHandleProbe (pub behind #[cfg(loom)]) and PushHandle::probe() were added in src/push/queues/handle.rs; dlq_drop_count reads an AtomicUsize (SeqCst). A cfg-gated internal sync module re-exports Mutex/atomic types vs non-loom std variants. Reviewer action: verify the #[cfg(loom)] gating is complete (no accidental production exposure) and the probe only observes internal state (no behavioral change).
  • Synchronization primitive strategy (important)

    • PR summary/doc indicates std::sync::Arc is reused while Mutex/Atomic types are swapped under cfg(loom). Reviewer action: confirm this choice is intentional — using std::sync::Arc under loom can reduce loom’s ability to model Arc-related interleavings; consider whether Arc/Weak should also use loom::sync when cfg(loom) to ensure full loom coverage.
  • SessionRegistry public API

    • Docs & design describe SessionRegistry backed by DashMap<ConnectionId, Weak<PushHandleInner>> with methods get/insert/remove/active_handles and lazy cleanup (upgrade Weak -> Arc during get, prune stale entries). Reviewer action: verify implementation uses Arc::downgrade for insert, properly upgrades/prunes in get/active_handles, and that trait bounds (Send/Sync) and lifetimes are correct for use from background tasks.
  • Tests converted to loom

    • tests/advanced/concurrency_loom.rs migrates earlier Tokio-based concurrency tests to loom::thread and asserts deterministic DLQ accounting and queue-full error behavior. Reviewer action: ensure tests do not rely on non-loom synchronization or Tokio runtime primitives and that they exercise the intended interleavings (especially where the Arc/Weak choice may matter). Also confirm the test binary is wired so running Cargo with RUSTFLAGS="--cfg loom" builds what it expects.
  • Docs / roadmap updates

    • docs/asynchronous-outbound-messaging-design.md documents the loom probe and the SessionRegistry API; docs/roadmap.md marks the loom test item complete. Reviewer action: ensure documentation matches the implemented behavior and public surface (visibility, method signatures).

Notes for the reviewer (high priority)

  • Double-check the sync re-export strategy: if you want exhaustive loom modeling, prefer using loom::sync::{Arc, Weak, Mutex, atomic::AtomicUsize} under cfg(loom) rather than only switching mutex/atomics. This is the highest-risk correctness/coverage question.
  • Confirm Cargo.toml/CI: ensure CI runs the loom test with the required RUSTFLAGS and that duplicate loom declarations (dev-deps vs target cfg) don’t cause resolver/warning issues.
  • Confirm SessionRegistry’s upgrade/prune semantics are robust under concurrent access and that active_handles() does not produce surprising strong references that prolong connections.

Sources used

  • Repository wiki/docs & file summaries.,
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-test
🔇 Additional comments (8)
src/push/queues/handle.rs (3)

56-67: LGTM: probe type is minimal and correctly gated.

The loom-only probe encapsulates internals without surfacing to production; SeqCst load is appropriate for test determinism.


72-83: LGTM: probe() API is correctly gated and documented.

Method is #[must_use], returns a cheap clone, and preserves production surface.

Confirm that re-exports expose PushHandleProbe at the documented path used in tests/docs.


3-11: Use loom::sync::Arc/Weak under cfg(loom).

Replace std::sync::{Arc, Weak} with loom::sync::{Arc, Weak} in the #[cfg(loom)] shim so loom can model-check Arc/Weak interleavings.

Apply:

 #[cfg(loom)]
 mod sync {
-    pub use std::sync::{Arc, Weak};
-
-    pub use loom::sync::{
-        Mutex,
-        atomic::{AtomicUsize, Ordering},
-    };
+    pub use loom::sync::{
+        Arc,
+        Weak,
+        Mutex,
+        atomic::{AtomicUsize, Ordering},
+    };
 }

rg found std::sync::Arc usages in:

  • src/server/config/mod.rs:38 (code)
  • src/hooks.rs:7 (use)
    Other matches are doc/examples (src/extractor.rs, src/app/builder.rs, src/server/runtime.rs). Ensure none of these are compiled under cfg(loom); replace with loom::sync::{Arc, Weak} where they are.

Run this to verify no std::sync::Arc/Weak remain in loom-compiled code:

#!/bin/bash
set -eu
rg -nP --type=rust '\bstd::sync::(Arc|Weak)\b' src | sed 's/^/std-arc-usage: /'
rg -l --type=rust '\bstd::sync::(Arc|Weak)\b' src | sort -u | while read -r f; do
  if rg -n --type=rust '#\s*\[cfg\(loom\)\]' "$f" >/dev/null; then
    echo "loom-compiled-std-arc: $f"
  fi
done
tests/advanced/concurrency_loom.rs (5)

13-65: LGTM: parameterised DLQ drop/reset test covers both priorities.

Test sets a deterministic logging threshold, forces two drops, then asserts post‑reset state and DLQ contents.

Ensure this test remains stable if DLQ logging interval logic changes; gate the reset solely on the N‑multiple path as done here.


67-112: LGTM: queue‑full errors under higher contention are asserted.

Three producers with a full buffer correctly observe QueueFull without relying on Tokio runtime.


114-143: LGTM: DLQ‑disabled probe case validates zero drops.

Probe semantics remain zero when DLQ is disabled and a drop occurs.


145-171: LGTM: probe reports zero when DLQ exists but is idle.

Covers the idle path, ensuring no spurious accounting.


1-12: Enable Tokio's "loom" feature under cfg(loom) so tokio::sync::mpsc is instrumented.

Add to Cargo.toml (match your existing Tokio version):

[target.'cfg(loom)'.dependencies]
tokio = { version = "1", features = ["sync", "loom"] }

Verify configuration:

# Expect a [target.'cfg(loom)'.dependencies] section with tokio features including "loom".
rg -n "^\[target\.'cfg\(loom\)'\.dependencies\]" Cargo.toml || true
rg -n "tokio.*features.*loom" Cargo.toml || true
rg -n "tokio" Cargo.toml || true

Previous automated check produced no matches; confirm Cargo.toml manually.

Comment thread docs/asynchronous-outbound-messaging-design.md Outdated
codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos leynos merged commit 8fa1554 into main Sep 17, 2025
6 checks passed
@leynos leynos deleted the codex/implement-loom-concurrency-testing-with-unit-tests branch September 17, 2025 12:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant