io.axoniq.axonserver.connector.event.EventChannel Maven / Gradle / Ivy
/*
* Copyright (c) 2020. AxonIQ
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.axoniq.axonserver.connector.event;
import io.axoniq.axonserver.grpc.InstructionAck;
import io.axoniq.axonserver.grpc.event.Confirmation;
import io.axoniq.axonserver.grpc.event.Event;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.CompletableFuture;
/**
* Communication channel for Event related interactions with AxonServer.
*/
public interface EventChannel {
/**
* Starts a new transaction to append events.
*
* @return The transaction reference onto which to register events to append
*/
AppendEventsTransaction startAppendEventsTransaction();
/**
* Schedule the given {@code event} to be published after given {@code triggerDuration}. The returned value can be
* used to cancel the schedule, or to reschedule the event to another time.
*
* @param triggerDuration the amount of time to wait to publish the event
* @param event the event to publish
* @return a token used to cancel the schedule
*/
default CompletableFuture scheduleEvent(Duration triggerDuration, Event event) {
return scheduleEvent(Instant.now().plus(triggerDuration), event);
}
/**
* Schedule the given {@code event} to be published at given {@code scheduleTime}. The returned value can be used to
* cancel the schedule, or to reschedule the event to another time.
*
* @param scheduleTime The scheduleTime at which to publish the event
* @param event The event to publish
* @return a token used to cancel the schedule
*/
CompletableFuture scheduleEvent(Instant scheduleTime, Event event);
/**
* Cancels the scheduled publication of an event for which the given {@code scheduleToken} was returned.
*
* @param scheduleToken the token provided when scheduling the event to be cancelled
* @return a future reference to the result of the instruction
*/
CompletableFuture cancelSchedule(String scheduleToken);
/**
* Convenience method to cancel the scheduled event with given {@code scheduleToken} and reschedule the given {@code
* event} to be published after given {@code triggerDuration}. Is effectively the same as cancelling and scheduling
* in separate calls, but this call requires only a single round-trip to the server.
*
* @param scheduleToken the token of the event to cancel
* @param triggerDuration the point amount of time to wait to publish the event
* @param event the event to publish
* @return a future reference to the token for the new schedule
*/
default CompletableFuture reschedule(String scheduleToken, Duration triggerDuration, Event event) {
return reschedule(scheduleToken, Instant.now().plus(triggerDuration), event);
}
/**
* Convenience method to cancel the scheduled event with given {@code scheduleToken} and reschedule the given {@code
* event} to be published at given {@code scheduleTime}. Is effectively the same as cancelling and scheduling in
* separate calls, but this call requires only a single round-trip to the server.
*
* @param scheduleToken the token of the event to cancel
* @param scheduleTime the point in time to publish the new event
* @param event the event to publish
* @return a future reference to the token for the new schedule
*/
CompletableFuture reschedule(String scheduleToken, Instant scheduleTime, Event event);
/**
* Append the given {@code events} to the Event Store. Prior to starting, the {@link
* #startAppendEventsTransaction()} method should be invoked
*
* @param events the {@link Event}s to append to the Event Store
* @return a {@link CompletableFuture} resolving the confirmation of the successful processing of the append
* transaction
*/
default CompletableFuture appendEvents(Event... events) {
AppendEventsTransaction tx = startAppendEventsTransaction();
for (Event event : events) {
tx.appendEvent(event);
}
return tx.commit();
}
/**
* Find the highest sequence number (i.e. the sequence number of the most recent event) for an aggregate with given
* {@code aggregateId}.
*
* If no events for an aggregate with given identifier have been found, the returned CompletableFuture will resolve
* to a {@code null} value.
*
* @param aggregateId the identifier of the aggregate to find the sequence number for
* @return a CompletableFuture providing the sequence number found, or resolving to {@code null} when no event was
* found.
*/
CompletableFuture findHighestSequence(String aggregateId);
/**
* Opens an EventStream, for sequentially consuming events from AxonServer, starting at given {@code token} and
* keeping a local buffer of {@code bufferSize}. When consuming 1/8th of the buffer size (with a minimum of 16), the
* client will request additional messages to keep the buffer filled.
*
* A value for {@code bufferSize} smaller than 64 items will result in a buffer of 64.
*
* The stream of Events starts immediately upon the invocation of this method, making the first messages available
* for consumption as soon as they have arrived from AxonServer.
*
* @param token the token representing the position to start the stream, or {@code -1} to start from beginning
* @param bufferSize the number of events to buffer locally
* @return the Stream for consuming the requested Events
* @see #openStream(long, int, int) to configure the refill frequency.
*/
default EventStream openStream(long token, int bufferSize) {
return openStream(token, bufferSize, Math.max(bufferSize >> 3, 16));
}
/**
* Open an EventStream, for sequentially consuming events from AxonServer, starting at given {@code token} and
* keeping a local buffer of {@code bufferSize}, which is refilled after consuming {@code refillBatch} items.
*
* A value for {@code bufferSize} smaller than 64 items will result in a buffer of 64. A value for {@code
* refillBatch} smaller than 16 will result in a refill batch of 16. A value larger than the {@code bufferSize} will
* be reduced to match the given {@code bufferSize}. While this will work, it is not recommended. The {@code
* refillBatch} should be sufficiently small to allow for a constant flow of messages to consume.
*
* The stream of Events starts immediately upon the invocation of this method, making the first messages available
* for consumption as soon as they have arrived from AxonServer.
*
* @param token the token representing the position to start the stream, or {@code -1} to start from
* beginning
* @param bufferSize the number of events to buffer locally
* @param refillBatch the number of events to be consumed prior to refilling the buffer
* @return the Stream for consuming the requested Events
* @see #openStream(long, int) to use a sensible default for refill batch value.
*/
default EventStream openStream(long token, int bufferSize, int refillBatch) {
return openStream(token, bufferSize, refillBatch, false);
}
/**
* Open an EventStream, for sequentially consuming events from AxonServer, starting at given {@code token} and
* keeping a local buffer of {@code bufferSize}, which is refilled after consuming {@code refillBatch} items. The
* {@code forceReadFromLeader} parameter can be used to enforce this stream to read events from the RAFT leader.
*
* A value for {@code bufferSize} smaller than 64 items will result in a buffer of 64. A value for {@code
* refillBatch} smaller than 16 will result in a refill batch of 16. A value larger than the {@code bufferSize} will
* be reduced to match the given {@code bufferSize}. While this will work, it is not recommended. The {@code
* refillBatch} should be sufficiently small to allow for a constant flow of messages to consume.
*
* The stream of Events starts immediately upon the invocation of this method, making the first messages available
* for consumption as soon as they have arrived from AxonServer.
*
* @param token the token representing the position to start the stream, or {@code -1} to start from
* beginning
* @param bufferSize the number of events to buffer locally
* @param refillBatch the number of events to be consumed prior to refilling the buffer
* @param forceReadFromLeader a {@code boolean} defining whether Events must be read from the leader
* @return the Stream for consuming the requested Events
* @see #openStream(long, int) to use a sensible default for refill batch value.
*/
EventStream openStream(long token, int bufferSize, int refillBatch, boolean forceReadFromLeader);
/**
* Opens a stream for consuming Events from a single aggregate, allowing the first event to be a Snapshot Event.
*
* Note that this method does not have any form of flow control. All messages are buffered locally. When expecting
* large streams of events, consider using {@link #openAggregateStream(String, long, long)} to retrieve chunks of
* the event stream instead.
*
* @param aggregateIdentifier the identifier of the Aggregate to load events for
* @return a stream of Events for the given Aggregate, for which the first event can be a Snapshot Event
*/
default AggregateEventStream openAggregateStream(String aggregateIdentifier) {
return openAggregateStream(aggregateIdentifier, true);
}
/**
* Opens a stream for consuming Events from a single aggregate, with given {@code allowSnapshots} indicating whether
* the first Event may be a Snapshot Event. When given {@code allowSnapshots} is {@code false}, this method will
* return events starting at the first available sequence number of the aggregate (typically 0).
*
* Note that this method does not have any form of flow control. All messages are buffered locally. When expecting
* large streams of events, consider using {@link #openAggregateStream(String, long, long)} to retrieve chunks of
* the event stream instead.
*
* @param aggregateIdentifier the identifier of the Aggregate to load events for
* @param allowSnapshots a {@code boolean} whether to allow a snapshot event as first event, or not
* @return a stream of Events for the given Aggregate
*/
AggregateEventStream openAggregateStream(String aggregateIdentifier, boolean allowSnapshots);
/**
* Opens a stream for consuming Events from a single aggregate, starting with the given {@code initialSequence}.
* This method will not return a Snapshot Event as first event.
*
* Note that this method does not have any form of flow control. All messages are buffered locally. When expecting
* large streams of events, consider using {@link #openAggregateStream(String, long, long)} to retrieve chunks of
* the event stream instead.
*
* @param aggregateIdentifier the identifier of the Aggregate to load events for
* @param initialSequence the sequence number of the first event to return
* @return a stream of Events for the given Aggregate
*/
default AggregateEventStream openAggregateStream(String aggregateIdentifier, long initialSequence) {
return openAggregateStream(aggregateIdentifier, initialSequence, 0);
}
/**
* Opens a stream for consuming Events from a single aggregate, starting with the given {@code initialSequence}
* until the given {@code maxSequence}. This method will not return a Snapshot Event as first event.
*
* Note: a {@code maxSequence} of {@code 0} will result in all events after the initial sequence to be returned.
*
* @param aggregateIdentifier the identifier of the Aggregate to load events for
* @param initialSequence the sequence number of the first event to return
* @param maxSequence the sequence number of the last event to return
* @return a stream of Events for the given Aggregate
*/
AggregateEventStream openAggregateStream(String aggregateIdentifier, long initialSequence, long maxSequence);
/**
* Store the given {@code snapshotEvent}.
*
* @param snapshotEvent the Snapshot Event to store
* @return a CompletableFuture providing the confirmation upon storage of the snapshot
*/
CompletableFuture appendSnapshot(Event snapshotEvent);
/**
* Loads the Snapshot Event for the given {@code aggregateIdentifier} with the highest sequence number.
*
* Note that the returned stream may not yield any result when there are no snapshots available.
*
* @param aggregateIdentifier the identifier of the Aggregate to retrieve snapshots for
* @return a stream containing the most recent Snapshot Event
*/
default AggregateEventStream loadSnapshot(String aggregateIdentifier) {
return loadSnapshots(aggregateIdentifier, 0, Long.MAX_VALUE, 1);
}
/**
* Loads Snapshot Events for the given {@code aggregateIdentifier} with sequence number lower or equal to {@code
* maxSequence}, returning at most {@code maxResults} number of snapshots.
*
* Note that Snapshot Events are returned in reverse order of their sequence number.
*
* @param aggregateIdentifier the identifier of the Aggregate to retrieve snapshots for
* @param maxSequence the highest sequence number of snapshots to return
* @param maxResults the maximum allowed number of snapshots to return
* @return a stream containing Snapshot Events within the requested bounds
*/
default AggregateEventStream loadSnapshots(String aggregateIdentifier, long maxSequence, int maxResults) {
return loadSnapshots(aggregateIdentifier, 0, maxSequence, maxResults);
}
/**
* Loads Snapshot Events for the given {@code aggregateIdentifier} with sequence number between {@code
* initialSequence} and {@code maxSequence} (inclusive), returning at most {@code maxResults} number of snapshots.
*
* Note that Snapshot Events are returned in reverse order of their sequence number.
*
* @param aggregateIdentifier the identifier of the Aggregate to retrieve snapshots for
* @param initialSequence the lowest sequence number of snapshots to return
* @param maxSequence the highest sequence number of snapshots to return
* @param maxResults the maximum allowed number of snapshots to return
* @return a stream containing Snapshot Events within the requested bounds
*/
AggregateEventStream loadSnapshots(String aggregateIdentifier,
long initialSequence,
long maxSequence,
int maxResults);
/**
* Retrieves the Token referring to the most recent Event in the Event Store. Using this token to open a stream will
* only yield events that were appended after execution of this call.
*
* @return a completable future resolving the Token of the last (i.e. most recent) event
*/
CompletableFuture getLastToken();
/**
* Retrieves the Token referring to the first Event in the Event Store. Using this token to open a stream will yield
* all events that available in the event store.
*
* @return a completable future resolving the Token of the first (i.e. oldest) event
*/
CompletableFuture getFirstToken();
/**
* Retrieves the Token referring to the first Event in the Event Store with a timestamp on or after given {@code
* instant}. Using this token to open a stream will yield all events with a timestamp starting at that instance, but
* may also yield events that were created before this {@code instant}, whose append transaction was completed after
* the {@code instant}.
*
* @return a completable future resolving the Token of the first (i.e. oldest) event with timestamp on or after
* given {@code instant}
*/
CompletableFuture getTokenAt(long instant);
}