Appending many
Appending many events in a single call is useful for batch workflows such as imports, migrations, or multi-step business operations.
Batch appends preserve ordering and reduce per-event overhead compared to appending each event individually.
AppendMany is transactional all the way to storage. Either all events in the batch are committed, or none are. Chronicle assigns sequence numbers in order, persists the events and metadata atomically, and updates the sequence state once the batch succeeds.
How it works
Section titled “How it works”- Each item in the batch pairs an event with the event source it belongs to.
- The batch is validated as a unit and written atomically.
- Sequence numbers are assigned in the order provided.
- The event sequence state is updated once the batch commits.
When to use
Section titled “When to use”Use this approach when you already have a set of events that should be appended together. Each event can still target different event sources, and you can include concurrency scopes to validate the boundary across streams. See Concurrency for details.
Example
Section titled “Example”using Cratis.Chronicle.EventSequences;using Cratis.Chronicle.Events;
public readonly record struct AccountId(string Value){ public static implicit operator EventSourceId(AccountId id) => new(id.Value);}
[EventType]public record MoneyWithdrawn(decimal Amount);
[EventType]public record MoneyDeposited(decimal Amount);
public class TransferService(IEventLog eventLog){ public Task<AppendManyResult> Transfer(AccountId fromAccount, AccountId toAccount, decimal amount) { var events = new[] { new EventForEventSourceId(fromAccount, new MoneyWithdrawn(amount)), new EventForEventSourceId(toAccount, new MoneyDeposited(amount)) };
return eventLog.AppendMany(events); }}The Kotlin Chronicle client does not support this workflow yet.It can append several events for one event source, but it does not currently expose a transactional multi-source append-many API.The Java Chronicle client does not support this workflow yet.It can use the JVM client APIs, but it does not currently expose a transactional multi-source append-many API.The Elixir Chronicle client does not support this workflow yet.It can append several events for one event source, but it does not currently expose a transactional multi-source append-many API.import { eventType, EventForEventSourceId, IEventStore } from '@cratis/chronicle';
@eventType()class MoneyWithdrawn { constructor(readonly amount: number) {}}
@eventType()class MoneyDeposited { constructor(readonly amount: number) {}}
class TransferService { constructor(private readonly store: IEventStore) {}
async transfer(fromAccount: string, toAccount: string, amount: number): Promise<void> { const events: EventForEventSourceId[] = [ { eventSourceId: fromAccount, event: new MoneyWithdrawn(amount) }, { eventSourceId: toAccount, event: new MoneyDeposited(amount) } ];
const results = await this.store.eventLog.appendMany(events);
if (results.some(_ => !_.isSuccess)) { // Decide whether to retry or surface a conflict to the caller. } }}