Skip to content

Conversation

@alexey-troshkin-xpress
Copy link
Contributor

@alexey-troshkin-xpress alexey-troshkin-xpress commented Nov 20, 2025

User description

Added the ability to specify a SessionId when publishing events for parallel processing with guaranteed order within the SessionId on the consumer side


Auto-created Ticket

#471

PR Type

Enhancement


Description

  • Add SessionId and ReplyToSessionId support for message producers

  • Implement ServiceBusSessionProcessor for ordered message consumption

  • Enable session-based message processing with guaranteed ordering

  • Support both standard and session-based subscription modes


Diagram Walkthrough

flowchart LR
  Producer["Producer with SessionId"] -->|"SessionId + ReplyToSessionId"| Message["ServiceBusMessage"]
  Message -->|"Session-enabled"| Broker["Service Bus Broker"]
  Broker -->|"SessionProcessorOptions"| Consumer["SessionProcessor Consumer"]
  Consumer -->|"Ordered by SessionId"| Handler["Message Handler"]
Loading

File Walkthrough

Relevant files
Enhancement
ServiceBusMessageBuilder.cs
Add SessionId and ReplyToSessionId to messages                     

src/Azure/src/Eventuous.Azure.ServiceBus/Producers/ServiceBusMessageBuilder.cs

  • Added ReplyToSessionId property assignment to ServiceBusMessage
  • Implemented conditional SessionId assignment with null-check to avoid
    overriding PartitionKey
  • Added explanatory comment about SessionId behavior
+9/-1     
ServiceBusProduceOptions.cs
Add session properties to produce options                               

src/Azure/src/Eventuous.Azure.ServiceBus/Producers/ServiceBusProduceOptions.cs

  • Added SessionId property for specifying session identifier on messages
  • Added ReplyToSessionId property for request-reply session patterns
  • Both properties use init-only accessors for immutability
+10/-0   
ServiceBusSubscription.cs
Implement session processor support in subscriptions         

src/Azure/src/Eventuous.Azure.ServiceBus/Subscriptions/ServiceBusSubscription.cs

  • Added _sessionProcessor field to support session-based message
    processing
  • Implemented conditional logic to use SessionProcessor when
    SessionProcessorOptions is configured
  • Added new HandleSessionMessage method to process session-based
    messages with identical logic to standard handler
  • Both processor types register their respective message and error
    handlers
+62/-4   
ServiceBusSubscriptionOptions.cs
Add session processor configuration options                           

src/Azure/src/Eventuous.Azure.ServiceBus/Subscriptions/ServiceBusSubscriptionOptions.cs

  • Added SessionProcessorOptions property to enable session-based
    processing
  • Added MakeSessionProcessor method to IQueueOrTopic interface
  • Implemented MakeSessionProcessor in Queue, Topic, and
    TopicAndSubscription classes
  • Session processor options take priority over standard ProcessorOptions
    when specified
+41/-0   

…cer, along with support for ServiceBusSessionProcessor for the consumer
@qodo-free-for-open-source-projects
Copy link
Contributor

qodo-free-for-open-source-projects bot commented Nov 20, 2025

PR Compliance Guide 🔍

(Compliance updated until commit adb53f4)

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🟢
🎫 #471
🟢 Add SessionId and ReplyToSessionId properties to produce options
Apply SessionId and ReplyToSessionId to outgoing messages
Implement ServiceBusSessionProcessor support in subscription
Conditionally activate session processor based on configuration
Create session-aware message handler that processes session messages
Implement proper context handling in session message handler
Implement proper error handling in session message handler
Add SessionProcessorOptions to subscription options
SessionProcessorOptions should take priority over standard processor options
Codebase Duplication Compliance
🟢
No codebase code duplication found No new components were introduced in the PR code
Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Missing null validation: The HandleSessionMessage method accesses msg.ApplicationProperties without null checks,
which could throw NullReferenceException if properties are missing or null.

Referred Code
var eventType = msg.ApplicationProperties[Options.AttributeNames.MessageType].ToString()
 ?? throw new InvalidOperationException("Event type is missing in message properties");
var contentType = msg.ContentType;

// Should this be a stream name? or topic or something
var streamName = msg.ApplicationProperties[Options.AttributeNames.StreamName].ToString()
 ?? throw new InvalidOperationException("Stream name is missing in message properties");

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Insufficient input validation: The HandleSessionMessage method throws generic exceptions when required properties are
missing but doesn't validate the content or format of eventType and streamName values
before use.

Referred Code
var eventType = msg.ApplicationProperties[Options.AttributeNames.MessageType].ToString()
 ?? throw new InvalidOperationException("Event type is missing in message properties");
var contentType = msg.ContentType;

// Should this be a stream name? or topic or something
var streamName = msg.ApplicationProperties[Options.AttributeNames.StreamName].ToString()
 ?? throw new InvalidOperationException("Stream name is missing in message properties");

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

Previous compliance checks

Compliance check up to commit f43b587
Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
🟢
No codebase code duplication found No new components were introduced in the PR code
Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Missing null validation: The HandleSessionMessage method does not validate that msg.ApplicationProperties contains
the required keys before accessing them, which could cause runtime exceptions.

Referred Code
var eventType = msg.ApplicationProperties[Options.AttributeNames.MessageType].ToString()
 ?? throw new InvalidOperationException("Event type is missing in message properties");
var contentType = msg.ContentType;

// Should this be a stream name? or topic or something
var streamName = msg.ApplicationProperties[Options.AttributeNames.StreamName].ToString()
 ?? throw new InvalidOperationException("Stream name is missing in message properties");

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Insufficient input validation: The HandleSessionMessage method accesses msg.ApplicationProperties dictionary without
validating key existence, potentially causing KeyNotFoundException for malformed messages.

Referred Code
var eventType = msg.ApplicationProperties[Options.AttributeNames.MessageType].ToString()
 ?? throw new InvalidOperationException("Event type is missing in message properties");
var contentType = msg.ContentType;

// Should this be a stream name? or topic or something
var streamName = msg.ApplicationProperties[Options.AttributeNames.StreamName].ToString()
 ?? throw new InvalidOperationException("Stream name is missing in message properties");

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Potential sensitive data: The error logging at line 101 and 150 logs msg.MessageId which may contain sensitive
information depending on how MessageId is constructed in the system.

Referred Code
    Log.ErrorLog?.Log(ex, "Error processing message: {MessageId}", msg.MessageId);
}

Learn more about managing compliance generic rules or creating your own custom rules

@qodo-free-for-open-source-projects
Copy link
Contributor

qodo-free-for-open-source-projects bot commented Nov 20, 2025

PR Code Suggestions ✨

Latest suggestions up to adb53f4

CategorySuggestion                                                                                                                                    Impact
Incremental [*]
Dispose processors to prevent leaks

Dispose of ServiceBusProcessor and ServiceBusSessionProcessor instances in the
Unsubscribe method to prevent resource leaks.

src/Azure/src/Eventuous.Azure.ServiceBus/Subscriptions/ServiceBusSubscription.cs [189-196]

 protected override async ValueTask Unsubscribe(CancellationToken cancellationToken) {
     if (_sessionProcessor is not null) {
         await _sessionProcessor.StopProcessingAsync(cancellationToken).NoContext();
+        await _sessionProcessor.DisposeAsync().NoContext();
+        _sessionProcessor = null;
     }
     else if (_processor is not null) {
         await _processor.StopProcessingAsync(cancellationToken).NoContext();
+        await _processor.DisposeAsync().NoContext();
+        _processor = null;
     }
 }
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a resource leak, as the ServiceBusProcessor and ServiceBusSessionProcessor instances are not being disposed, and provides the correct fix by calling DisposeAsync.

Medium
  • More

Previous suggestions

✅ Suggestions up to commit f43b587
CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix resource leak by stopping session processor
Suggestion Impact:The suggestion was implemented in the commit. The code now stops both _sessionProcessor and _processor to prevent resource leaks. The implementation differs slightly in order (checks _sessionProcessor first instead of _processor first) and uses 'is not null' instead of '!= null', but the core fix is the same.

code diff:

+        if (_sessionProcessor is not null) {
+            await _sessionProcessor.StopProcessingAsync(cancellationToken).NoContext();
+        }
+        else if (_processor is not null) {
+            await _processor.StopProcessingAsync(cancellationToken).NoContext();
+        }

Update the Unsubscribe method to also stop the _sessionProcessor if it is
active, preventing a resource leak.

src/Azure/src/Eventuous.Azure.ServiceBus/Subscriptions/ServiceBusSubscription.cs [189-192]

 protected override async ValueTask Unsubscribe(CancellationToken cancellationToken) {
-    if (_processor == null) return;
-    await _processor.StopProcessingAsync(cancellationToken).NoContext();
+    if (_processor != null) {
+        await _processor.StopProcessingAsync(cancellationToken).NoContext();
+    }
+    else if (_sessionProcessor != null) {
+        await _sessionProcessor.StopProcessingAsync(cancellationToken).NoContext();
+    }
 }
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a resource leak bug where the new _sessionProcessor is started but never stopped, which is a critical flaw introduced in the PR.

High
General
Refactor duplicated logic into a single method

Refactor the duplicated logic from HandleMessage and HandleSessionMessage into a
single, generic method to improve code maintainability and reduce redundancy.

src/Azure/src/Eventuous.Azure.ServiceBus/Subscriptions/ServiceBusSubscription.cs [57-151]

-async Task HandleMessage(ProcessMessageEventArgs arg) {
-    var ct = arg.CancellationToken;
+async Task HandleMessage(ProcessMessageEventArgs arg) => await Handle(new MessageHandlerContext<ProcessMessageEventArgs>(arg));
+async Task HandleSessionMessage(ProcessSessionMessageEventArgs arg) => await Handle(new MessageHandlerContext<ProcessSessionMessageEventArgs>(arg));
+
+async Task Handle<T>(IMessageHandlerContext<T> handlerContext) where T : class {
+    var ct = handlerContext.CancellationToken;
 
     if (ct.IsCancellationRequested) return;
 
-    var msg = arg.Message;
+    var msg = handlerContext.Message;
 
     var eventType = msg.ApplicationProperties[Options.AttributeNames.MessageType].ToString()
      ?? throw new InvalidOperationException("Event type is missing in message properties");
     var contentType = msg.ContentType;
 
     // Should this be a stream name? or topic or something
     var streamName = msg.ApplicationProperties[Options.AttributeNames.StreamName].ToString()
      ?? throw new InvalidOperationException("Stream name is missing in message properties");
 
     Logger.Current = Log;
 
     var evt = DeserializeData(contentType, eventType, msg.Body, streamName);
 
     var applicationProperties = msg.ApplicationProperties.Concat(MessageProperties(msg));
 
     var ctx = new MessageConsumeContext(
         msg.MessageId,
         eventType,
         contentType,
         streamName,
         0,
         0,
         0,
         Sequence++,
         msg.EnqueuedTime.UtcDateTime,
         evt,
         AsMeta(applicationProperties),
         SubscriptionId,
         ct
     );
 
     try {
         await Handler(ctx).NoContext();
-        await arg.CompleteMessageAsync(msg, ct).NoContext();
+        await handlerContext.CompleteMessageAsync(msg, ct).NoContext();
     } catch (Exception ex) {
         // Abandoning the message will make it available for reprocessing, or dead letter it?
-        await arg.AbandonMessageAsync(msg, null, ct).NoContext(); 
-        await _defaultErrorHandler(new(ex, ServiceBusErrorSource.Abandon, arg.FullyQualifiedNamespace, arg.EntityPath, arg.Identifier, arg.CancellationToken)).NoContext();
+        await handlerContext.AbandonMessageAsync(msg, null, ct).NoContext();
+        await _defaultErrorHandler(new(ex, ServiceBusErrorSource.Abandon, handlerContext.FullyQualifiedNamespace, handlerContext.EntityPath, handlerContext.Identifier, handlerContext.CancellationToken)).NoContext();
         Log.ErrorLog?.Log(ex, "Error processing message: {MessageId}", msg.MessageId);
     }
 }
 
-async Task HandleSessionMessage(ProcessSessionMessageEventArgs arg) {
-    var ct = arg.CancellationToken;
-
-    if (ct.IsCancellationRequested) return;
-
-    var msg = arg.Message;
-
-    var eventType = msg.ApplicationProperties[Options.AttributeNames.MessageType].ToString()
-     ?? throw new InvalidOperationException("Event type is missing in message properties");
-    var contentType = msg.ContentType;
-
-    // Should this be a stream name? or topic or something
-    var streamName = msg.ApplicationProperties[Options.AttributeNames.StreamName].ToString()
-     ?? throw new InvalidOperationException("Stream name is missing in message properties");
-
-    Logger.Current = Log;
-
-    var evt = DeserializeData(contentType, eventType, msg.Body, streamName);
-
-    var applicationProperties = msg.ApplicationProperties.Concat(MessageProperties(msg));
-
-    var ctx = new MessageConsumeContext(
-        msg.MessageId,
-        eventType,
-        contentType,
-        streamName,
-        0,
-        0,
-        0,
-        Sequence++,
-        msg.EnqueuedTime.UtcDateTime,
-        evt,
-        AsMeta(applicationProperties),
-        SubscriptionId,
-        ct
-    );
-
-    try {
-        await Handler(ctx).NoContext();
-        await arg.CompleteMessageAsync(msg, ct).NoContext();
-    } catch (Exception ex) {
-        // Abandoning the message will make it available for reprocessing, or dead letter it?
-        await arg.AbandonMessageAsync(msg, null, ct).NoContext();
-        await _defaultErrorHandler(new(ex, ServiceBusErrorSource.Abandon, arg.FullyQualifiedNamespace, arg.EntityPath, arg.Identifier, arg.CancellationToken)).NoContext();
-        Log.ErrorLog?.Log(ex, "Error processing message: {MessageId}", msg.MessageId);
-    }
-}
-

[Suggestion processed]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies significant code duplication between HandleMessage and the new HandleSessionMessage, and the proposed refactoring would improve maintainability.

Medium

return new(_processor.StartProcessingAsync(cancellationToken));
}

async Task HandleMessage(ProcessMessageEventArgs arg) {

Choose a reason for hiding this comment

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

Suggestion: Refactor duplicated logic into a single method

Copy link
Contributor

Choose a reason for hiding this comment

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

Create a suggestion ready to commit

Choose a reason for hiding this comment

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

Code Implementation 🛠️

Implementation: Extract the duplicated message handling logic from HandleMessage and HandleSessionMessage into a shared private method to reduce code duplication and improve maintainability.

Suggested change
async Task HandleMessage(ProcessMessageEventArgs arg) {
async Task HandleMessage(ProcessMessageEventArgs arg) {
await ProcessMessageAsync(
arg.Message,
arg.CancellationToken,
msg => arg.CompleteMessageAsync(msg, arg.CancellationToken),
msg => arg.AbandonMessageAsync(msg, null, arg.CancellationToken),
arg.FullyQualifiedNamespace,
arg.EntityPath,
arg.Identifier
).NoContext();
}
async Task HandleSessionMessage(ProcessSessionMessageEventArgs arg) {
await ProcessMessageAsync(
arg.Message,
arg.CancellationToken,
msg => arg.CompleteMessageAsync(msg, arg.CancellationToken),
msg => arg.AbandonMessageAsync(msg, null, arg.CancellationToken),
arg.FullyQualifiedNamespace,
arg.EntityPath,
arg.Identifier
).NoContext();
}
async Task ProcessMessageAsync(
ServiceBusReceivedMessage msg,
CancellationToken ct,
Func<ServiceBusReceivedMessage, Task> completeMessage,
Func<ServiceBusReceivedMessage, Task> abandonMessage,
string fullyQualifiedNamespace,
string entityPath,
string identifier) {
if (ct.IsCancellationRequested) return;
var eventType = msg.ApplicationProperties[Options.AttributeNames.MessageType].ToString()
?? throw new InvalidOperationException("Event type is missing in message properties");
var contentType = msg.ContentType;
// Should this be a stream name? or topic or something
var streamName = msg.ApplicationProperties[Options.AttributeNames.StreamName].ToString()
?? throw new InvalidOperationException("Stream name is missing in message properties");
Logger.Current = Log;
var evt = DeserializeData(contentType, eventType, msg.Body, streamName);
var applicationProperties = msg.ApplicationProperties.Concat(MessageProperties(msg));
var ctx = new MessageConsumeContext(
msg.MessageId,
eventType,
contentType,
streamName,
0,
0,
0,
Sequence++,
msg.EnqueuedTime.UtcDateTime,
evt,
AsMeta(applicationProperties),
SubscriptionId,
ct
);
try {
await Handler(ctx).NoContext();
await completeMessage(msg).NoContext();
} catch (Exception ex) {
// Abandoning the message will make it available for reprocessing, or dead letter it?
await abandonMessage(msg).NoContext();
await _defaultErrorHandler(new(ex, ServiceBusErrorSource.Abandon, fullyQualifiedNamespace, entityPath, identifier, ct)).NoContext();
Log.ErrorLog?.Log(ex, "Error processing message: {MessageId}", msg.MessageId);
}
}
📄 References
  • No matching references available

See review comment here

@github-actions
Copy link

Test Results

 51 files  + 34   51 suites  +34   32m 1s ⏱️ + 19m 59s
279 tests + 10  277 ✅ +  8  0 💤 ±0  2 ❌ +2 
840 runs  +560  834 ✅ +554  0 💤 ±0  6 ❌ +6 

For more details on these failures, see this check.

Results for commit adb53f4. ± Comparison against base commit 20e513c.

This pull request removes 5 and adds 15 tests. Note that renamed tests count towards both.
Eventuous.Tests.Azure.ServiceBus.IsSerialisableByServiceBus ‑ Passes(11/15/2025 4:21:41 PM +00:00)
Eventuous.Tests.Azure.ServiceBus.IsSerialisableByServiceBus ‑ Passes(11/15/2025 4:21:41 PM)
Eventuous.Tests.Azure.ServiceBus.IsSerialisableByServiceBus ‑ Passes(9f9500c2-a728-4355-9693-4b0bf3e9ba06)
Eventuous.Tests.Subscriptions.SequenceTests ‑ ShouldReturnFirstBefore(CommitPosition { Position: 0, Sequence: 1, Timestamp: 2025-11-15T16:21:42.3737910+00:00 }, CommitPosition { Position: 0, Sequence: 2, Timestamp: 2025-11-15T16:21:42.3737910+00:00 }, CommitPosition { Position: 0, Sequence: 4, Timestamp: 2025-11-15T16:21:42.3737910+00:00 }, CommitPosition { Position: 0, Sequence: 6, Timestamp: 2025-11-15T16:21:42.3737910+00:00 }, CommitPosition { Position: 0, Sequence: 2, Timestamp: 2025-11-15T16:21:42.3737910+00:00 })
Eventuous.Tests.Subscriptions.SequenceTests ‑ ShouldReturnFirstBefore(CommitPosition { Position: 0, Sequence: 1, Timestamp: 2025-11-15T16:21:42.3737910+00:00 }, CommitPosition { Position: 0, Sequence: 2, Timestamp: 2025-11-15T16:21:42.3737910+00:00 }, CommitPosition { Position: 0, Sequence: 6, Timestamp: 2025-11-15T16:21:42.3737910+00:00 }, CommitPosition { Position: 0, Sequence: 8, Timestamp: 2025-11-15T16:21:42.3737910+00:00 }, CommitPosition { Position: 0, Sequence: 2, Timestamp: 2025-11-15T16:21:42.3737910+00:00 })
Eventuous.Tests.Azure.ServiceBus.IsSerialisableByServiceBus ‑ Passes(11/22/2025 2:34:37 PM +00:00)
Eventuous.Tests.Azure.ServiceBus.IsSerialisableByServiceBus ‑ Passes(11/22/2025 2:34:37 PM)
Eventuous.Tests.Azure.ServiceBus.IsSerialisableByServiceBus ‑ Passes(11/22/2025 2:34:39 PM +00:00)
Eventuous.Tests.Azure.ServiceBus.IsSerialisableByServiceBus ‑ Passes(11/22/2025 2:34:39 PM)
Eventuous.Tests.Azure.ServiceBus.IsSerialisableByServiceBus ‑ Passes(11/22/2025 2:34:46 PM +00:00)
Eventuous.Tests.Azure.ServiceBus.IsSerialisableByServiceBus ‑ Passes(11/22/2025 2:34:46 PM)
Eventuous.Tests.Azure.ServiceBus.IsSerialisableByServiceBus ‑ Passes(5a6838d5-2fcc-45ed-a45d-414202ad2c2f)
Eventuous.Tests.Azure.ServiceBus.IsSerialisableByServiceBus ‑ Passes(7a9901b7-2100-4f98-96df-80d9a1e1fe63)
Eventuous.Tests.Azure.ServiceBus.IsSerialisableByServiceBus ‑ Passes(8e3f2293-f5b4-4e35-9ead-14125bf5286a)
Eventuous.Tests.Subscriptions.SequenceTests ‑ ShouldReturnFirstBefore(CommitPosition { Position: 0, Sequence: 1, Timestamp: 2025-11-22T14:34:36.8503773+00:00 }, CommitPosition { Position: 0, Sequence: 2, Timestamp: 2025-11-22T14:34:36.8503773+00:00 }, CommitPosition { Position: 0, Sequence: 4, Timestamp: 2025-11-22T14:34:36.8503773+00:00 }, CommitPosition { Position: 0, Sequence: 6, Timestamp: 2025-11-22T14:34:36.8503773+00:00 }, CommitPosition { Position: 0, Sequence: 2, Timestamp: 2025-11-22T14:34:36.8503773+00:00 })
…

@alexeyzimarev
Copy link
Contributor

Replaced by #474

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants