Skip to content

feat(csharp): implement rented message polling#3250

Merged
hubcio merged 7 commits into
masterfrom
feat/dotnet-memory-usage
May 22, 2026
Merged

feat(csharp): implement rented message polling#3250
hubcio merged 7 commits into
masterfrom
feat/dotnet-memory-usage

Conversation

@lukaszzborek

@lukaszzborek lukaszzborek commented May 13, 2026

Copy link
Copy Markdown
Contributor

Rationale

Polling path allocated fresh byte[] per message payload + another per raw user-headers blob. On high-throughput consumers that's dominant allocation source. Goal: cut allocs by reusing pooled buffers, without breaking existing safe API.

What changed

  • Underlying poll now reads server bytes into MemoryPool.Shared.Rent(...) buffer instead of new byte[len]. Whole batch shares one rented buffer; payloads + raw headers are slices into it.
  • New rented polling path: IggyConsumer.ReceiveRentedAsync() yields ReceivedRentedMessage. Slices stay alive until caller disposes. Saves 1–2 allocs per message vs old path.
  • Typed variant: IggyConsumer.ReceiveDeserializedAsync() deserializes whole batch eagerly, returns buffer to pool immediately. Caller disposes nothing.
  • New client method: IIggyClient.PollMessagesRentedAsync(...) → PolledMessagesRental.
  • IDeserializer.Deserialize signature: byte[] → ReadOnlyMemory.
  • Old ReceiveMessagesAsync / MessageResponse API unchanged on surface, but internally also reads into pooled buffer now and materializes byte[] only after mapping — saves 1 allocation per poll (the big receive buffer).

What's next

  • Move encryption/decryption into IggyClient so it stops re-allocating (TODO in IggyConsumer.Rented.cs:158).
  • Add rented / Memory / Span API on send path.
  • Make header mapping lazy after decryption move.
  • Update docs in iggy website repo.

Benchmark in comment

@codecov

codecov Bot commented May 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 76.81661% with 134 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.44%. Comparing base (f1965fc) to head (7207260).

Files with missing lines Patch % Lines
...n/csharp/Iggy_SDK/Consumers/IggyConsumer.Rented.cs 60.71% 46 Missing and 9 partials ⚠️
...SDK/IggyClient/Implementations/TcpMessageStream.cs 81.64% 9 Missing and 20 partials ⚠️
foreign/csharp/Iggy_SDK/Consumers/IggyConsumer.cs 37.50% 16 Missing and 4 partials ⚠️
...reign/csharp/Iggy_SDK/Contracts/MessageResponse.cs 68.96% 9 Missing ⚠️
...n/csharp/Iggy_SDK/Consumers/IggyConsumerBuilder.cs 0.00% 3 Missing and 1 partial ⚠️
...csharp/Iggy_SDK/Consumers/ReceivedRentedMessage.cs 86.66% 3 Missing and 1 partial ⚠️
...oreign/csharp/Iggy_SDK/IggyClient/IIggyConsumer.cs 0.00% 4 Missing ⚠️
foreign/csharp/Iggy_SDK/Mappers/BinaryMapper.cs 95.65% 1 Missing and 3 partials ⚠️
...reign/csharp/Iggy_SDK/Consumers/IggyConsumerOfT.cs 94.87% 0 Missing and 2 partials ⚠️
...csharp/Iggy_SDK/Contracts/RentedMessageResponse.cs 94.11% 0 Missing and 1 partial ⚠️
... and 2 more
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #3250      +/-   ##
============================================
+ Coverage     74.07%   74.44%   +0.37%     
  Complexity      943      943              
============================================
  Files          1201     1204       +3     
  Lines        110672   109354    -1318     
  Branches      87563    85944    -1619     
============================================
- Hits          81977    81407     -570     
+ Misses        25939    25176     -763     
- Partials       2756     2771      +15     
Components Coverage Δ
Rust Core 75.74% <ø> (+0.48%) ⬆️
Java SDK 58.44% <ø> (ø)
C# SDK 70.12% <76.81%> (+0.68%) ⬆️
Python SDK 81.43% <ø> (ø)
Node SDK 91.44% <ø> (-0.10%) ⬇️
Go SDK 39.91% <ø> (ø)
Files with missing lines Coverage Δ
...reign/csharp/Iggy_SDK/Consumers/ReceivedMessage.cs 100.00% <100.00%> (+16.66%) ⬆️
.../csharp/Iggy_SDK/Contracts/PolledMessagesRental.cs 100.00% <100.00%> (ø)
...DK/IggyClient/Implementations/HttpMessageStream.cs 72.02% <100.00%> (+0.29%) ⬆️
...csharp/Iggy_SDK/Contracts/RentedMessageResponse.cs 94.11% <94.11%> (ø)
.../csharp/Iggy_SDK/Extensions/IggyClientExtension.cs 0.00% <0.00%> (ø)
...ggy_SDK/JsonConverters/MessageResponseConverter.cs 70.90% <87.50%> (+2.90%) ⬆️
...reign/csharp/Iggy_SDK/Consumers/IggyConsumerOfT.cs 96.49% <94.87%> (+96.49%) ⬆️
...n/csharp/Iggy_SDK/Consumers/IggyConsumerBuilder.cs 74.12% <0.00%> (-2.14%) ⬇️
...csharp/Iggy_SDK/Consumers/ReceivedRentedMessage.cs 86.66% <86.66%> (ø)
...oreign/csharp/Iggy_SDK/IggyClient/IIggyConsumer.cs 50.00% <0.00%> (-50.00%) ⬇️
... and 5 more

... and 44 files with indirect coverage changes

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

@hubcio

hubcio commented May 14, 2026

Copy link
Copy Markdown
Contributor

/ready

@github-actions github-actions Bot added the S-waiting-on-review PR is waiting on a reviewer label May 14, 2026
@lukaszzborek lukaszzborek force-pushed the feat/dotnet-memory-usage branch from a28b2fb to 6cc8c2a Compare May 14, 2026 16:44
@lukaszzborek lukaszzborek force-pushed the feat/dotnet-memory-usage branch from 6cc8c2a to 1405d89 Compare May 14, 2026 16:50
@lukaszzborek lukaszzborek force-pushed the feat/dotnet-memory-usage branch from 1405d89 to 858433e Compare May 14, 2026 16:57
@lukaszzborek

Copy link
Copy Markdown
Contributor Author

Some benchmark:

Method 0.8.0 Mean Current Mean Δ Mean 0.8.0 Gen0 Current Gen0 0.8.0 Gen1 Current Gen1 0.8.0 Gen2 Current Gen2 0.8.0 Allocated Current Allocated Δ Allocated
PollMessagesAsync 22.52 ms 20.26 ms -10.03% 312.5000 187.5000 312.5000 31.2500 312.5000 - 3.91 MB 2.97 MB -24.04%
PollMessagesRentedAsync 22.52 ms* 22.56 ms +0.18% 312.5000* 125.0000 312.5000* - 312.5000* - 3.91 MB* 1.93 MB -50.64%
ConsumerReceiveAsync 24.15 ms 22.57 ms -6.54% 312.5000 187.5000 312.5000 31.2500 312.5000 - 3.97 MB 3.02 MB -23.93%
ConsumerReceiveRentedAsync 24.15 ms* 23.32 ms -3.44% 312.5000* 125.0000 312.5000* - 312.5000* - 3.97 MB* 2 MB -49.62%
TypedConsumerReceiveAsync 24.31 ms 22.57 ms -7.16% 312.5000 125.0000 312.5000 31.2500 312.5000 - 4.02 MB 2 MB -50.25%

* Compared against the 0.8.0 non-rented equivalent (PollMessagesAsync / ConsumerReceiveAsync) as requested.

It was tested with a 1 KB message. Polling messages were performed in batches of 100 until 1,000 processed messages were obtained (deserialising the messages via MessagePack).

@lukaszzborek lukaszzborek requested review from numinnex and spetz May 19, 2026 21:27
Comment thread foreign/csharp/Iggy_SDK/Consumers/IggyConsumer.Rented.cs
Comment thread foreign/csharp/Iggy_SDK/Consumers/IggyConsumer.cs
Comment thread foreign/csharp/Iggy_SDK/IggyClient/Implementations/TcpMessageStream.cs Outdated
Comment thread foreign/csharp/Iggy_SDK/Mappers/BinaryMapper.cs Outdated
Comment thread foreign/csharp/Iggy_SDK/Consumers/IggyConsumer.cs
Comment thread foreign/csharp/Iggy_SDK/IggyClient/IIggyConsumer.cs
@github-actions github-actions Bot added S-waiting-on-author PR is waiting on author response and removed S-waiting-on-review PR is waiting on a reviewer labels May 21, 2026
@lukaszzborek

Copy link
Copy Markdown
Contributor Author

/ready

@github-actions github-actions Bot added S-waiting-on-review PR is waiting on a reviewer and removed S-waiting-on-author PR is waiting on author response labels May 21, 2026
@hubcio hubcio merged commit c3e4db7 into master May 22, 2026
45 checks passed
@hubcio hubcio deleted the feat/dotnet-memory-usage branch May 22, 2026 11:39
@github-actions github-actions Bot removed the S-waiting-on-review PR is waiting on a reviewer label May 22, 2026
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.

3 participants