Skip to content

Observing Append Operations

IEventSequence exposes an AppendOperations observable that emits after every Append or AppendMany call on that sequence. Any code can subscribe to this observable to react to appended events in real time — without polling the event log.

IObservable<IEnumerable<AppendedEventWithResult>> AppendOperations { get; }

The observable emits a collection of AppendedEventWithResult after each operation:

  • A single-event Append emits a collection containing one element.
  • A batch AppendMany emits the full batch as one collection.

Each AppendedEventWithResult pairs the appended event with its result:

MemberTypeDescription
EventAppendedEventThe appended event, including context and deserialized content
Event.ContentobjectThe deserialized event object
Event.ContextEventContextMetadata: event source, sequence number, correlation ID, causation chain
ResultAppendResultSuccess flag, sequence number, violations, and errors

Subscribers receive the notification after the operation has completed, whether it succeeded or failed. This observable does not fire for transactional appends through ITransactionalEventSequence.

Inject IEventSequence (or IEventLog) and subscribe to AppendOperations:

public class AppendMonitor(IEventLog eventLog) : IDisposable
{
readonly IDisposable _subscription = eventLog.AppendOperations.Subscribe(OnAppended);
static void OnAppended(IEnumerable<AppendedEventWithResult> operations)
{
foreach (var item in operations)
{
Console.WriteLine($"Event {item.Event.Content.GetType().Name} appended: success={item.Result.IsSuccess}");
}
}
public void Dispose() => _subscription.Dispose();
}

Always dispose the subscription when you no longer need it to avoid resource leaks.

The most common use of AppendOperations in application code is through the IEventAppendCollection helper provided by Cratis.Chronicle.XUnit.Integration. It subscribes internally and provides a ready-to-assert collection of AppendedEventWithResult entries. See Chronicle.Testing.EventAppendCollection for full details.

Waiting for Observer Completion After Append

Section titled “Waiting for Observer Completion After Append”

When you need to wait until observers affected by an append operation have completed, use WaitForCompletion() from the Cratis.Chronicle.Observation namespace.

If any affected observer fails while catching up, the returned result includes failed partitions.

using Cratis.Chronicle.Observation;
var appendResult = await eventLog.Append(eventSourceId, new SomeEvent());
var completion = await appendResult.WaitForCompletion();
if (!completion.IsSuccess)
{
foreach (var failedPartition in completion.FailedPartitions)
{
Console.WriteLine($"Observer {failedPartition.ObserverId} failed partition {failedPartition.Partition}");
}
}
using Cratis.Chronicle.Observation;
var appendManyResult = await eventLog.AppendMany(eventSourceId, new object[]
{
new FirstEvent(),
new SecondEvent()
});
var completion = await appendManyResult.WaitForCompletion();
if (!completion.IsSuccess)
{
// Inspect failed partitions from affected observers
}