private async Task Wait(int timeout = 3000) { var sw = Stopwatch.StartNew(); var maxCheckpoint = await _fixture.EventStore.ReadHeadPosition(CancellationToken.None).ConfigureAwait(false); AllStreamPosition checkpoint = AllStreamPosition.None; while (sw.ElapsedMilliseconds < timeout) { if (_fixture.Observer.All.Any()) { // var name = _fixture.Observer.All.First().Key; // var id = ProjectionPosition.GetIdFromName(name); // using (var s = _fixture.SessionFactory()) // { // var cp = await s.LoadAsync<ProjectionPosition>(id).ConfigureAwait(false); // checkpoint = AllStreamPosition.FromNullableInt64(cp?.Position); // } if (_fixture.Observer.Min >= maxCheckpoint) { return; } } await Task.Delay(300); } foreach (var state in _fixture.Observer.All.Values) { _writeLine($"[{state.Name}]: {state.Checkpoint} {state.Suspended} {state.Exception}"); } throw new TimeoutException(); }
private ReadAllPage Read(AllStreamPosition from) { var maxPosition = MaxPosition; _writeLine($"From {from}, Max {maxPosition}"); if (from > MaxPosition) { var page = new ReadAllPage(from, from, true, new Envelope[0]); _writeLine(page.ToString()); return(page); } var messages = Enumerable.Range(0, 10) .Where(x => x <= maxPosition - from.ToInt64()) .Select(x => new Envelope(from.Shift(x), x)) .ToArray(); bool isEnd = !messages.Any() || messages.Last().Checkpoint.ToInt64() == maxPosition; var result = new ReadAllPage( from, messages.Any() ? messages.Last().Checkpoint.Shift() : from, isEnd, messages); _writeLine(result.ToString()); return(result); }
public async Task Notification_on_position_change() { // this also verifies cancellation (await Wait()).ShouldBeFalse(); _currentPosition = _currentPosition.Shift(); (await Wait()).ShouldBeTrue(); }
public async Task Recovers_on_error() { _currentPosition = new AllStreamPosition(9998); (await Wait()).ShouldBeTrue(); _currentPosition = _currentPosition.Shift(); (await Wait()).ShouldBeFalse(); (await _error.Task.ConfigureAwait(false)).ShouldBeOfType <InvalidOperationException>(); _currentPosition = _currentPosition.Shift(); (await Wait()).ShouldBeTrue(); }
private Task <IDisposable> CreateSubscription( AllStreamPosition fromPosition, MessageReceived onMessage, HasCaughtUp hasCaughtUp, Func <Exception, Task> onSubscriptionError) => Task.FromResult <IDisposable>(new GenericSubscription( (from, ct) => EventStore.ReadForward(from, cancellationToken: ct), fromPosition, Notifier.WaitForNotification, onMessage, onSubscriptionError, hasCaughtUp));
/// <summary> /// Subscribes to latest changes. /// Only supports a single subscriber at a time, based on notifier implementation. /// </summary> public Task <IDisposable> Subscribe( AllStreamPosition fromPosition, MessageReceived onMessage, HasCaughtUp hasCaughtUp, Func <Exception, Task> onSubscriptionError) => Task.FromResult <IDisposable>( new GenericSubscription( (f, ct) => ReadForward(f, 10, ct), fromPosition, _notifier.WaitForNotification, onMessage, onSubscriptionError, hasCaughtUp));
public PollingNotifierTests() { _currentPosition = AllStreamPosition.None; _notifier = new PollingNotifier( _ => _currentPosition.ToInt64() != 9999 ? Task.FromResult(_currentPosition) : throw new InvalidOperationException("Error happened"), (ex, p) => { _error.SetResult(ex); // this actually fails 2nd+ time (intentional) return(Task.CompletedTask); }, interval: Interval); }
public async Task Checkpoint_is_stored_on_commit() { var expected = new AllStreamPosition(10); using (var cpStore = Util.BuildCheckpointStore()) using (var sut = new CheckpointProjection(new DelegateProjection(), cpStore)) { await sut.Project(new Envelope(expected, null)); await sut.Commit(); cpStore.Read().ShouldBe(expected.ToInt64()); } }
public SubscriptionFixture(Action <string> writeLine, long maxPosition = 20, long handlerExceptionPosition = -2) { _writeLine = writeLine; _cts = new CancellationTokenSource(); MaxPosition = maxPosition; AllStreamPosition hasCaughtUpTrigger = AllStreamPosition.None; AllStreamPosition notifierTrigger = AllStreamPosition.None; ReadAllPageFunc readAllPage = (from, ct) => Task.FromResult(Read(from)); MessageReceived handler = (s, m, ct) => { LastProcessed = m.Checkpoint; if (m.Checkpoint == handlerExceptionPosition) { throw new InvalidOperationException("Custom exception thrown"); } return(Task.CompletedTask); }; Func <Exception, Task> onError = ex => Async(() => _exceptionSource.SetResult(ex)); HasCaughtUp hasCaughtUp = () => Async(() => hasCaughtUpTrigger = hasCaughtUpTrigger.Shift()); var hasCaughtUpNotifier = new PollingNotifier(_ => Task.FromResult(hasCaughtUpTrigger)); var notifier = new PollingNotifier(_ => Task.FromResult(notifierTrigger)); Subscription = new GenericSubscription( readAllPage, AllStreamPosition.None, notifier.WaitForNotification, handler, onError, hasCaughtUp); var cancellationToken = _cts.Token; cancellationToken.Register(() => { Subscription.Dispose(); notifier.Dispose(); hasCaughtUpNotifier.Dispose(); }); WaitForCaughtUp = () => hasCaughtUpNotifier.WaitForNotification(cancellationToken); AppendEvents = c => { MaxPosition += c; notifierTrigger = notifierTrigger.Shift(); }; }
public static async Task LoadCheckpoints( Func <IAsyncDocumentSession> sessionFactory, ProjectionGroupStateObserver observer, IEnumerable <string> keys) { using (var session = sessionFactory()) { var docs = await session.LoadAsync <ProjectionPosition>( keys.Select(ProjectionPosition.GetIdFromName)).ConfigureAwait(false); var pairs = keys.Zip(docs, (k, d) => new KeyValuePair <string, AllStreamPosition>(k, AllStreamPosition.FromNullableInt64(d?.Position))); foreach (var pair in pairs) { observer.MoveTo(pair.Key, pair.Value); } } }
public async Task Checkpoint_is_notified_but_not_stored_on_project() { var expected = new AllStreamPosition(10); AllStreamPosition projected = AllStreamPosition.None; AllStreamPosition notified = AllStreamPosition.None; using (var cpStore = Util.BuildCheckpointStore()) using (var sut = new CheckpointProjection( Util.Projection(m => projected = m.Checkpoint), cpStore, p => notified = p)) { await sut.Project(new Envelope(expected, null)); projected.ShouldBe(expected); notified.ShouldBe(expected); cpStore.Read().ShouldBeNull(); } }
private Task <IDisposable> CreateSubscription( AllStreamPosition fromPosition, MessageReceived onMessage, LocalProjections.HasCaughtUp hasCaughtUp, Func <Exception, Task> onSubscriptionError) { SqlStreamStore.Subscriptions.AllStreamMessageReceived receivedHandler = (s, m) => onMessage(s, new Envelope(new AllStreamPosition(m.Position), m), CancellationToken.None); SqlStreamStore.Subscriptions.AllSubscriptionDropped subscriptionDroppedHandler = (s, r, e) => (r != SubscriptionDroppedReason.Disposed ? onSubscriptionError(e) : Task.CompletedTask) .GetAwaiter().GetResult(); SqlStreamStore.Subscriptions.HasCaughtUp caughtUpHandler = caughtUp => (caughtUp == true ? hasCaughtUp() : Task.CompletedTask).GetAwaiter().GetResult(); var subscription = EventStore.SubscribeToAll( fromPosition.ToNullableInt64(), receivedHandler, subscriptionDroppedHandler, caughtUpHandler); return(Task.FromResult <IDisposable>(subscription)); }
public Task <ReadAllPage> ReadForward( AllStreamPosition from = default(AllStreamPosition), int batchSize = 10, CancellationToken cancellationToken = default(CancellationToken)) { var pairs = _allStream.ReadAfter(from.ToInt64() - 1, batchSize); var messages = pairs.Select(p => new Envelope( TranslateKey(p.Key), Serializer.DeserializeJson <DocumentSaved>(p.Value))) .ToArray(); if (messages.Length == 0) { return(Task.FromResult(new ReadAllPage(from, from, true, new Envelope[0]))); } var next = messages.Last().Checkpoint.Shift(); var isEnd = _allStream.GetLastCheckpoint().Key < next; return(Task.FromResult(new ReadAllPage(from, next, isEnd, messages))); }
public async Task Only_first_messages_before_error_are_processed() { var expected = new AllStreamPosition(3); AllStreamPosition lastCheckpoint = AllStreamPosition.None; using (var sut = new SuspendableProjection( Util.Projection(m => { lastCheckpoint = m.Checkpoint; if (m.Checkpoint == expected) { throw new Exception("test"); } }))) { for (int i = 1; i < 5; i++) { await sut.Project(new Envelope(new AllStreamPosition(i), null)); } } lastCheckpoint.ShouldBe(expected); }
public async Task Commit_happens_only_after_nth_attempt(int n) { AllStreamPosition projected = AllStreamPosition.None; bool committed = false; using (var sut = new CommitNthProjection( Util.Projection(m => projected = m.Checkpoint, () => committed = true), n)) { for (int i = 0; i < n; i++) { var expected = new AllStreamPosition(i); await sut.Project(new Envelope(expected, null)); projected.ShouldBe(expected); if (i < n - 1) { committed.ShouldBeFalse(); } } } committed.ShouldBeTrue(); }
public Envelope(AllStreamPosition checkpoint, object payload) { Checkpoint = checkpoint; Payload = payload; }