Skip to content

Inbox held-transaction batch send: true multi-row insert (SQL Server + PostgreSQL) (#167)#169

Merged
blehnen merged 9 commits into
masterfrom
phase-1-inbox-batch
Jun 30, 2026
Merged

Inbox held-transaction batch send: true multi-row insert (SQL Server + PostgreSQL) (#167)#169
blehnen merged 9 commits into
masterfrom
phase-1-inbox-batch

Conversation

@blehnen

@blehnen blehnen commented Jun 30, 2026

Copy link
Copy Markdown
Owner

Summary

Follow-up to #162. Gives the inbox held-transaction batch send path
(Send(List<...>, DbTransaction) with EnableHoldTransactionUntilMessageCommitted) a
true multi-row insert inside the caller's transaction, for SQL Server and
PostgreSQL
. Previously this path looped single-row SendOne per message; now it
dispatches a single RelationalSendMessageCommandBatch to the batch handler, which
reuses the caller's connection/transaction.

Closes #167.

What changed

  • Handlers (SQL Server + PostgreSQL, sync + async): fork on
    RelationalSendMessageCommandBatch.ExternalTransaction. When set, HandleExternalTransaction[Async]
    reuses the caller's SqlConnection/SqlTransaction (resp. NpgsqlConnection/NpgsqlTransaction)
    via the existing ProcessChunk/ProcessChunkAsync — no Open/BeginTransaction/Commit/Rollback/
    Dispose/Close and no catch wrapper. The fork sits after GuardNoScheduledJobs, so scheduled-job
    batches are still rejected on this path. The standalone/outbox batch path is unchanged.
  • Producers (SqlServerRelationalProducerQueue, PostgreSqlRelationalProducerQueue): the
    SendWithExternalTransactionBatch[Async] overrides validate once at the boundary, then dispatch a
    single RelationalSendMessageCommandBatch instead of looping SendOne. Build-and-dispatch is
    factored into an internal DispatchBatch/DispatchBatchAsync seam (testability — see below).
    SendOne/SendOneAsync remain for the single-message overrides.

Behavior change

On the held-transaction batch path only, a failure now throws (the caller owns the
transaction's all-or-nothing semantics and the rollback) instead of being swallowed into per-message
results. The standalone Send(List<...>) path is unchanged (still reports HasErrors).

Scope / non-goals

  • SQLite is excluded by design — its single-writer model makes holding a transaction open across a
    batch non-viable (see Add outbox pattern support for SQLite (inbox not workable — single-writer lock) #149). Send(batch, transaction) throws InvalidOperationException on
    transports that don't override it (the base default), i.e. everything except SQL Server + PostgreSQL.
  • No public API surface changes. No DI registration changes — SimpleInjector auto-resolves the new
    producer ctor params, and RelationalSendMessageCommandBatch.SkipRetry keeps the retry decorator out
    of the caller's transaction.

Testing

  • Unit (26 pass, run locally): producer dispatches one batch command (not a SendOne loop), the
    command carries the caller's transaction, the producer never commits/rolls back the caller's
    transaction, async dispatch, exception propagation, and a non-Sql/Npgsql transaction throws without
    dispatching. (SqlTransaction/NpgsqlTransaction are sealed/unmockable, so dispatch is tested
    through the internal DispatchBatch seam; the cast guard is covered by the non-Sql/Npgsql tests.)
  • Integration (run on Jenkins / local connectionstring.txt): new SqlServerInboxBatchSendTests
    and PostgreSqlInboxBatchSendTests — commit → rows visible, rollback → rows absent, caller connection
    still open & usable after the call, forced failure throws (MetaData table dropped → meta insert fails),
    one distinct positive id per message, and (PG) a multi-chunk batch (BatchSize=2, 5 messages → 3
    chunks) asserting recovered ids are strictly increasing in caller input order across chunks within one
    external transaction.

Changelog

0.9.42 entry added.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added held-transaction batch send for caller-managed transactions in SQL Server and PostgreSQL.
    • Batch send now performs multi-row inserts and returns one output result per message, including distinct positive message ids.
  • Bug Fixes
    • Batch sends now fail fast: errors throw instead of being hidden as per-item results.
    • Caller-owned connections/transactions remain usable after Send; rollback prevents both inbox and related business rows from appearing.
    • In multi-chunk batches, returned message ids increase in the same order as input messages.
  • Documentation
    • Updated async batch/outbox guidance with correct try/catch rollback + transport support details.

blehnen and others added 8 commits June 30, 2026 12:40
… (sync + async)

Forks both SQL Server batch command handlers on RelationalSendMessageCommandBatch.ExternalTransaction:
the inbox held-transaction path reuses the caller's SqlConnection/SqlTransaction via the existing
ProcessChunk/ProcessChunkAsync with no Open/Begin/Commit/Rollback/Dispose/Close and no catch wrapper
(failures propagate; caller owns rollback). Fork sits after GuardNoScheduledJobs so scheduled-job
batches are still rejected. Standalone/outbox path unchanged.

Refs #167.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… (sync + async)

Mirrors the SQL Server fork for PostgreSQL: forks both batch handlers on
RelationalSendMessageCommandBatch.ExternalTransaction, reusing the caller's
NpgsqlConnection/NpgsqlTransaction via the existing ProcessChunk/ProcessChunkAsync
(unnest RETURNING + ascending-sort id recovery, _getTime already in scope) with no
Open/Begin/Commit/Rollback/Dispose/Close and no catch wrapper. Fork sits after
GuardNoScheduledJobs. Standalone/outbox path unchanged.

Refs #167.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SqlServerRelationalProducerQueue now injects the sync/async batch handlers and
dispatches one RelationalSendMessageCommandBatch (carrying the caller transaction)
for the held-transaction batch overrides, replacing the per-message SendOne loop.
Exceptions propagate (no per-message swallow). Build+dispatch factored into an
internal DispatchBatch/DispatchBatchAsync seam so dispatch behavior is unit-testable
(SqlTransaction is sealed/unmockable, so the cast guard stays covered by the
non-SqlTransaction tests; handler commit/rollback behavior is integration-tested).
No DI init change (SimpleInjector auto-resolves; SkipRetry bypasses the retry decorator).

Refs #167.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mirrors the SQL Server producer rewire for PostgreSQL: injects the sync/async batch
handlers, dispatches one RelationalSendMessageCommandBatch via internal DispatchBatch/
DispatchBatchAsync seam (exceptions propagate, no SendOne loop), keeps SendOne for
single-message overrides. 13 unit tests pass. No DI init change.

Refs #167.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…angelog

New SqlServerInboxBatchSendTests (held-transaction queue, enableHoldTransaction:true):
commit -> queue+business rows visible; rollback -> none visible; caller connection
still open and usable after send; forced failure (MetaData table dropped) throws
rather than swallowing; one distinct positive id per message. Changelog 0.9.42 entry
for #167. Integration tests run on Jenkins / local connectionstring.txt.

Refs #167.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New PostgreSqlInboxBatchSendTests mirroring the SQL Server inbox suite (commit/rollback
visibility, connection still usable, forced failure throws, one distinct id per message),
plus a multi-chunk test (BatchSize=2, 5 messages -> 3 chunks) asserting the unnest/RETURNING
ascending-sort id recovery yields strictly increasing ids in caller input order across
chunks inside one external transaction. Runs on Jenkins / local connectionstring.txt.

Refs #167.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Producers: restore empty-list short-circuit after validate/guard in both batch
  overrides (SQL Server + PostgreSQL) so an empty batch skips dispatch (Wave 2 review).
- Integration tests: forced-failure test rolls back in a finally (rollback error can't
  mask the assertion), comments clarify the failure originates at the meta insert
  (no pre-check), and a note explains the synchronous-rollback queue-count poll (Wave 3 review).

Refs #167.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Update docs/outbox-pattern.md batch sub-section: the caller-transaction batch overload
(SQL Server + PostgreSQL) now performs a true multi-row insert and throws on failure
(catch + rollback) instead of reporting per-message HasErrors. Note other transports
throw InvalidOperationException (SQLite single-writer); standalone Send(List<T>) still
uses HasErrors. Addresses documenter HIGH gap.

Refs #167.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 92bca05b-01a0-41ed-b07f-403e46c3887f

📥 Commits

Reviewing files that changed from the base of the PR and between da55301 and 6d4264d.

📒 Files selected for processing (3)
  • Source/DotNetWorkQueue.Transport.PostgreSQL.Integration.Tests/Inbox/PostgreSqlInboxBatchSendTests.cs
  • Source/DotNetWorkQueue.Transport.SqlServer.IntegrationTests/Inbox/SqlServerInboxBatchSendTests.cs
  • docs/outbox-pattern.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • docs/outbox-pattern.md
  • Source/DotNetWorkQueue.Transport.PostgreSQL.Integration.Tests/Inbox/PostgreSqlInboxBatchSendTests.cs
  • Source/DotNetWorkQueue.Transport.SqlServer.IntegrationTests/Inbox/SqlServerInboxBatchSendTests.cs

📝 Walkthrough

Walkthrough

Adds held-transaction batch dispatch for SQL Server and PostgreSQL inbox sends. The producer queues now send batch commands through external-transaction handlers, and the tests and docs were updated to cover commit, rollback, failure, and result semantics.

Changes

PostgreSQL held-transaction batch send

Layer / File(s) Summary
PostgreSQL batch dispatch path
Source/DotNetWorkQueue.Transport.PostgreSQL/Basic/CommandHandler/SendMessageCommandBatchHandler.cs, Source/DotNetWorkQueue.Transport.PostgreSQL/Basic/CommandHandler/SendMessageCommandBatchHandlerAsync.cs, Source/DotNetWorkQueue.Transport.PostgreSQL/Basic/PostgreSqlRelationalProducerQueue.cs
Adds external-transaction batch handling and routes held-transaction batch sends through RelationalSendMessageCommandBatch using the caller’s NpgsqlConnection and NpgsqlTransaction.
PostgreSQL batch send tests
Source/DotNetWorkQueue.Transport.PostgreSQL.Tests/Basic/PostgreSqlRelationalProducerQueueTests.cs, Source/DotNetWorkQueue.Transport.PostgreSQL.Integration.Tests/Inbox/PostgreSqlInboxBatchSendTests.cs
Adds batch handler wiring tests and inbox integration tests for commit, rollback, connection reuse, forced failure, result ids, and multi-chunk ordering.

SQL Server held-transaction batch send

Layer / File(s) Summary
SQL Server batch dispatch path
Source/DotNetWorkQueue.Transport.SqlServer/Basic/CommandHandler/SendMessageCommandBatchHandler.cs, Source/DotNetWorkQueue.Transport.SqlServer/Basic/CommandHandler/SendMessageCommandBatchHandlerAsync.cs, Source/DotNetWorkQueue.Transport.SqlServer/Basic/SqlServerRelationalProducerQueue.cs
Adds external-transaction batch handling and routes held-transaction batch sends through RelationalSendMessageCommandBatch using the caller’s SqlConnection and SqlTransaction.
SQL Server batch send tests
Source/DotNetWorkQueue.Transport.SqlServer.Tests/Basic/SqlServerRelationalProducerQueueTests.cs, Source/DotNetWorkQueue.Transport.SqlServer.IntegrationTests/Inbox/SqlServerInboxBatchSendTests.cs
Adds batch handler wiring tests and inbox integration tests for commit, rollback, connection reuse, forced failure, and per-message result ids.

Documentation update

Layer / File(s) Summary
Outbox batch semantics docs
docs/outbox-pattern.md
Updates the caller-transaction batch example to roll back on exception and rewrites the surrounding text to describe fail-fast batch behavior and transport support.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • blehnen/DotNetWorkQueue#141: Earlier work around ExternalTransaction routing and related batch documentation is directly extended by these held-transaction batch paths.
  • blehnen/DotNetWorkQueue#164: Closely related SQL Server batch-send changes overlap with the producer queue and handler paths updated here.
  • blehnen/DotNetWorkQueue#168: Closely related PostgreSQL batch-send changes overlap with the producer queue and handler paths updated here.

Poem

I thump, I hop, I batch with glee,
Two databases now dance with me.
One transaction, rows aligned,
Inbox carrots neatly lined. 🥕
Batch by batch, the moon is bright,
Rabbit sends till morning light.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: held-transaction inbox batch send now uses true multi-row inserts for SQL Server and PostgreSQL.
Linked Issues check ✅ Passed The changes implement caller-transaction batch dispatch with external-transaction handlers, no handler-side commit/rollback, and SQL Server/PostgreSQL support as requested.
Out of Scope Changes check ✅ Passed The added tests and docs stay aligned with the inbox held-transaction batch-send work and do not introduce unrelated functionality.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
Source/DotNetWorkQueue.Transport.PostgreSQL.Integration.Tests/Inbox/PostgreSqlInboxBatchSendTests.cs (1)

250-262: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the Interlocked disposal guard for ProducerScope.

ProducerScope is a new IDisposable; add the same thread-safe disposal guard expected for disposable types.

As per coding guidelines, “Use Interlocked-based disposal patterns for thread-safe disposal throughout the codebase.”

Proposed fix
 private sealed class ProducerScope : System.IDisposable
 {
+    private int _disposed;
+
     public QueueContainer<PostgreSqlMessageQueueInit> Creator { get; init; }
     public IProducerQueue<FakeMessage> Producer { get; init; }
     public IRelationalProducerQueue<FakeMessage> RelationalProducer { get; init; }

     public void Dispose()
     {
+        if (System.Threading.Interlocked.Exchange(ref _disposed, 1) == 1)
+            return;
+
         Producer?.Dispose();
         Creator?.Dispose();
     }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Source/DotNetWorkQueue.Transport.PostgreSQL.Integration.Tests/Inbox/PostgreSqlInboxBatchSendTests.cs`
around lines 250 - 262, ProducerScope currently disposes its dependencies
without a thread-safe guard, so update its Dispose implementation to follow the
codebase’s Interlocked-based disposable pattern. Add a disposal state field to
ProducerScope and use an Interlocked exchange/check in Dispose so Creator and
Producer are released only once even under concurrent calls. Keep the fix
localized to the ProducerScope nested class in PostgreSqlInboxBatchSendTests and
mirror the same disposal style used elsewhere for disposable helpers.

Source: Coding guidelines

Source/DotNetWorkQueue.Transport.SqlServer/Basic/CommandHandler/SendMessageCommandBatchHandlerAsync.cs (1)

145-160: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Mirror the sync handler’s MessageData contract check here.

ProcessChunkAsync still assumes every batch item already carries non-null MessageData. The producer currently normalizes that upstream, but this new async branch has no fail-fast check of its own, so any direct dispatch or future bypass will crash later in the chunk loop instead of at the boundary.

Suggested guard
 private async Task<QueueOutputMessages> HandleExternalTransactionAsync(RelationalSendMessageCommandBatch rel)
 {
+    if (rel.Messages.Any(m => m.MessageData == null))
+    {
+        throw new DotNetWorkQueueException(
+            "Batch messages must have non-null MessageData before handler dispatch.");
+    }
+
     var sqlTransaction = (SqlTransaction)rel.ExternalTransaction;
     var sqlConn = (SqlConnection)sqlTransaction.Connection;

Based on learnings: "In the batch send implementations for the PostgreSQL, SQL Server, and SQLite transports, m.MessageData must be non-null when the internal batch handler runs... add an explicit guard (throw) or at least a debug assertion..."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Source/DotNetWorkQueue.Transport.SqlServer/Basic/CommandHandler/SendMessageCommandBatchHandlerAsync.cs`
around lines 145 - 160, Add the same fail-fast MessageData non-null contract
check used by the sync batch handler before entering ProcessChunkAsync in
HandleExternalTransactionAsync. This async SQL Server path should validate
rel.Messages items (or the batch chunk) and throw or assert immediately if any
message has null MessageData, rather than letting the loop fail later. Use the
existing HandleExternalTransactionAsync and ProcessChunkAsync flow as the place
to mirror the sync handler’s guard.

Source: Learnings

Source/DotNetWorkQueue.Transport.SqlServer/Basic/CommandHandler/SendMessageCommandBatchHandler.cs (1)

152-167: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Fail fast if a batch reaches this handler with null MessageData.

This new path feeds rel.Messages straight into ProcessChunk, which later dereferences m.MessageData for expiration, delay, metadata/status writes, and correlation IDs. The producer currently normalizes nulls before dispatch, but a direct handler call or future refactor would turn that into a late runtime failure here. A small guard/debug assertion at the handoff point would make the contract explicit.

Suggested guard
 private QueueOutputMessages HandleExternalTransaction(RelationalSendMessageCommandBatch rel)
 {
+    if (rel.Messages.Any(m => m.MessageData == null))
+    {
+        throw new DotNetWorkQueueException(
+            "Batch messages must have non-null MessageData before handler dispatch.");
+    }
+
     var sqlTransaction = (SqlTransaction)rel.ExternalTransaction;
     var sqlConn = (SqlConnection)sqlTransaction.Connection;

Based on learnings: "In the batch send implementations for the PostgreSQL, SQL Server, and SQLite transports, m.MessageData must be non-null when the internal batch handler runs... add an explicit guard (throw) or at least a debug assertion..."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Source/DotNetWorkQueue.Transport.SqlServer/Basic/CommandHandler/SendMessageCommandBatchHandler.cs`
around lines 152 - 167, Add an explicit fail-fast guard in
SendMessageCommandBatchHandler.HandleExternalTransaction before the call to
ProcessChunk, because rel.Messages is passed through without revalidating
MessageData and later code assumes it is non-null. Check the message batch (or
each message in rel.Messages) for null MessageData and throw a clear exception
or add a debug assertion so the contract is enforced at this handoff. Use the
HandleExternalTransaction and ProcessChunk symbols to place the guard at the
internal batch entry point.

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/outbox-pattern.md`:
- Around line 165-169: The batch-path description overstates the implementation
by implying everything is inserted in a single batched operation; update the
wording in the outbox-pattern docs near SendAsync(batch, transaction) to clarify
that only the body rows are inserted as a multi-row batch inside the
caller-owned transaction, while metadata/status rows are still written per
message afterward. Keep the fail-fast/rollback guidance, but avoid saying “one
insert per chunk, not one round trip per message” for the whole path.

---

Nitpick comments:
In
`@Source/DotNetWorkQueue.Transport.PostgreSQL.Integration.Tests/Inbox/PostgreSqlInboxBatchSendTests.cs`:
- Around line 250-262: ProducerScope currently disposes its dependencies without
a thread-safe guard, so update its Dispose implementation to follow the
codebase’s Interlocked-based disposable pattern. Add a disposal state field to
ProducerScope and use an Interlocked exchange/check in Dispose so Creator and
Producer are released only once even under concurrent calls. Keep the fix
localized to the ProducerScope nested class in PostgreSqlInboxBatchSendTests and
mirror the same disposal style used elsewhere for disposable helpers.

In
`@Source/DotNetWorkQueue.Transport.SqlServer/Basic/CommandHandler/SendMessageCommandBatchHandler.cs`:
- Around line 152-167: Add an explicit fail-fast guard in
SendMessageCommandBatchHandler.HandleExternalTransaction before the call to
ProcessChunk, because rel.Messages is passed through without revalidating
MessageData and later code assumes it is non-null. Check the message batch (or
each message in rel.Messages) for null MessageData and throw a clear exception
or add a debug assertion so the contract is enforced at this handoff. Use the
HandleExternalTransaction and ProcessChunk symbols to place the guard at the
internal batch entry point.

In
`@Source/DotNetWorkQueue.Transport.SqlServer/Basic/CommandHandler/SendMessageCommandBatchHandlerAsync.cs`:
- Around line 145-160: Add the same fail-fast MessageData non-null contract
check used by the sync batch handler before entering ProcessChunkAsync in
HandleExternalTransactionAsync. This async SQL Server path should validate
rel.Messages items (or the batch chunk) and throw or assert immediately if any
message has null MessageData, rather than letting the loop fail later. Use the
existing HandleExternalTransactionAsync and ProcessChunkAsync flow as the place
to mirror the sync handler’s guard.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9644fc41-1f04-47b2-b40f-88c38e8540e2

📥 Commits

Reviewing files that changed from the base of the PR and between c32636f and da55301.

📒 Files selected for processing (11)
  • Source/DotNetWorkQueue.Transport.PostgreSQL.Integration.Tests/Inbox/PostgreSqlInboxBatchSendTests.cs
  • Source/DotNetWorkQueue.Transport.PostgreSQL.Tests/Basic/PostgreSqlRelationalProducerQueueTests.cs
  • Source/DotNetWorkQueue.Transport.PostgreSQL/Basic/CommandHandler/SendMessageCommandBatchHandler.cs
  • Source/DotNetWorkQueue.Transport.PostgreSQL/Basic/CommandHandler/SendMessageCommandBatchHandlerAsync.cs
  • Source/DotNetWorkQueue.Transport.PostgreSQL/Basic/PostgreSqlRelationalProducerQueue.cs
  • Source/DotNetWorkQueue.Transport.SqlServer.IntegrationTests/Inbox/SqlServerInboxBatchSendTests.cs
  • Source/DotNetWorkQueue.Transport.SqlServer.Tests/Basic/SqlServerRelationalProducerQueueTests.cs
  • Source/DotNetWorkQueue.Transport.SqlServer/Basic/CommandHandler/SendMessageCommandBatchHandler.cs
  • Source/DotNetWorkQueue.Transport.SqlServer/Basic/CommandHandler/SendMessageCommandBatchHandlerAsync.cs
  • Source/DotNetWorkQueue.Transport.SqlServer/Basic/SqlServerRelationalProducerQueue.cs
  • docs/outbox-pattern.md

Comment thread docs/outbox-pattern.md Outdated
@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.12903% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.48%. Comparing base (c32636f) to head (6d4264d).
⚠️ Report is 10 commits behind head on master.

Files with missing lines Patch % Lines
...tgreSQL/Basic/PostgreSqlRelationalProducerQueue.cs 85.18% 2 Missing and 2 partials ⚠️
...qlServer/Basic/SqlServerRelationalProducerQueue.cs 85.18% 2 Missing and 2 partials ⚠️
...mandHandler/SendMessageCommandBatchHandlerAsync.cs 94.44% 0 Missing and 1 partial ⚠️
...c/CommandHandler/SendMessageCommandBatchHandler.cs 94.11% 0 Missing and 1 partial ⚠️
...mandHandler/SendMessageCommandBatchHandlerAsync.cs 94.44% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #169      +/-   ##
==========================================
+ Coverage   87.42%   87.48%   +0.05%     
==========================================
  Files        1023     1023              
  Lines       33793    33863      +70     
  Branches     2856     2864       +8     
==========================================
+ Hits        29544    29625      +81     
+ Misses       3373     3365       -8     
+ Partials      876      873       -3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- docs/outbox-pattern.md: clarify only the body insert is multi-row; per-message
  meta/status rows are still written one per message (prior wording overstated it).
- Integration test ProducerScope (SQL Server + PostgreSQL): add the Interlocked-based
  thread-safe disposal guard per repo convention.

Refs #167.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@blehnen blehnen merged commit 5dd4c74 into master Jun 30, 2026
5 checks passed
@blehnen blehnen deleted the phase-1-inbox-batch branch June 30, 2026 22:31
blehnen added a commit that referenced this pull request Jul 1, 2026
…reSQL)

Bump Version 0.9.41 -> 0.9.42 and add the 0.9.42 CHANGELOG entry for #167
(the entry was lost from the #169 merge due to a CHANGELOG.md casing mismatch;
the code and tests all merged correctly).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Inbox held-transaction batch send: true multi-row insert in the caller's transaction (SQL Server + PostgreSQL)

1 participant