diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index bf1dfc50b..dcf7fd415 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -18,7 +18,6 @@ jobs: - 'Events.Store.Streams.StreamProcessorStateRepository' - 'Events.Processing.EventHandlers.EventHandler' - 'Events.Processing.EventHandlers.FastEventHandler' -# - 'Events.Processing.EventHandlers.FastEventHandlerWithImplicitFilter' - 'Events.Processing.EventHandlers.Filter' - 'Events.Processing.Projections.Projection' env: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f69ec4d57..ac343a756 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,7 +1,7 @@ name: Release env: - PRERELEASE_BRANCHES: bad-aggregate + PRERELEASE_BRANCHES: hadhafang on: pull_request: @@ -62,10 +62,8 @@ jobs: - 'Events.Store.FetchAggregateEvents' - 'Events.Store.Streams.StreamProcessorStateRepository' - 'Events.Processing.EventHandlers.EventHandler' - - 'Events.Processing.EventHandlers.FastEventHandler' -# - 'Events.Processing.EventHandlers.FastEventHandlerWithImplicitFilter' - 'Events.Processing.EventHandlers.Filter' - - 'Events.Processing.Projections.Projection' + - 'Events.Processing.Projections' env: BENCHMARK_NAME: Integration.Benchmarks.${{ matrix.benchmark }} steps: diff --git a/Configurations/consumer/.dolittle/runtime.yml b/Configurations/consumer/.dolittle/runtime.yml new file mode 100644 index 000000000..d32773887 --- /dev/null +++ b/Configurations/consumer/.dolittle/runtime.yml @@ -0,0 +1,48 @@ +opentelemetry: + serviceName: "Consumer-Runtime" +endpoints: + private: + port: 5055 + public: + port: 5054 + management: + port: 5252 + managementweb: + port: 5452 + metrics: + port: 9701 + web: + port: 8009 +platform: + applicationName: "EventHorizon Tutorial" + applicationID: "5bd8762f-6c39-4ba2-a141-d041c8668894" + microserviceName: "Consumer" + microserviceID: "a14bb24e-51f3-4d83-9eba-44c4cffe6bb9" + customerName: "Dolittle Tacos" + customerID: "c2d49e3e-9bd4-4e54-9e13-3ea4e04d8230" + environment: "Tutorial" +microservices: + f39b1f61-d360-4675-b859-53c05c87c0e6: + host: localhost + port: 5052 +tenants: + 445f8ea8-1a6f-40d7-b2fc-796dba92dc44: + resources: + eventStore: + servers: + - localhost + database: "consumer_event_store" + projections: + servers: + - localhost + database: "consumer_projections" + maxConnectionPoolSize: 1000 + embeddings: + servers: + - localhost + database: "consumer_embeddings" + maxConnectionPoolSize: 1000 + readModels: + host: "mongodb://localhost:27017" + database: "consumer_readmodels" + useSSL: false diff --git a/Configurations/producer/.dolittle/runtime.yml b/Configurations/producer/.dolittle/runtime.yml new file mode 100644 index 000000000..095d5038f --- /dev/null +++ b/Configurations/producer/.dolittle/runtime.yml @@ -0,0 +1,47 @@ +opentelemetry: + serviceName: "Producer-Runtime" +endpoints: + private: + port: 5053 + public: + port: 5052 + management: + port: 5152 + managementweb: + port: 5352 +platform: + applicationName: "EventHorizon Tutorial" + applicationID: "5bd8762f-6c39-4ba2-a141-d041c8668894" + microserviceName: "Producer" + microserviceID: "f39b1f61-d360-4675-b859-53c05c87c0e6" + customerName: "Dolittle Tacos" + customerID: "c2d49e3e-9bd4-4e54-9e13-3ea4e04d8230" + environment: "Tutorial" +tenants: + 445f8ea8-1a6f-40d7-b2fc-796dba92dc44: + resources: + eventStore: + servers: + - localhost + database: "producer_event_store" + projections: + servers: + - localhost + database: "producer_projections" + maxConnectionPoolSize: 1000 + embeddings: + servers: + - localhost + database: "producer_embeddings" + maxConnectionPoolSize: 1000 + readModels: + host: "mongodb://localhost:27017" + database: "producer_readmodels" + useSSL: false + eventHorizons: + a14bb24e-51f3-4d83-9eba-44c4cffe6bb9: + consents: + - consumerTenant: "445f8ea8-1a6f-40d7-b2fc-796dba92dc44" + stream: "2c087657-b318-40b1-ae92-a400de44e507" + partition: "Dolittle Tacos" + consent: "ad57aa2b-e641-4251-b800-dd171e175d1f" diff --git a/Integration/Benchmarks/Events.Processing/EventHandlers/EventHandler.cs b/Integration/Benchmarks/Events.Processing/EventHandlers/EventHandler.cs index 32ef5cd33..82a8ed9c3 100644 --- a/Integration/Benchmarks/Events.Processing/EventHandlers/EventHandler.cs +++ b/Integration/Benchmarks/Events.Processing/EventHandlers/EventHandler.cs @@ -11,11 +11,9 @@ using Dolittle.Runtime.Events.Processing.Contracts; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store; -using Integration.Benchmarks.Events.Store; using Integration.Shared; using Microsoft.Extensions.DependencyInjection; using Moq; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; using ReverseCallDispatcher = Dolittle.Runtime.Services.IReverseCallDispatcher< Dolittle.Runtime.Events.Processing.Contracts.EventHandlerClientToRuntimeMessage, Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRuntimeToClientMessage, @@ -88,7 +86,7 @@ public void IterationSetup() var eventHandlers = new List(); eventHandlers.AddRange(Enumerable.Range(0, EventHandlers).Select(_ => _eventHandlerFactory.Create( - new EventHandlerRegistrationArguments(Runtime.CreateExecutionContextFor("d9fd643f-ce74-4ae5-b706-b76859fd8827"), Guid.NewGuid(), _eventTypes, Partitioned, ScopeId.Default), + new EventHandlerRegistrationArguments(Runtime.CreateExecutionContextFor("d9fd643f-ce74-4ae5-b706-b76859fd8827"), Guid.NewGuid(), _eventTypes, Partitioned, ScopeId.Default, Concurrency), _dispatcher.Object, CancellationToken.None))); _eventHandlersToRun = eventHandlers; @@ -125,6 +123,10 @@ public void IterationCleanup() // [Params(1, 10)] TODO: We can maybe enable this in the future, but as of now it seems that the performance depends on the amount of events processed. public int EventTypes { get; set; } = 1; + + [Params(1, 20)] + public int Concurrency { get; set; } = 1; + /// /// Gets the number of events committed per configured event type. /// diff --git a/Integration/Benchmarks/Events.Processing/EventHandlers/FastEventHandler.cs b/Integration/Benchmarks/Events.Processing/EventHandlers/FastEventHandler.cs index 956fc1b06..bfbcd454c 100644 --- a/Integration/Benchmarks/Events.Processing/EventHandlers/FastEventHandler.cs +++ b/Integration/Benchmarks/Events.Processing/EventHandlers/FastEventHandler.cs @@ -1,152 +1,151 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using BenchmarkDotNet.Attributes; -using Dolittle.Runtime.Artifacts; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Events.Processing.Contracts; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Integration.Shared; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using ReverseCallDispatcher = Dolittle.Runtime.Services.IReverseCallDispatcher< - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerClientToRuntimeMessage, - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRuntimeToClientMessage, - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRegistrationRequest, - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRegistrationResponse, - Dolittle.Runtime.Events.Processing.Contracts.HandleEventRequest, - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerResponse>; - -namespace Integration.Benchmarks.Events.Processing.EventHandlers; - - -/// -/// Benchmarks for Event Handlers. -/// -public class FastEventHandler : JobBase -{ - IEventStore _eventStore; - IEventHandlers _eventHandlers; - IEventHandlerFactory _eventHandlerFactory; - IEnumerable _eventHandlersToRun; - ArtifactId[] _eventTypes; - Mock _dispatcher; - - /// - protected override void Setup(IServiceProvider services) - { - _eventStore = services.GetRequiredService(); - _eventHandlers = services.GetRequiredService(); - _eventHandlerFactory = services.GetRequiredService(); - - _eventTypes = Enumerable.Range(0, EventTypes).Select(_ => new ArtifactId(Guid.NewGuid())).ToArray(); - var uncommittedEvents = new List(); - foreach (var eventType in _eventTypes) - { - foreach (var _ in Enumerable.Range(0, Events)) - { - uncommittedEvents.Add(new UncommittedEvent("some event source", new Artifact(eventType, ArtifactGeneration.First), false, "{\"hello\": 42}")); - } - } - foreach (var tenant in ConfiguredTenants) - { - _eventStore.Commit(new UncommittedEvents(uncommittedEvents), Runtime.CreateExecutionContextFor(tenant)).GetAwaiter().GetResult(); - } - } - - [IterationSetup] - public void IterationSetup() - { - var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - var numEventsProcessed = 0; - _dispatcher = new Mock(); - _dispatcher - .Setup(_ => _.Reject(It.IsAny(), It.IsAny())) - .Returns(Task.CompletedTask); - _dispatcher - .Setup(_ => _.Accept(It.IsAny(), It.IsAny())) - .Returns(tcs.Task); - _dispatcher - .Setup(_ => _.Call(It.IsAny(), It.IsAny(), It.IsAny())) - .Returns((request, _, __) => - { - Interlocked.Add(ref numEventsProcessed, 1); - var response = new EventHandlerResponse(); - if (numEventsProcessed == NumberEventsToProcess) - { - tcs.SetResult(); - } - return Task.FromResult(response); - }); - - var eventHandlers = new List(); - eventHandlers.AddRange(Enumerable.Range(0, EventHandlers).Select(_ => _eventHandlerFactory.CreateFast( - new EventHandlerRegistrationArguments(Runtime.CreateExecutionContextFor("d9fd643f-ce74-4ae5-b706-b76859fd8827"), Guid.NewGuid(), _eventTypes, Partitioned, ScopeId.Default), - false, - _dispatcher.Object, - CancellationToken.None))); - _eventHandlersToRun = eventHandlers; - } - - [IterationCleanup] - public void IterationCleanup() - { - foreach (var eventHandler in _eventHandlersToRun) - { - eventHandler.Dispose(); - } - } - - /// - [Params(1, 2)] // TODO: Adding 10 here results in really slow benchmarks. Let's adding 100 when we've made this blazingly fast :) - public override int NumTenants { get; set; } - - /// - /// Gets the number of simultaneously running event handlers. - /// - [Params(1, 2, 5)] // TODO: Adding 10 here results in really slow benchmarks. Let's adding 100 when we've made this blazingly fast :) - public int EventHandlers { get; set; } - - /// - /// Gets the value indicating whether performing benchmark on a partitioned event handler or not. - /// - // [Params(false, true)] TODO: We can maybe enable this in the future, but as of now it seems that the performance is the same. - public bool Partitioned { get; set; } = true; - - /// - /// Gets the number of event types. - /// - // [Params(1, 10)] TODO: We can maybe enable this in the future, but as of now it seems that the performance depends on the amount of events processed. - public int EventTypes { get; set; } = 1; - - /// - /// Gets the number of events committed per configured event type. - /// - [Params(1, 10, 100)] // TODO: Adding 100 here results in really slow benchmarks. Let's adding 100 when we've made this blazingly fast :) - public int Events { get; set; } - - int NumberEventsToProcess => Events * EventTypes * NumTenants * EventHandlers; - - /// - /// Commits the events one-by-one in a loop. - /// - [Benchmark] - public Task RegisteringAndProcessing() - { - return Task.WhenAll(_eventHandlersToRun.Select(eventHandler => _eventHandlers.RegisterAndStart( - eventHandler, - (_, _) => _dispatcher.Object.Reject(new EventHandlerRegistrationResponse(), CancellationToken.None), - CancellationToken.None))); - } - - /// - protected override void Cleanup() - { - } -} +// // Copyright (c) Dolittle. All rights reserved. +// // Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// using System; +// using System.Collections.Generic; +// using System.Linq; +// using System.Threading; +// using System.Threading.Tasks; +// using BenchmarkDotNet.Attributes; +// using Dolittle.Runtime.Artifacts; +// using Dolittle.Runtime.Events.Processing.Contracts; +// using Dolittle.Runtime.Events.Processing.EventHandlers; +// using Dolittle.Runtime.Events.Store; +// using Integration.Shared; +// using Microsoft.Extensions.DependencyInjection; +// using Moq; +// using ReverseCallDispatcher = Dolittle.Runtime.Services.IReverseCallDispatcher< +// Dolittle.Runtime.Events.Processing.Contracts.EventHandlerClientToRuntimeMessage, +// Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRuntimeToClientMessage, +// Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRegistrationRequest, +// Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRegistrationResponse, +// Dolittle.Runtime.Events.Processing.Contracts.HandleEventRequest, +// Dolittle.Runtime.Events.Processing.Contracts.EventHandlerResponse>; +// +// namespace Integration.Benchmarks.Events.Processing.EventHandlers; +// +// +// /// +// /// Benchmarks for Event Handlers. +// /// +// public class FastEventHandler : JobBase +// { +// IEventStore _eventStore; +// IEventHandlers _eventHandlers; +// IEventHandlerFactory _eventHandlerFactory; +// IEnumerable _eventHandlersToRun; +// ArtifactId[] _eventTypes; +// Mock _dispatcher; +// +// /// +// protected override void Setup(IServiceProvider services) +// { +// _eventStore = services.GetRequiredService(); +// _eventHandlers = services.GetRequiredService(); +// _eventHandlerFactory = services.GetRequiredService(); +// +// _eventTypes = Enumerable.Range(0, EventTypes).Select(_ => new ArtifactId(Guid.NewGuid())).ToArray(); +// var uncommittedEvents = new List(); +// foreach (var eventType in _eventTypes) +// { +// foreach (var _ in Enumerable.Range(0, Events)) +// { +// uncommittedEvents.Add(new UncommittedEvent("some event source", new Artifact(eventType, ArtifactGeneration.First), false, "{\"hello\": 42}")); +// } +// } +// foreach (var tenant in ConfiguredTenants) +// { +// _eventStore.Commit(new UncommittedEvents(uncommittedEvents), Runtime.CreateExecutionContextFor(tenant)).GetAwaiter().GetResult(); +// } +// } +// +// [IterationSetup] +// public void IterationSetup() +// { +// var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); +// var numEventsProcessed = 0; +// _dispatcher = new Mock(); +// _dispatcher +// .Setup(_ => _.Reject(It.IsAny(), It.IsAny())) +// .Returns(Task.CompletedTask); +// _dispatcher +// .Setup(_ => _.Accept(It.IsAny(), It.IsAny())) +// .Returns(tcs.Task); +// _dispatcher +// .Setup(_ => _.Call(It.IsAny(), It.IsAny(), It.IsAny())) +// .Returns((request, _, __) => +// { +// Interlocked.Add(ref numEventsProcessed, 1); +// var response = new EventHandlerResponse(); +// if (numEventsProcessed == NumberEventsToProcess) +// { +// tcs.SetResult(); +// } +// return Task.FromResult(response); +// }); +// +// var eventHandlers = new List(); +// eventHandlers.AddRange(Enumerable.Range(0, EventHandlers).Select(_ => _eventHandlerFactory.CreateFast( +// new EventHandlerRegistrationArguments(Runtime.CreateExecutionContextFor("d9fd643f-ce74-4ae5-b706-b76859fd8827"), Guid.NewGuid(), _eventTypes, Partitioned, ScopeId.Default), +// false, +// _dispatcher.Object, +// CancellationToken.None))); +// _eventHandlersToRun = eventHandlers; +// } +// +// [IterationCleanup] +// public void IterationCleanup() +// { +// foreach (var eventHandler in _eventHandlersToRun) +// { +// eventHandler.Dispose(); +// } +// } +// +// /// +// [Params(1, 2)] // TODO: Adding 10 here results in really slow benchmarks. Let's adding 100 when we've made this blazingly fast :) +// public override int NumTenants { get; set; } +// +// /// +// /// Gets the number of simultaneously running event handlers. +// /// +// [Params(1, 2, 5)] // TODO: Adding 10 here results in really slow benchmarks. Let's adding 100 when we've made this blazingly fast :) +// public int EventHandlers { get; set; } +// +// /// +// /// Gets the value indicating whether performing benchmark on a partitioned event handler or not. +// /// +// // [Params(false, true)] TODO: We can maybe enable this in the future, but as of now it seems that the performance is the same. +// public bool Partitioned { get; set; } = true; +// +// /// +// /// Gets the number of event types. +// /// +// // [Params(1, 10)] TODO: We can maybe enable this in the future, but as of now it seems that the performance depends on the amount of events processed. +// public int EventTypes { get; set; } = 1; +// +// /// +// /// Gets the number of events committed per configured event type. +// /// +// [Params(1, 10, 100)] // TODO: Adding 100 here results in really slow benchmarks. Let's adding 100 when we've made this blazingly fast :) +// public int Events { get; set; } +// +// int NumberEventsToProcess => Events * EventTypes * NumTenants * EventHandlers; +// +// /// +// /// Commits the events one-by-one in a loop. +// /// +// [Benchmark] +// public Task RegisteringAndProcessing() +// { +// return Task.WhenAll(_eventHandlersToRun.Select(eventHandler => _eventHandlers.RegisterAndStart( +// eventHandler, +// (_, _) => _dispatcher.Object.Reject(new EventHandlerRegistrationResponse(), CancellationToken.None), +// CancellationToken.None))); +// } +// +// /// +// protected override void Cleanup() +// { +// } +// } diff --git a/Integration/Benchmarks/Events.Processing/EventHandlers/FastEventHandlerWithImplicitFilter.cs b/Integration/Benchmarks/Events.Processing/EventHandlers/FastEventHandlerWithImplicitFilter.cs index 6d5343f2c..d3596cda7 100644 --- a/Integration/Benchmarks/Events.Processing/EventHandlers/FastEventHandlerWithImplicitFilter.cs +++ b/Integration/Benchmarks/Events.Processing/EventHandlers/FastEventHandlerWithImplicitFilter.cs @@ -1,152 +1,151 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using BenchmarkDotNet.Attributes; -using Dolittle.Runtime.Artifacts; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Events.Processing.Contracts; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Integration.Shared; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using ReverseCallDispatcher = Dolittle.Runtime.Services.IReverseCallDispatcher< - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerClientToRuntimeMessage, - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRuntimeToClientMessage, - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRegistrationRequest, - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRegistrationResponse, - Dolittle.Runtime.Events.Processing.Contracts.HandleEventRequest, - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerResponse>; - -namespace Integration.Benchmarks.Events.Processing.EventHandlers; - - -/// -/// Benchmarks for Event Handlers. -/// -public class FastEventHandlerWithImplicitFilter : JobBase -{ - IEventStore _eventStore; - IEventHandlers _eventHandlers; - IEventHandlerFactory _eventHandlerFactory; - IEnumerable _eventHandlersToRun; - ArtifactId[] _eventTypes; - Mock _dispatcher; - - /// - protected override void Setup(IServiceProvider services) - { - _eventStore = services.GetRequiredService(); - _eventHandlers = services.GetRequiredService(); - _eventHandlerFactory = services.GetRequiredService(); - - _eventTypes = Enumerable.Range(0, EventTypes).Select(_ => new ArtifactId(Guid.NewGuid())).ToArray(); - var uncommittedEvents = new List(); - foreach (var eventType in _eventTypes) - { - foreach (var _ in Enumerable.Range(0, Events)) - { - uncommittedEvents.Add(new UncommittedEvent("some event source", new Artifact(eventType, ArtifactGeneration.First), false, "{\"hello\": 42}")); - } - } - foreach (var tenant in ConfiguredTenants) - { - _eventStore.Commit(new UncommittedEvents(uncommittedEvents), Runtime.CreateExecutionContextFor(tenant)).GetAwaiter().GetResult(); - } - } - - [IterationSetup] - public void IterationSetup() - { - var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - var numEventsProcessed = 0; - _dispatcher = new Mock(); - _dispatcher - .Setup(_ => _.Reject(It.IsAny(), It.IsAny())) - .Returns(Task.CompletedTask); - _dispatcher - .Setup(_ => _.Accept(It.IsAny(), It.IsAny())) - .Returns(tcs.Task); - _dispatcher - .Setup(_ => _.Call(It.IsAny(), It.IsAny(), It.IsAny())) - .Returns((request, _, __) => - { - Interlocked.Add(ref numEventsProcessed, 1); - var response = new EventHandlerResponse(); - if (numEventsProcessed == NumberEventsToProcess) - { - tcs.SetResult(); - } - return Task.FromResult(response); - }); - - var eventHandlers = new List(); - eventHandlers.AddRange(Enumerable.Range(0, EventHandlers).Select(_ => _eventHandlerFactory.CreateFast( - new EventHandlerRegistrationArguments(Runtime.CreateExecutionContextFor("d9fd643f-ce74-4ae5-b706-b76859fd8827"), Guid.NewGuid(), _eventTypes, Partitioned, ScopeId.Default), - true, - _dispatcher.Object, - CancellationToken.None))); - _eventHandlersToRun = eventHandlers; - } - - [IterationCleanup] - public void IterationCleanup() - { - foreach (var eventHandler in _eventHandlersToRun) - { - eventHandler.Dispose(); - } - } - - /// - [Params(1, 2)] // TODO: Adding 10 here results in really slow benchmarks. Let's adding 100 when we've made this blazingly fast :) - public override int NumTenants { get; set; } - - /// - /// Gets the number of simultaneously running event handlers. - /// - [Params(1, 2, 5)] // TODO: Adding 10 here results in really slow benchmarks. Let's adding 100 when we've made this blazingly fast :) - public int EventHandlers { get; set; } - - /// - /// Gets the value indicating whether performing benchmark on a partitioned event handler or not. - /// - // [Params(false, true)] TODO: We can maybe enable this in the future, but as of now it seems that the performance is the same. - public bool Partitioned { get; set; } = true; - - /// - /// Gets the number of event types. - /// - // [Params(1, 10)] TODO: We can maybe enable this in the future, but as of now it seems that the performance depends on the amount of events processed. - public int EventTypes { get; set; } = 1; - - /// - /// Gets the number of events committed per configured event type. - /// - [Params(1, 10, 100)] // TODO: Adding 100 here results in really slow benchmarks. Let's adding 100 when we've made this blazingly fast :) - public int Events { get; set; } - - int NumberEventsToProcess => Events * EventTypes * NumTenants * EventHandlers; - - /// - /// Commits the events one-by-one in a loop. - /// - // [Benchmark] TODO: Implicit filters does not work yet - public Task RegisteringAndProcessing() - { - return Task.WhenAll(_eventHandlersToRun.Select(eventHandler => _eventHandlers.RegisterAndStart( - eventHandler, - (_, _) => _dispatcher.Object.Reject(new EventHandlerRegistrationResponse(), CancellationToken.None), - CancellationToken.None))); - } - - /// - protected override void Cleanup() - { - } -} +// // Copyright (c) Dolittle. All rights reserved. +// // Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// using System; +// using System.Collections.Generic; +// using System.Linq; +// using System.Threading; +// using System.Threading.Tasks; +// using BenchmarkDotNet.Attributes; +// using Dolittle.Runtime.Artifacts; +// using Dolittle.Runtime.Events.Processing.Contracts; +// using Dolittle.Runtime.Events.Processing.EventHandlers; +// using Dolittle.Runtime.Events.Store; +// using Integration.Shared; +// using Microsoft.Extensions.DependencyInjection; +// using Moq; +// using ReverseCallDispatcher = Dolittle.Runtime.Services.IReverseCallDispatcher< +// Dolittle.Runtime.Events.Processing.Contracts.EventHandlerClientToRuntimeMessage, +// Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRuntimeToClientMessage, +// Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRegistrationRequest, +// Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRegistrationResponse, +// Dolittle.Runtime.Events.Processing.Contracts.HandleEventRequest, +// Dolittle.Runtime.Events.Processing.Contracts.EventHandlerResponse>; +// +// namespace Integration.Benchmarks.Events.Processing.EventHandlers; +// +// +// /// +// /// Benchmarks for Event Handlers. +// /// +// public class FastEventHandlerWithImplicitFilter : JobBase +// { +// IEventStore _eventStore; +// IEventHandlers _eventHandlers; +// IEventHandlerFactory _eventHandlerFactory; +// IEnumerable _eventHandlersToRun; +// ArtifactId[] _eventTypes; +// Mock _dispatcher; +// +// /// +// protected override void Setup(IServiceProvider services) +// { +// _eventStore = services.GetRequiredService(); +// _eventHandlers = services.GetRequiredService(); +// _eventHandlerFactory = services.GetRequiredService(); +// +// _eventTypes = Enumerable.Range(0, EventTypes).Select(_ => new ArtifactId(Guid.NewGuid())).ToArray(); +// var uncommittedEvents = new List(); +// foreach (var eventType in _eventTypes) +// { +// foreach (var _ in Enumerable.Range(0, Events)) +// { +// uncommittedEvents.Add(new UncommittedEvent("some event source", new Artifact(eventType, ArtifactGeneration.First), false, "{\"hello\": 42}")); +// } +// } +// foreach (var tenant in ConfiguredTenants) +// { +// _eventStore.Commit(new UncommittedEvents(uncommittedEvents), Runtime.CreateExecutionContextFor(tenant)).GetAwaiter().GetResult(); +// } +// } +// +// [IterationSetup] +// public void IterationSetup() +// { +// var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); +// var numEventsProcessed = 0; +// _dispatcher = new Mock(); +// _dispatcher +// .Setup(_ => _.Reject(It.IsAny(), It.IsAny())) +// .Returns(Task.CompletedTask); +// _dispatcher +// .Setup(_ => _.Accept(It.IsAny(), It.IsAny())) +// .Returns(tcs.Task); +// _dispatcher +// .Setup(_ => _.Call(It.IsAny(), It.IsAny(), It.IsAny())) +// .Returns((request, _, __) => +// { +// Interlocked.Add(ref numEventsProcessed, 1); +// var response = new EventHandlerResponse(); +// if (numEventsProcessed == NumberEventsToProcess) +// { +// tcs.SetResult(); +// } +// return Task.FromResult(response); +// }); +// +// var eventHandlers = new List(); +// eventHandlers.AddRange(Enumerable.Range(0, EventHandlers).Select(_ => _eventHandlerFactory.CreateFast( +// new EventHandlerRegistrationArguments(Runtime.CreateExecutionContextFor("d9fd643f-ce74-4ae5-b706-b76859fd8827"), Guid.NewGuid(), _eventTypes, Partitioned, ScopeId.Default), +// true, +// _dispatcher.Object, +// CancellationToken.None))); +// _eventHandlersToRun = eventHandlers; +// } +// +// [IterationCleanup] +// public void IterationCleanup() +// { +// foreach (var eventHandler in _eventHandlersToRun) +// { +// eventHandler.Dispose(); +// } +// } +// +// /// +// [Params(1, 2)] // TODO: Adding 10 here results in really slow benchmarks. Let's adding 100 when we've made this blazingly fast :) +// public override int NumTenants { get; set; } +// +// /// +// /// Gets the number of simultaneously running event handlers. +// /// +// [Params(1, 2, 5)] // TODO: Adding 10 here results in really slow benchmarks. Let's adding 100 when we've made this blazingly fast :) +// public int EventHandlers { get; set; } +// +// /// +// /// Gets the value indicating whether performing benchmark on a partitioned event handler or not. +// /// +// // [Params(false, true)] TODO: We can maybe enable this in the future, but as of now it seems that the performance is the same. +// public bool Partitioned { get; set; } = true; +// +// /// +// /// Gets the number of event types. +// /// +// // [Params(1, 10)] TODO: We can maybe enable this in the future, but as of now it seems that the performance depends on the amount of events processed. +// public int EventTypes { get; set; } = 1; +// +// /// +// /// Gets the number of events committed per configured event type. +// /// +// [Params(1, 10, 100)] // TODO: Adding 100 here results in really slow benchmarks. Let's adding 100 when we've made this blazingly fast :) +// public int Events { get; set; } +// +// int NumberEventsToProcess => Events * EventTypes * NumTenants * EventHandlers; +// +// /// +// /// Commits the events one-by-one in a loop. +// /// +// // [Benchmark] TODO: Implicit filters does not work yet +// public Task RegisteringAndProcessing() +// { +// return Task.WhenAll(_eventHandlersToRun.Select(eventHandler => _eventHandlers.RegisterAndStart( +// eventHandler, +// (_, _) => _dispatcher.Object.Reject(new EventHandlerRegistrationResponse(), CancellationToken.None), +// CancellationToken.None))); +// } +// +// /// +// protected override void Cleanup() +// { +// } +// } diff --git a/Integration/Benchmarks/Events.Processing/Projections/Projection.cs b/Integration/Benchmarks/Events.Processing/Projections/Projection.cs index 49d91573f..bd8a194e4 100644 --- a/Integration/Benchmarks/Events.Processing/Projections/Projection.cs +++ b/Integration/Benchmarks/Events.Processing/Projections/Projection.cs @@ -16,11 +16,9 @@ using Dolittle.Runtime.Projections.Store.Definition.Copies.MongoDB; using Dolittle.Runtime.Projections.Store.State; using Dolittle.Runtime.Rudimentary; -using Integration.Benchmarks.Events.Store; using Integration.Shared; using Microsoft.Extensions.DependencyInjection; using Moq; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; using ProjectionEventSelector = Dolittle.Runtime.Projections.Store.Definition.ProjectionEventSelector; using ReverseCallDispatcher = Dolittle.Runtime.Services.IReverseCallDispatcher< Dolittle.Runtime.Events.Processing.Contracts.ProjectionClientToRuntimeMessage, diff --git a/Integration/Benchmarks/Events.Store/Streams/StreamProcessorStateRepository.cs b/Integration/Benchmarks/Events.Store/Streams/StreamProcessorStateRepository.cs index d6c097d3e..942746312 100644 --- a/Integration/Benchmarks/Events.Store/Streams/StreamProcessorStateRepository.cs +++ b/Integration/Benchmarks/Events.Store/Streams/StreamProcessorStateRepository.cs @@ -21,14 +21,14 @@ namespace Integration.Benchmarks.Events.Store.Streams; /// public class StreamProcessorStateRepository : JobBase { - Dictionary _streamProcessorStates; + Dictionary _streamProcessorStates; (StreamProcessorId, StreamProcessorState)[] _nonPartitionedStates; (StreamProcessorId, PartitionedStreamProcessorState)[] _partitionedStates; /// protected override void Setup(IServiceProvider services) { - _streamProcessorStates = ConfiguredTenants.ToDictionary(tenant => tenant, tenant => services.GetRequiredService>()(tenant)); + _streamProcessorStates = ConfiguredTenants.ToDictionary(tenant => tenant, tenant => services.GetRequiredService>()(tenant)); } [IterationSetup] @@ -83,7 +83,7 @@ public async Task PersistNonPartitionedState() var (id, state) = _nonPartitionedStates[y]; _nonPartitionedStates[y] = (id, state with { - Position = state.Position + 1, + Position = state.Position.IncrementWithStream(), LastSuccessfullyProcessed = DateTimeOffset.UtcNow }); } @@ -109,7 +109,7 @@ public async Task PersistPartitionedState() var (id, state) = _partitionedStates[y]; _partitionedStates[y] = (id, state with { - Position = state.Position + 1, + Position = state.Position.IncrementWithStream(), LastSuccessfullyProcessed = DateTimeOffset.UtcNow }); } diff --git a/Integration/Benchmarks/Events.Store/Streams/StreamProcessorStateTest.cs b/Integration/Benchmarks/Events.Store/Streams/StreamProcessorStateTest.cs index bcfb47d32..b18fc6000 100644 --- a/Integration/Benchmarks/Events.Store/Streams/StreamProcessorStateTest.cs +++ b/Integration/Benchmarks/Events.Store/Streams/StreamProcessorStateTest.cs @@ -12,6 +12,7 @@ using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.MongoDB; using Dolittle.Runtime.Events.Store.MongoDB.Processing.Streams; +using Dolittle.Runtime.Events.Store.Streams; using Microsoft.Extensions.DependencyInjection; using MongoDB.Driver; using StreamProcessorState = Dolittle.Runtime.Events.Processing.Streams.StreamProcessorState; @@ -23,7 +24,7 @@ namespace Integration.Benchmarks.Events.Store.Streams; /// public class StreamProcessorStateTest : JobBase { - Dictionary _statesCollections; + Dictionary _statesCollections; (StreamProcessorId, StreamProcessorState)[] _states; @@ -31,7 +32,7 @@ public class StreamProcessorStateTest : JobBase protected override void Setup(IServiceProvider services) { _statesCollections = ConfiguredTenants.ToDictionary(tenant => tenant, tenant => - (services.GetRequiredService>()(tenant), services.GetRequiredService>()(tenant))); + (services.GetRequiredService>()(tenant), services.GetRequiredService>()(tenant))); } [IterationSetup] @@ -72,7 +73,8 @@ public async Task ReplaceOneAsync() await collection.ReplaceOneAsync(CreateFilter(id), new Dolittle.Runtime.Events.Store.MongoDB.Processing.Streams.StreamProcessorState( id.EventProcessorId, id.SourceStreamId, - state.Position, + state.Position.StreamPosition, + state.Position.EventLogPosition, state.RetryTime.UtcDateTime, state.FailureReason, state.ProcessingAttempts, diff --git a/Integration/Benchmarks/JobBase.cs b/Integration/Benchmarks/JobBase.cs index ed7105643..fb21f33a6 100644 --- a/Integration/Benchmarks/JobBase.cs +++ b/Integration/Benchmarks/JobBase.cs @@ -15,7 +15,7 @@ namespace Integration.Benchmarks; /// public abstract class JobBase { - RunningRuntime _runtime; + RunningRuntime? _runtime; /// /// Ensures that a local MongoDB is reachable, and boots up a new Runtime Server host configured for tenants provided by the . @@ -35,13 +35,13 @@ public void GlobalSetup() public void GlobalCleanup() { Cleanup(); - Runtime.CleanAll(_runtime).GetAwaiter().GetResult(); + Runtime.CleanAll(_runtime!).GetAwaiter().GetResult(); } /// /// Gets the tenants configured for the running benchmark. /// - protected IEnumerable ConfiguredTenants => _runtime.ConfiguredTenants; + protected IEnumerable ConfiguredTenants => _runtime!.ConfiguredTenants; /// /// Gets the number of tenants to setup. diff --git a/Integration/Shared/EventStoreExtensions.cs b/Integration/Shared/EventStoreExtensions.cs index 019c34338..c02c1ebb3 100644 --- a/Integration/Shared/EventStoreExtensions.cs +++ b/Integration/Shared/EventStoreExtensions.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; using Dolittle.Runtime.Artifacts; -using Dolittle.Runtime.Embeddings.Processing; using Dolittle.Runtime.Events; using Dolittle.Runtime.Events.Contracts; using Dolittle.Runtime.Events.Store; diff --git a/Integration/Shared/Runtime.cs b/Integration/Shared/Runtime.cs index d623ec432..f34fad8c3 100644 --- a/Integration/Shared/Runtime.cs +++ b/Integration/Shared/Runtime.cs @@ -10,12 +10,14 @@ using Dolittle.Runtime.Actors.Hosting; using Dolittle.Runtime.Bootstrap.Hosting; using Dolittle.Runtime.DependencyInversion.Building; +using Dolittle.Runtime.Diagnostics.OpenTelemetry; using Dolittle.Runtime.Domain.Platform; using Dolittle.Runtime.Domain.Tenancy; using Dolittle.Runtime.Execution; using Dolittle.Runtime.Metrics.Hosting; using Dolittle.Runtime.Server.Web; using Dolittle.Runtime.Services; +using Dolittle.Runtime.Services.Configuration; using Dolittle.Runtime.Services.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -42,12 +44,17 @@ public static RunningRuntime CreateAndStart(int numberOfTenants) { var mongoClient = new MongoClient("mongodb://localhost:27017"); ThrowIfCannotConnectToMongoDB(mongoClient); - + + var cfg = new ConfigurationManager() + .AddEnvironmentVariables() + .Build(); + var configuration = new Dictionary(); var (databases, tenants) = CreateRuntimeConfiguration(configuration, numberOfTenants); var runtimeHost = Host.CreateDefaultBuilder() .UseDolittleServices() + .ConfigureOpenTelemetry(cfg) .ConfigureHostConfiguration(_ => { _.Sources.Clear(); @@ -58,8 +65,16 @@ public static RunningRuntime CreateAndStart(int numberOfTenants) _.Sources.Clear(); _.AddInMemoryCollection(configuration); }) - .ConfigureServices(_ => _ - .AddLogging(_ => _.ClearProviders())) + .ConfigureServices(_ => + { + _.AddLogging(_ => _.ClearProviders()); + _.AddOptions().Configure(builder => + { + builder.Management = new EndpointConfiguration { Port = 0 }; + // builder.Private = new EndpointConfiguration { Port = 0 }; + builder.Public = new EndpointConfiguration { Port = 0 }; + }); + }) .AddActorSystem() .AddMetrics() .AddGrpcHost(EndpointVisibility.Private) @@ -71,7 +86,7 @@ public static RunningRuntime CreateAndStart(int numberOfTenants) runtimeHost.PerformBootstrap().GetAwaiter().GetResult(); runtimeHost.Start(); - + return new RunningRuntime(runtimeHost, tenants, mongoClient, databases); } @@ -82,7 +97,7 @@ public static Task CleanAll(RunningRuntime runtime) public static Task DropAllDatabases(RunningRuntime runtime) => Task.WhenAll(runtime.Databases.Select(database => runtime.MongoClient.DropDatabaseAsync(database, CancellationToken.None))); - + /// /// Creates a new for the specified tenant to be used in the benchmark. /// @@ -90,13 +105,14 @@ public static Task DropAllDatabases(RunningRuntime runtime) /// The newly created . public static Dolittle.Runtime.Execution.ExecutionContext CreateExecutionContextFor(TenantId tenant) => new(_microserviceId, tenant, Version.NotSet, _environment, Guid.NewGuid(), null, Claims.Empty, CultureInfo.InvariantCulture); - - static (IEnumerable databases, IEnumerable tenants) CreateRuntimeConfiguration(Dictionary configuration, int numberOfTenants) + + static (IEnumerable databases, IEnumerable tenants) CreateRuntimeConfiguration(Dictionary configuration, + int numberOfTenants) { configuration["dolittle:runtime:eventstore:backwardscompatibility:version"] = "V7"; configuration["dolittle:runtime:platform:microserviceID"] = _microserviceId.ToString(); configuration["dolittle:runtime:platform:environment"] = _environment.ToString(); - + var tenants = Enumerable.Range(0, numberOfTenants).Select(_ => new TenantId(Guid.NewGuid())).ToArray(); var databases = new List(); foreach (var tenant in tenants) @@ -105,22 +121,23 @@ public static Dolittle.Runtime.Execution.ExecutionContext CreateExecutionContext configuration[$"dolittle:runtime:tenants:{tenant}:resources:eventStore:servers:0"] = "localhost"; configuration[$"dolittle:runtime:tenants:{tenant}:resources:eventStore:database"] = eventStoreName; databases.Add(eventStoreName); - + var projectionsName = Guid.NewGuid().ToString(); configuration[$"dolittle:runtime:tenants:{tenant}:resources:projections:servers:0"] = "localhost"; configuration[$"dolittle:runtime:tenants:{tenant}:resources:projections:database"] = projectionsName; databases.Add(projectionsName); - + var embeddingsName = Guid.NewGuid().ToString(); configuration[$"dolittle:runtime:tenants:{tenant}:resources:embeddings:servers:0"] = "localhost"; configuration[$"dolittle:runtime:tenants:{tenant}:resources:embeddings:database"] = embeddingsName; databases.Add(embeddingsName); - + var readModelsName = Guid.NewGuid().ToString(); configuration[$"dolittle:runtime:tenants:{tenant}:resources:readModels:host"] = "mongodb://localhost:27017"; configuration[$"dolittle:runtime:tenants:{tenant}:resources:readModels:database"] = readModelsName; databases.Add(readModelsName); } + return (databases, tenants); } diff --git a/Source/Embeddings.Processing/UncommittedAggregateEventsExtension.cs b/Integration/Shared/UncommittedAggregateEventsExtension.cs similarity index 84% rename from Source/Embeddings.Processing/UncommittedAggregateEventsExtension.cs rename to Integration/Shared/UncommittedAggregateEventsExtension.cs index 748be3982..8ac988b3b 100644 --- a/Source/Embeddings.Processing/UncommittedAggregateEventsExtension.cs +++ b/Integration/Shared/UncommittedAggregateEventsExtension.cs @@ -1,4 +1,4 @@ -// Copyright (c) Dolittle. All rights reserved. +// Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Linq; @@ -8,7 +8,7 @@ using Dolittle.Services.Contracts; using UncommittedAggregateEvents = Dolittle.Runtime.Events.Store.UncommittedAggregateEvents; -namespace Dolittle.Runtime.Embeddings.Processing; +namespace Integration.Shared; /// /// Extensions for . @@ -29,14 +29,14 @@ public static CommitAggregateEventsRequest ToCommitRequest(this UncommittedAggre { ExecutionContext = executionContext.ToProtobuf() }, - Events = new Events.Contracts.UncommittedAggregateEvents + Events = new Dolittle.Runtime.Events.Contracts.UncommittedAggregateEvents { AggregateRootId = events.AggregateRoot.Id.ToProtobuf(), EventSourceId = events.EventSource, ExpectedAggregateRootVersion = events.ExpectedAggregateRootVersion, } }; - request.Events.Events.AddRange(events.Select(_ => new Events.Contracts.UncommittedAggregateEvents.Types.UncommittedAggregateEvent + request.Events.Events.AddRange(events.Select(_ => new Dolittle.Runtime.Events.Contracts.UncommittedAggregateEvents.Types.UncommittedAggregateEvent { Content = _.Content, Public = _.Public, diff --git a/Integration/Tests/Events.Processing/EventHandlers/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/given/single_tenant_and_event_handlers.cs index 1576587fe..360572a85 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/given/single_tenant_and_event_handlers.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/given/single_tenant_and_event_handlers.cs @@ -37,30 +37,33 @@ using UncommittedEvent = Dolittle.Runtime.Events.Store.UncommittedEvent; using MongoStreamEvent = Dolittle.Runtime.Events.Store.MongoDB.Events.StreamEvent; using EventHorizonConsumerProcessor = Dolittle.Runtime.EventHorizon.Consumer.Processing.EventProcessor; +using StreamEvent = Dolittle.Runtime.Events.Store.Streams.StreamEvent; namespace Integration.Tests.Events.Processing.EventHandlers.given; class single_tenant_and_event_handlers : Processing.given.a_clean_event_store { protected const int number_of_event_types = 2; - protected static IEventHandlers event_handlers; - protected static IEventHandlerFactory event_handler_factory; - protected static IEnumerable event_handlers_to_run; - protected static ArtifactId[] event_types; - protected static Mock dispatcher; - protected static TaskCompletionSource dispatcher_cancellation_source; - protected static CommittedEvents committed_events; - protected static Dictionary scoped_committed_events; - protected static IWriteEventHorizonEvents event_horizon_events_writer; - protected static EventLogSequenceNumber external_event_sequence_number; - - static ICommitExternalEvents external_event_committer; + protected static IEventHandlers event_handlers = default!; + protected static IEventHandlerFactory event_handler_factory = default!; + protected static IEnumerable event_handlers_to_run = default!; + protected static ArtifactId[] event_types = default!; + protected static Mock dispatcher = default!; + protected static TaskCompletionSource dispatcher_cancellation_source = default!; + protected static CommittedEvents committed_events = default!; + protected static Dictionary scoped_committed_events = default!; + protected static IWriteEventHorizonEvents event_horizon_events_writer = default!; + protected static EventLogSequenceNumber external_event_sequence_number = default!; + protected static int concurrency = 1; + + + static ICommitExternalEvents external_event_committer = default!; static int number_of_events_handled; static CancellationTokenRegistration? cancel_event_handlers_registration; static CancellationTokenSource? cancel_event_handlers_source; - static Dictionary> persisted_stream_definitions; - static Dictionary> persisted_stream_processor_states; + static Dictionary> persisted_stream_definitions = default!; + Establish context = () => { @@ -71,7 +74,7 @@ class single_tenant_and_event_handlers : Processing.given.a_clean_event_store committed_events = new CommittedEvents(Array.Empty()); dispatcher_cancellation_source = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); event_horizon_events_writer = runtime.Host.Services.GetRequiredService>()(tenant); - + event_handlers = runtime.Host.Services.GetRequiredService(); event_handler_factory = runtime.Host.Services.GetRequiredService(); event_types = Enumerable.Range(0, number_of_event_types).Select(_ => new ArtifactId(Guid.NewGuid())).ToArray(); @@ -103,36 +106,32 @@ static async Task commit_events(UncommittedEvents uncommitted_events) var all_committed_events = committed_events.ToList(); all_committed_events.AddRange(newly_committed_events); committed_events = new CommittedEvents(all_committed_events); - } - protected static IEnumerable get_partitioned_events_in_stream(IEventHandler event_handler, PartitionId partition_id) + protected static IEnumerable get_partitioned_events_in_stream(IEventHandler event_handler, + PartitionId partition_id) { - if (event_handler.Info.Partitioned) + using var cts = new CancellationTokenSource(100); + + var reader = stream_event_subscriber.Subscribe(event_handler.Info.Id.Scope, event_handler.Info.EventTypes.ToList(), ProcessingPosition.Initial, + event_handler.Info.Partitioned, $"get_partitioned_events_in_stream:{event_handler.Info.Id.EventHandler.Value}", cts.Token); + + var events = new List(); + + try { - var fetcher = event_fetchers.GetPartitionedFetcherFor( - event_handler.Info.Id.Scope, - new StreamDefinition(new TypeFilterWithEventSourcePartitionDefinition( - StreamId.EventLog, - event_handler.Info.Id.EventHandler.Value, - event_handler.Info.EventTypes, - event_handler.Info.Partitioned)), CancellationToken.None).Result; - - return fetcher.FetchInPartition(partition_id, StreamPosition.Start, CancellationToken.None).Result.Result; + while (!cts.IsCancellationRequested) + { + var evt = Task.Run(async () => await reader.ReadAsync(CancellationToken.None), cts.Token).GetAwaiter().GetResult(); + events.Add(evt); + } } - var rangeFetcher = event_fetchers.GetRangeFetcherFor(event_handler.Info.Id.Scope, - new StreamDefinition(new TypeFilterWithEventSourcePartitionDefinition( - StreamId.EventLog, - event_handler.Info.Id.EventHandler.Value, - event_handler.Info.EventTypes, - event_handler.Info.Partitioned)), CancellationToken.None).Result; - - return rangeFetcher - .FetchRange(new StreamPositionRange(StreamPosition.Start, ulong.MaxValue), CancellationToken.None) - .ToListAsync() - .GetAwaiter() - .GetResult() - .Where(_ => _.Event.EventSource.Value == partition_id.Value); + catch (Exception) + { + // ignored + } + + return events.Where(_ => _.Partition == partition_id); } protected static async Task commit_events_for_each_event_type(IEnumerable<(int number_of_events, EventSourceId event_source, ScopeId scope_id)> commit) @@ -156,7 +155,7 @@ IEnumerable CreateUncommittedEvents(IEnumerable<(int number_of CreateUncommittedEvents(commit.Where(_ => _.scope_id == ScopeId.Default).Select(_ => (_.number_of_events, _.event_source))).ToArray()); tasks.Add(commit_events(unscoped_uncommitted_events)); } - + var scoped_uncommitted_events = new Dictionary(); foreach (var scoped_commit_group in commit.Where(_ => _.scope_id != ScopeId.Default).GroupBy(_ => _.scope_id)) { @@ -188,12 +187,13 @@ static async Task write_committed_events_to_scoped_event_log(CommittedEvents com { previously_committed_events = new CommittedEvents(Array.Empty()); } + var all_committed_events = previously_committed_events.ToList(); all_committed_events.AddRange(committed_events); scoped_committed_events[scope] = new CommittedEvents(all_committed_events); } - protected static async Task run_event_handlers_until_completion(IEnumerable pre_start_tasks = default, Task post_start_task = default) + protected static async Task run_event_handlers_until_completion(IEnumerable? pre_start_tasks = default, Task? post_start_task = default) { await Task.WhenAll(pre_start_tasks ?? Array.Empty()).ConfigureAwait(false); var tasks = new List(); @@ -206,23 +206,23 @@ protected static async Task run_event_handlers_until_completion(IEnumerable run_event_handlers_until_completion(post_start_task: commit_after_delay(events)); - protected static void with_event_handlers_filtering_number_of_event_types(params (bool partitioned, int max_event_types_to_filter, ScopeId scope, bool fast, bool implicitFilter)[] event_handler_infos) + protected static void with_event_handlers_filtering_number_of_event_types( + params (bool partitioned, int max_event_types_to_filter, ScopeId scope, bool fast, bool implicitFilter)[] event_handler_infos) { event_handlers_to_run = event_handler_infos.Select(_ => { var (partitioned, max_event_types_to_filter, scope, fast, implicitFilter) = _; var registration_arguments = new EventHandlerRegistrationArguments( - Runtime.CreateExecutionContextFor(tenant), Guid.NewGuid(), event_types.Take(max_event_types_to_filter), partitioned, scope); - return fast - ? event_handler_factory.CreateFast(registration_arguments, implicitFilter, dispatcher.Object, CancellationToken.None) - : event_handler_factory.Create(registration_arguments, dispatcher.Object, CancellationToken.None); + Runtime.CreateExecutionContextFor(tenant), Guid.NewGuid(), event_types.Take(max_event_types_to_filter), partitioned, scope, concurrency); + return event_handler_factory.Create(registration_arguments, dispatcher.Object, CancellationToken.None); }).ToArray(); } - static void setup_dispatcher_call(Func callback) + static void setup_dispatcher_call(Func callback) { dispatcher .Setup(_ => _.Call(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) @@ -230,7 +230,7 @@ static void setup_dispatcher_call(Func .Returns((request, _, _) => { var response = callback(request); - reset_timeout_after_action(TimeSpan.FromMilliseconds(1000)); + reset_timeout_after_action(TimeSpan.FromMilliseconds(250)); return Task.FromResult(response); }); } @@ -241,9 +241,9 @@ static void reset_timeout_after_action(TimeSpan timeout) cancel_event_handlers_registration?.Dispose(); cancel_event_handlers_source?.Dispose(); cancel_event_handlers_source = new CancellationTokenSource(timeout); - cancel_event_handlers_registration = cancel_event_handlers_source.Token.Register(() => dispatcher_cancellation_source?.SetResult()); + cancel_event_handlers_registration = cancel_event_handlers_source.Token.Register(() => dispatcher_cancellation_source?.TrySetResult()); } - + protected static void fail_after_processing_number_of_events(int number_of_events, string reason, retry_failing_event? retry = default) { setup_dispatcher_call(_ => @@ -253,11 +253,12 @@ protected static void fail_after_processing_number_of_events(int number_of_event { response.Failure = new ProcessorFailure { - Reason = reason, + Reason = reason, Retry = retry is not null, RetryTimeout = retry?.timeout.ToDuration() ?? TimeSpan.FromSeconds(1).ToDuration() }; } + return response; }); } @@ -267,13 +268,13 @@ protected static IEnumerable committed_events_for_event_types(in var nFirstEventTypes = event_types.Take(num_event_types); return committed_events.Where(_ => nFirstEventTypes.Contains(_.Type.Id)); } - + protected static IEnumerable scope_events_for_event_types(ScopeId scope_id, int num_event_types) { var nFirstEventTypes = event_types.Take(num_event_types); return scoped_committed_events[scope_id].Where(_ => nFirstEventTypes.Contains(_.Type.Id)); } - + protected static void fail_for_event_sources(IEnumerable event_sources, string reason, retry_failing_event? retry = default) { setup_dispatcher_call(request => @@ -283,11 +284,12 @@ protected static void fail_for_event_sources(IEnumerable event_so { response.Failure = new ProcessorFailure { - Reason = reason, + Reason = reason, Retry = retry is not null, RetryTimeout = retry?.timeout.ToDuration() ?? TimeSpan.FromSeconds(1).ToDuration() }; } + return response; }); } @@ -312,51 +314,49 @@ protected static Try get_stream_definition_for(IEventHandler persisted_stream_definitions[info] = tryGetDefinition; } } + if (!persisted_stream_definitions.ContainsKey(event_handler.Info)) { - var tryGetDefinition = stream_definition_repository.TryGet(event_handler.Info.Id.Scope, event_handler.Info.Id.EventHandler.Value, CancellationToken.None).Result; + var tryGetDefinition = stream_definition_repository + .TryGet(event_handler.Info.Id.Scope, event_handler.Info.Id.EventHandler.Value, CancellationToken.None).Result; persisted_stream_definitions[event_handler.Info] = tryGetDefinition; } + return persisted_stream_definitions[event_handler.Info]; } + protected static Try get_stream_processor_state_for(StreamProcessorId stream_processor_id) { - if (persisted_stream_processor_states == default) - { - persisted_stream_processor_states = new Dictionary>(); - foreach (var info in event_handlers_to_run.Select(_ => _.Info)) - { - var filterProcessorId = info.GetFilterStreamId(); - var eventProcessorId = info.GetEventProcessorStreamId(); - persisted_stream_processor_states[filterProcessorId] = stream_processor_states.TryGetFor(filterProcessorId, CancellationToken.None).Result;; - persisted_stream_processor_states[eventProcessorId] = stream_processor_states.TryGetFor(eventProcessorId, CancellationToken.None).Result;; - } - } - if (!persisted_stream_processor_states.ContainsKey(stream_processor_id)) - { - persisted_stream_processor_states[stream_processor_id] = stream_processor_states.TryGetFor(stream_processor_id, CancellationToken.None).Result;; - } - return persisted_stream_processor_states[stream_processor_id]; + return stream_processor_states.TryGetFor(stream_processor_id, CancellationToken.None).GetAwaiter().GetResult(); + + // if (persisted_stream_processor_states == default) + // { + // persisted_stream_processor_states = new Dictionary>(); + // foreach (var info in event_handlers_to_run.Select(_ => _.Info)) + // { + // var filterProcessorId = info.GetFilterStreamId(); + // var eventProcessorId = info.GetEventProcessorStreamId(); + // persisted_stream_processor_states[filterProcessorId] = stream_processor_states.TryGetFor(filterProcessorId, CancellationToken.None).Result; + // persisted_stream_processor_states[eventProcessorId] = stream_processor_states.TryGetFor(eventProcessorId, CancellationToken.None).Result; + // } + // } + // + // if (!persisted_stream_processor_states.ContainsKey(stream_processor_id)) + // { + // persisted_stream_processor_states[stream_processor_id] = stream_processor_states.TryGetFor(stream_processor_id, CancellationToken.None).Result; + // } + // + // return persisted_stream_processor_states[stream_processor_id]; } #region SpecHelpers - protected static void expect_number_of_filtered_events(IEventHandler event_handler, long expected_number) - => count_events_in_stream(event_handler, Builders.Filter.Empty).ShouldEqual(expected_number); - - protected static void expect_number_of_filtered_events_with_partition(IEventHandler event_handler, long expected_number, PartitionId partition_id) - => count_events_in_stream(event_handler, Builders.Filter.Eq(_ => _.Partition, partition_id.Value)).ShouldEqual(expected_number); - - protected static void expect_number_of_filtered_events_with_event_type(IEventHandler event_handler, long expected_number, ArtifactId event_type) - => count_events_in_stream(event_handler, Builders.Filter.Eq(_ => _.Metadata.TypeId, event_type.Value)).ShouldEqual(expected_number); - - static long count_events_in_stream(IEventHandler event_handler, FilterDefinition filter) => streams .Get(event_handler.Info.Id.Scope, event_handler.Info.Id.EventHandler.Value, CancellationToken.None) .Result .CountDocuments(filter, cancellationToken: CancellationToken.None); - + protected static void expect_correct_stream_definition( IEventHandler event_handler, @@ -369,7 +369,7 @@ protected static void expect_correct_stream_definition( var tryGetStreamDefinition = get_stream_definition_for(event_handler); tryGetStreamDefinition.Success.ShouldBeTrue(); var streamDefinition = tryGetStreamDefinition.Result; - streamDefinition.Partitioned.ShouldEqual(partitioned); + streamDefinition!.Partitioned.ShouldEqual(partitioned); streamDefinition.Public.ShouldEqual(public_stream); streamDefinition.FilterDefinition.ShouldBeOfExactType(); var filterDefinition = streamDefinition.FilterDefinition as TypeFilterWithEventSourcePartitionDefinition; @@ -382,39 +382,14 @@ protected static void expect_correct_stream_definition( protected static void expect_stream_processor_state( IEventHandler event_handler, - bool implicit_filter = false, - bool fast_event_handler = false, bool partitioned = false, int num_events_to_handle = 0, failing_partitioned_state? failing_partitioned_state = null, failing_unpartitioned_state? failing_unpartitioned_state = null - ) + ) { - expect_filter_stream_processor_state(event_handler.Info.GetFilterStreamId(), implicit_filter, fast_event_handler); - expect_event_processor_stream_processor_state(event_handler.Info.GetEventProcessorStreamId(), partitioned, num_events_to_handle, failing_partitioned_state, failing_unpartitioned_state); - } - - static void expect_filter_stream_processor_state(StreamProcessorId id, bool implicit_filter, bool fast_event_handler) - { - var isImplicit = implicit_filter && fast_event_handler; - var tryGetStreamProcessorState = get_stream_processor_state_for(id); - tryGetStreamProcessorState.Success.ShouldEqual(!isImplicit); - if (isImplicit) - { - return; - } - var state = tryGetStreamProcessorState.Result; - state.Partitioned.ShouldBeFalse(); - var expectedPosition = id.ScopeId == ScopeId.Default - ? new StreamPosition((ulong)committed_events.Count) - : new StreamPosition((ulong)scoped_committed_events[id.ScopeId].Count); - state.Position.ShouldEqual(expectedPosition); - state.ShouldBeOfExactType(); - var unpartitionedState = state as StreamProcessorState; - unpartitionedState!.IsFailing.ShouldBeFalse(); - unpartitionedState.ProcessingAttempts.ShouldEqual((uint)0); - unpartitionedState.RetryTime.ShouldBeLessThanOrEqualTo(DateTimeOffset.UtcNow); - unpartitionedState.LastSuccessfullyProcessed.ShouldBeLessThanOrEqualTo(DateTimeOffset.UtcNow); + expect_event_processor_stream_processor_state(event_handler.Info.GetEventProcessorStreamId(), partitioned, num_events_to_handle, + failing_partitioned_state, failing_unpartitioned_state); } static void expect_event_processor_stream_processor_state( @@ -423,16 +398,16 @@ static void expect_event_processor_stream_processor_state( int num_events_to_handle, failing_partitioned_state? failing_partitioned_state, failing_unpartitioned_state? failing_unpartitioned_state - ) + ) { var tryGetStreamProcessorState = get_stream_processor_state_for(id); tryGetStreamProcessorState.Success.ShouldBeTrue(); var state = tryGetStreamProcessorState.Result; - state.Partitioned.ShouldEqual(partitioned); - + state!.Partitioned.ShouldEqual(partitioned); + if (partitioned) { - state.Position.Value.ShouldEqual((ulong) num_events_to_handle); + state.Position.StreamPosition.Value.ShouldEqual((ulong)num_events_to_handle); expect_partitioned_event_processor_stream_processor_state(state, failing_partitioned_state); } else @@ -443,48 +418,50 @@ static void expect_event_processor_stream_processor_state( static void expect_partitioned_event_processor_stream_processor_state( IStreamProcessorState state, - failing_partitioned_state? failing_partitioned_state) + failing_partitioned_state? expected_failure_states) { state.ShouldBeOfExactType(); var partitionedState = state as Dolittle.Runtime.Events.Processing.Streams.Partitioned.StreamProcessorState; - - if (failing_partitioned_state is null) + + if (expected_failure_states is null) { partitionedState!.FailingPartitions.ShouldBeEmpty(); partitionedState.LastSuccessfullyProcessed.ShouldBeLessThanOrEqualTo(DateTimeOffset.UtcNow); } else { - partitionedState!.FailingPartitions.Keys.ShouldContainOnly(failing_partitioned_state.failing_partitions.Keys); + partitionedState!.FailingPartitions.Keys.ShouldContainOnly(expected_failure_states.failing_partitions.Keys); foreach (var (partition, failingState) in partitionedState!.FailingPartitions) { - var failingPosition = failing_partitioned_state.failing_partitions[partition]; - failingState.Position.ShouldEqual(failingPosition); + var failingPosition = expected_failure_states.failing_partitions[partition]; + failingState.Position.StreamPosition.ShouldEqual(failingPosition); failingState.LastFailed.ShouldBeLessThanOrEqualTo(DateTimeOffset.UtcNow); failingState.ProcessingAttempts.ShouldBeGreaterThanOrEqualTo(1); } } } + static void expect_unpartitioned_event_processor_stream_processor_state( IStreamProcessorState state, int num_events_to_handle, - failing_unpartitioned_state? failing_unpartitioned_state) + failing_unpartitioned_state? expected_failure_state) { state.ShouldBeOfExactType(); var unpartitionedState = state as StreamProcessorState; - - if (failing_unpartitioned_state is null) + + if (expected_failure_state is null) { unpartitionedState!.IsFailing.ShouldBeFalse(); unpartitionedState.ProcessingAttempts.ShouldEqual((uint)0); unpartitionedState.LastSuccessfullyProcessed.ShouldBeLessThanOrEqualTo(DateTimeOffset.UtcNow); unpartitionedState.RetryTime.ShouldBeLessThanOrEqualTo(DateTimeOffset.UtcNow); - unpartitionedState.Position.Value.ShouldEqual((ulong) num_events_to_handle); + unpartitionedState.Position.StreamPosition.Value.ShouldEqual((ulong)num_events_to_handle); } else { unpartitionedState!.IsFailing.ShouldBeTrue(); - unpartitionedState.Position.ShouldEqual(failing_unpartitioned_state.failing_position); + unpartitionedState.FailureReason.ShouldEqual(expected_failure_state.reason); + unpartitionedState.Position.StreamPosition.ShouldEqual(expected_failure_state.failing_position); unpartitionedState.ProcessingAttempts.ShouldBeGreaterThanOrEqualTo(1); unpartitionedState.LastSuccessfullyProcessed.ShouldBeLessThanOrEqualTo(DateTimeOffset.UtcNow); } @@ -492,10 +469,9 @@ static void expect_unpartitioned_event_processor_stream_processor_state( } record failing_partitioned_state(Dictionary failing_partitions); -record failing_unpartitioned_state(StreamPosition failing_position); - #endregion +record failing_unpartitioned_state(StreamPosition failing_position, string reason); - record retry_failing_event(TimeSpan timeout); +#endregion - \ No newline at end of file +record retry_failing_event(TimeSpan timeout); \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/given/single_tenant_and_event_handlers.cs index bce5fbc9d..cfcc5540a 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/given/single_tenant_and_event_handlers.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/given/single_tenant_and_event_handlers.cs @@ -12,7 +12,7 @@ namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped class single_tenant_and_event_handlers : EventHandlers.given.single_tenant_and_event_handlers { - protected static ScopeId event_handler_scope; + protected static ScopeId event_handler_scope = default!; Establish context = () => event_handler_scope = "3c641c00-f7f0-4222-9ac7-1d88200e09f7"; diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index ef410f501..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.with_implicit_filter.given; - -class single_tenant_and_event_handlers : event_handler.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler, int num_events_to_handle) - => expect_stream_processor_state(event_handler, true, false, num_events_to_handle, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_unpartitioned_state failing_unpartitioned_state) - => expect_stream_processor_state(event_handler, true, false, (int)failing_unpartitioned_state.failing_position.Value, failing_unpartitioned_state); - - protected static void with_event_handlers_filtering_number_of_event_types(params int[] max_event_types_to_filter) - => with_event_handlers_filtering_number_of_event_types(max_event_types_to_filter - .Select(_ => (_, true)) - .ToArray()); - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs deleted file mode 100644 index 491b8462d..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((4, failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs deleted file mode 100644 index 773fb8735..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 2a1c149f3..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.with_implicit_filter.processing_all_event_types.given; - -class single_tenant_and_event_handlers : with_implicit_filter.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, number_of_event_types); - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_without_failure(event_handler, scoped_committed_events[event_handler_scope].Count); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - number_of_event_types - } - .Select(_ => _) - .ToArray()); - return event_handlers_to_run.First(); - } - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index 83334130e..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index 61a5edda5..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs deleted file mode 100644 index 14c4d589e..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.with_implicit_filter.processing_all_event_types.needing_catchup; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static EventSourceId event_source; - - Establish context = () => - { - event_source = "some_source"; - commit_events_for_each_event_type((2, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs deleted file mode 100644 index f9d7e9bed..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.with_implicit_filter.processing_all_event_types; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => commit_events_after_starting_event_handler((2, "some_source")); - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs deleted file mode 100644 index 7b231ef8b..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs deleted file mode 100644 index 036e4f658..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 83afabb33..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.with_implicit_filter.processing_one_event_type.given; - -class single_tenant_and_event_handlers : with_implicit_filter.given.single_tenant_and_event_handlers -{ - - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, 1); - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_without_failure(event_handler, scope_events_for_event_types(event_handler_scope, 1).Count()); - - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - 1 - } - .Select(_ => (_, true)) - .ToArray()); - return event_handlers_to_run.First(); - } -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index 0cf66f31b..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((4, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index 7b62c67fa..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs deleted file mode 100644 index 652de5aa9..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.with_implicit_filter.processing_one_event_type.needing_catchup; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - commit_events_for_each_event_type((4, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs deleted file mode 100644 index d037b112f..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.with_implicit_filter.processing_one_event_type; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/that_handles_no_event_types.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/that_handles_no_event_types.cs deleted file mode 100644 index cc1ee6c1d..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/with_implicit_filter/that_handles_no_event_types.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.with_implicit_filter; - -class that_handles_no_event_types : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static Exception exception; - Establish context = () => - { - with_event_handlers_filtering_number_of_event_types(0); - event_handler = event_handlers_to_run.First(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler, 0); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 0).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler, 0!); - -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs index f245cbd99..a113a1d59 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs @@ -12,10 +12,10 @@ namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped class single_tenant_and_event_handlers : event_handler.given.single_tenant_and_event_handlers { protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler, int num_events_to_handle) - => expect_stream_processor_state(event_handler, false, false, num_events_to_handle, null!); + => expect_stream_processor_state(event_handler, num_events_to_handle, null!); protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_unpartitioned_state failing_unpartitioned_state) - => expect_stream_processor_state(event_handler, false, false, (int)failing_unpartitioned_state.failing_position.Value, failing_unpartitioned_state); + => expect_stream_processor_state(event_handler, (int)failing_unpartitioned_state.failing_position.Value, failing_unpartitioned_state); protected static void with_event_handlers_filtering_number_of_event_types(params int[] max_event_types_to_filter) => with_event_handlers_filtering_number_of_event_types(max_event_types_to_filter diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs index a9cd584cf..3c1be831b 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs @@ -1,8 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store.Streams; using Integration.Tests.Events.Processing.EventHandlers.given; @@ -31,7 +29,6 @@ class after_2_events : given.single_tenant_and_event_handlers }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1)); + It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1, failure_reason)); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs index fe2e6af09..be9df1378 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs @@ -32,9 +32,8 @@ class on_one_partition : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); + new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position, failure_reason)); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs index bd7cc03b0..2439a8c2b 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs @@ -5,7 +5,6 @@ using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.without_implicit_filter.processing_all_event_types.given; diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs index 81d38dfd1..3c86ecd7c 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs @@ -1,8 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store.Streams; using Integration.Tests.Events.Processing.EventHandlers.given; @@ -31,7 +29,6 @@ class after_2_events : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1)); + It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1, failure_reason)); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs index 55ff3f7ca..262fd1952 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs @@ -33,9 +33,8 @@ class on_one_partition : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); + new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position,failure_reason)); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/withoutout_problems.cs index 7e4b9df89..dbe14e12a 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/withoutout_problems.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/withoutout_problems.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.Events; using Dolittle.Runtime.Events.Processing.EventHandlers; using Machine.Specifications; @@ -26,7 +25,6 @@ class without_problems : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, "some_source")); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/withoutout_problems.cs index 2e08e6a87..c63d991cc 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/withoutout_problems.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/withoutout_problems.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Machine.Specifications; @@ -20,8 +19,6 @@ class without_problems : given.single_tenant_and_event_handlers Because of = () => commit_events_after_starting_event_handler((2, "some_source")); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs index 6e4b5f499..e101fe0ae 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs @@ -1,8 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store.Streams; using Integration.Tests.Events.Processing.EventHandlers.given; @@ -30,11 +28,9 @@ class after_2_events : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, - new failing_unpartitioned_state(1)); + new failing_unpartitioned_state(1, failure_reason)); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs index c8cad12ee..36bf18a1a 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs @@ -8,8 +8,8 @@ using Integration.Tests.Events.Processing.EventHandlers.given; using Machine.Specifications; -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.without_implicit_filter.processing_one_event_type.and_failing; - +namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.without_implicit_filter.processing_one_event_type + .and_failing; class on_one_partition : given.single_tenant_and_event_handlers { @@ -23,19 +23,16 @@ class on_one_partition : given.single_tenant_and_event_handlers failing_partition = "some event source"; succeeding_partition = "some other event source"; failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); + fail_for_event_sources(new EventSourceId[] { failing_partition.Value }, failure_reason); event_handler = setup_event_handler(); }; - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - + Because of = () => { commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); }; + + It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); + It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); + new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position, failure_reason)); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs index eb117ed71..1145d5ed1 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs @@ -5,7 +5,6 @@ using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.without_implicit_filter.processing_one_event_type.given; diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs index 50c8aeed0..01c74f123 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs @@ -1,8 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store.Streams; using Integration.Tests.Events.Processing.EventHandlers.given; @@ -31,9 +29,8 @@ class after_2_events : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, - new failing_unpartitioned_state(1)); + new failing_unpartitioned_state(1, failure_reason)); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs index 82142cf65..2d57369ae 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs @@ -33,9 +33,8 @@ class on_one_partition : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); + new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position, failure_reason)); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/withoutout_problems.cs index f58093d88..289f8cb08 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/withoutout_problems.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/withoutout_problems.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Machine.Specifications; @@ -24,7 +23,6 @@ class without_problems : given.single_tenant_and_event_handlers }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/withoutout_problems.cs index 8b4079161..42d7f809b 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/withoutout_problems.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/withoutout_problems.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Machine.Specifications; @@ -23,6 +22,5 @@ class without_problems : given.single_tenant_and_event_handlers }; It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/that_handles_no_event_types.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/that_handles_no_event_types.cs index 5312e9823..30035a546 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/that_handles_no_event_types.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/event_handler/without_implicit_filter/that_handles_no_event_types.cs @@ -1,30 +1,30 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.without_implicit_filter; - -class that_handles_no_event_types : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static Exception exception; - Establish context = () => - { - with_event_handlers_filtering_number_of_event_types(0); - event_handler = event_handlers_to_run.First(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler, 0); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 0).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler, 0!); - -} \ No newline at end of file +// // Copyright (c) Dolittle. All rights reserved. +// // Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// using System; +// using System.Linq; +// using Dolittle.Runtime.Events.Processing.EventHandlers; +// using Machine.Specifications; +// +// namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.event_handler.without_implicit_filter; +// +// class that_handles_no_event_types : given.single_tenant_and_event_handlers +// { +// static IEventHandler event_handler; +// static Exception exception; +// Establish context = () => +// { +// with_event_handlers_filtering_number_of_event_types(0); +// event_handler = event_handlers_to_run.First(); +// }; +// +// Because of = () => +// { +// commit_events_after_starting_event_handler((2, "some_source")); +// }; +// +// It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler, 0); +// It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 0).LongCount()); +// It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler, 0!); +// +// } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 48e139b38..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.given; - -class single_tenant_and_event_handlers : not_partitioned.given.single_tenant_and_event_handlers -{ - protected static void with_event_handlers_filtering_number_of_event_types(params (int max_event_types_to_filter, bool implicitFilter)[] event_handler_infos) - => with_event_handlers_filtering_number_of_event_types(event_handler_infos - .Select(_ => (_.max_event_types_to_filter, true, _.implicitFilter)) - .ToArray()); - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index b06d7d8e0..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.with_implicit_filter.given; - -class single_tenant_and_event_handlers : fast_event_handler.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler, int num_events_to_handle) - => expect_stream_processor_state(event_handler, true, true, num_events_to_handle, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_unpartitioned_state failing_unpartitioned_state) - => expect_stream_processor_state(event_handler, true, true, (int)failing_unpartitioned_state.failing_position.Value, failing_unpartitioned_state); - - protected static void with_event_handlers_filtering_number_of_event_types(params int[] max_event_types_to_filter) - => with_event_handlers_filtering_number_of_event_types(max_event_types_to_filter - .Select(_ => (_, true)) - .ToArray()); - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs deleted file mode 100644 index cc43546c5..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((4, failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs deleted file mode 100644 index a8cf32e01..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 491707386..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.given; - -class single_tenant_and_event_handlers : with_implicit_filter.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, number_of_event_types); - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_without_failure(event_handler, scoped_committed_events[event_handler_scope].Count); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - number_of_event_types - } - .Select(_ => _) - .ToArray()); - return event_handlers_to_run.First(); - } - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index 04bf003ad..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index b11009938..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs deleted file mode 100644 index fe0837b90..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.needing_catchup; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static EventSourceId event_source; - - Establish context = () => - { - event_source = "some_source"; - commit_events_for_each_event_type((2, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs deleted file mode 100644 index 26de9bb4c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => commit_events_after_starting_event_handler((2, "some_source")); - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs deleted file mode 100644 index 87baa2fa6..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs deleted file mode 100644 index cc2e7cf99..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 5064a44b6..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.given; - -class single_tenant_and_event_handlers : with_implicit_filter.given.single_tenant_and_event_handlers -{ - - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, 1); - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_without_failure(event_handler, scope_events_for_event_types(event_handler_scope, 1).Count()); - - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - 1 - } - .Select(_ => (_, true)) - .ToArray()); - return event_handlers_to_run.First(); - } -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index 3e9c87c3c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((4, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index 0057259b0..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs deleted file mode 100644 index 1dd66b0fd..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.needing_catchup; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - commit_events_for_each_event_type((4, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs deleted file mode 100644 index 09e4aab1b..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/that_handles_no_event_types.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/that_handles_no_event_types.cs deleted file mode 100644 index aec0ecf80..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/with_implicit_filter/that_handles_no_event_types.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.with_implicit_filter; - -class that_handles_no_event_types : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static Exception exception; - Establish context = () => - { - with_event_handlers_filtering_number_of_event_types(0); - event_handler = event_handlers_to_run.First(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler, 0); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 0).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler, 0!); - -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 7f3dca11f..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.without_implicit_filter.given; - -class single_tenant_and_event_handlers : fast_event_handler.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler, int num_events_to_handle) - => expect_stream_processor_state(event_handler, false, true, num_events_to_handle, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_unpartitioned_state failing_unpartitioned_state) - => expect_stream_processor_state(event_handler, false, true, (int)failing_unpartitioned_state.failing_position.Value, failing_unpartitioned_state); - - protected static void with_event_handlers_filtering_number_of_event_types(params int[] max_event_types_to_filter) - => with_event_handlers_filtering_number_of_event_types(max_event_types_to_filter - .Select(_ => (_, false)) - .ToArray()); - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs deleted file mode 100644 index a80487a58..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.and_failing; - - -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((4, failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs deleted file mode 100644 index 572e652b2..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.and_failing; - - -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index ffe9edfcf..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.given; - -class single_tenant_and_event_handlers : without_implicit_filter.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, number_of_event_types); - - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_without_failure(event_handler, scoped_committed_events[event_handler_scope].Count); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - number_of_event_types - } - .Select(_ => _) - .ToArray()); - return event_handlers_to_run.First(); - } - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index e39a51929..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - - -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index cfd53bc52..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - - -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/withoutout_problems.cs deleted file mode 100644 index e0ffbfa5d..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/withoutout_problems.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.needing_catchup; - - -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static EventSourceId event_source; - - Establish context = () => - { - event_source = "some_source"; - commit_events_for_each_event_type((2, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/withoutout_problems.cs deleted file mode 100644 index 6cd545288..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/withoutout_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types; - - -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => commit_events_after_starting_event_handler((2, "some_source")); - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs deleted file mode 100644 index bf807cded..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.and_failing; - - -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs deleted file mode 100644 index 3458f8af8..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.and_failing; - - -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index ed9136aa4..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.given; - -class single_tenant_and_event_handlers : without_implicit_filter.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, 1); - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_without_failure(event_handler, scope_events_for_event_types(event_handler_scope, 1).Count()); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - 1 - } - .Select(_ => _) - .ToArray()); - return event_handlers_to_run.First(); - } -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index 7c5b18a75..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - - -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((4, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index 7fa587648..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - - -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/withoutout_problems.cs deleted file mode 100644 index 65fdf6d84..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/withoutout_problems.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.needing_catchup; - - -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - commit_events_for_each_event_type((4, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/withoutout_problems.cs deleted file mode 100644 index cf4751aaa..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/withoutout_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type; - - -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/that_handles_no_event_types.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/that_handles_no_event_types.cs deleted file mode 100644 index fc872918d..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/fast_event_handler/without_implicit_filter/that_handles_no_event_types.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.fast_event_handler.without_implicit_filter; - -class that_handles_no_event_types : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static Exception exception; - Establish context = () => - { - with_event_handlers_filtering_number_of_event_types(0); - event_handler = event_handlers_to_run.First(); - }; - - Because of = () => - { - exception = Catch.Exception(() => commit_events_after_starting_event_handler((2, "some_source"))); - }; - - It should_fail_starting_event_handler = () => exception.ShouldNotBeNull(); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/given/single_tenant_and_event_handlers.cs index cdeeaae6e..eda6e535b 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/given/single_tenant_and_event_handlers.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/not_partitioned/given/single_tenant_and_event_handlers.cs @@ -5,7 +5,6 @@ using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; using Integration.Tests.Events.Processing.EventHandlers.given; namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.not_partitioned.given; @@ -15,11 +14,9 @@ class single_tenant_and_event_handlers : scoped.given.single_tenant_and_event_ha protected static void expect_stream_definition(IEventHandler event_handler, int max_handled_event_types) => expect_correct_stream_definition(event_handler, partitioned: false, public_stream: false, max_handled_event_types: max_handled_event_types); - protected static void expect_stream_processor_state(IEventHandler event_handler, bool implicit_filter, bool fast_event_handler, int num_events_to_handle, failing_unpartitioned_state failing_unpartitioned_state) + protected static void expect_stream_processor_state(IEventHandler event_handler, int num_events_to_handle, failing_unpartitioned_state failing_unpartitioned_state) => expect_stream_processor_state( event_handler, - implicit_filter: implicit_filter, - fast_event_handler: fast_event_handler, partitioned: false, num_events_to_handle: num_events_to_handle, failing_partitioned_state: null, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/given/single_tenant_and_event_handlers.cs index f770962e8..2d2b3a94d 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/given/single_tenant_and_event_handlers.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/given/single_tenant_and_event_handlers.cs @@ -4,10 +4,6 @@ #nullable enable using System.Linq; -using System.Threading.Tasks; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Integration.Tests.Events.Processing.EventHandlers.given; namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.given; diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 4e3f9a494..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.given; - -class single_tenant_and_event_handlers : event_handler.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler, int num_events_to_handle) - => expect_stream_processor_state_with_failure(event_handler, num_events_to_handle, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, int num_events_to_handle, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state(event_handler, true, false, num_events_to_handle, failing_partitioned_state); - - protected static void with_event_handlers_filtering_number_of_event_types(params int[] max_event_types_to_filter) - => with_event_handlers_filtering_number_of_event_types(max_event_types_to_filter - .Select(_ => (_, true)) - .ToArray()); - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs deleted file mode 100644 index 3a347e9bd..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((4, failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs deleted file mode 100644 index ae164fb0b..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs deleted file mode 100644 index 539cd7a00..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index d64dccce3..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types.given; - -class single_tenant_and_event_handlers : with_implicit_filter.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, number_of_event_types); - - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_with_failure(event_handler, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state_with_failure( - event_handler, - scoped_committed_events[event_handler_scope].Count, - failing_partitioned_state); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - number_of_event_types - } - .Select(_ => _) - .ToArray()); - return event_handlers_to_run.First(); - } - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index 305bc7f76..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs deleted file mode 100644 index 1da973dd3..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index ad09bda96..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs deleted file mode 100644 index 6618bbee7..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types.needing_catchup; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static EventSourceId event_source; - - Establish context = () => - { - event_source = "some_source"; - commit_events_for_each_event_type((2, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs deleted file mode 100644 index 7a5ace7ee..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => commit_events_after_starting_event_handler((2, "some_source")); - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs deleted file mode 100644 index 2a6b654bf..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs deleted file mode 100644 index 4be81b896..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs deleted file mode 100644 index d9fd75d63..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index a90b95ed2..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type.given; - -class single_tenant_and_event_handlers : with_implicit_filter.given.single_tenant_and_event_handlers -{ - - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, 1); - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_with_failure(event_handler, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state_with_failure(event_handler, scope_events_for_event_types(event_handler_scope, 1).Count(), failing_partitioned_state); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - 1 - } - .Select(_ => (_, true)) - .ToArray()); - return event_handlers_to_run.First(); - } -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index 9bebb188a..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((4, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs deleted file mode 100644 index 22ca6f533..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index 211ff674c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs deleted file mode 100644 index eff9c0ee8..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type.needing_catchup; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - commit_events_for_each_event_type((4, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs deleted file mode 100644 index e034227be..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/that_handles_no_event_types.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/that_handles_no_event_types.cs deleted file mode 100644 index 36bcdd35a..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/with_implicit_filter/that_handles_no_event_types.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.with_implicit_filter; - -class that_handles_no_event_types : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static Exception exception; - Establish context = () => - { - with_event_handlers_filtering_number_of_event_types(0); - event_handler = event_handlers_to_run.First(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler, 0); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 0).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler, 0!); - -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs index b441c7299..c747ec8c6 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs @@ -15,7 +15,7 @@ protected static void expect_stream_processor_state_without_failure(IEventHandle => expect_stream_processor_state_with_failure(event_handler, num_events_to_handle, null!); protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, int num_events_to_handle, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state(event_handler, false, false, num_events_to_handle, failing_partitioned_state); + => expect_stream_processor_state(event_handler, num_events_to_handle, failing_partitioned_state); protected static void with_event_handlers_filtering_number_of_event_types(params int[] max_event_types_to_filter) => with_event_handlers_filtering_number_of_event_types(max_event_types_to_filter diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs index 237183d69..61c75e177 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store.Streams; using Integration.Tests.Events.Processing.EventHandlers.given; @@ -30,8 +29,6 @@ class after_2_events : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((4, failing_partition.Value)); }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs index 34414c53d..80f3fe7e2 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs @@ -33,8 +33,6 @@ class on_both_partitions : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs index 3bed017e4..24998034c 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs @@ -33,7 +33,6 @@ class on_one_partition : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs index 635e1f136..6b034dfd3 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store.Streams; using Integration.Tests.Events.Processing.EventHandlers.given; @@ -31,7 +30,6 @@ class after_2_events : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs index ec558b63e..e870283fa 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs @@ -34,7 +34,6 @@ class on_both_partitions : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs index de8ae8c26..d9e27f110 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs @@ -34,7 +34,6 @@ class on_one_partition : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/withoutout_problems.cs index 116ef2379..ec8aba34e 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/withoutout_problems.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/withoutout_problems.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.Events; using Dolittle.Runtime.Events.Processing.EventHandlers; using Machine.Specifications; @@ -26,7 +25,6 @@ class without_problems : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, "some_source")); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/withoutout_problems.cs index d44ba46a5..621648583 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/withoutout_problems.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/withoutout_problems.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Machine.Specifications; @@ -20,8 +19,6 @@ class without_problems : given.single_tenant_and_event_handlers Because of = () => commit_events_after_starting_event_handler((2, "some_source")); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs index 0d5f3f1aa..fc5d81d86 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store.Streams; using Integration.Tests.Events.Processing.EventHandlers.given; @@ -30,8 +29,6 @@ class after_2_events : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs index 431895a91..a614d2c3a 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs @@ -33,8 +33,6 @@ class on_both_partitions : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs index f01e60066..e9939b3d7 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs @@ -33,7 +33,6 @@ class on_one_partition : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs index a268f0092..ab3a9ef5c 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store.Streams; using Integration.Tests.Events.Processing.EventHandlers.given; @@ -31,7 +30,6 @@ class after_2_events : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs index f1f4cfb52..b43500e15 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs @@ -34,7 +34,6 @@ class on_both_partitions : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs index 70e54cb1c..85fa55e82 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs @@ -34,7 +34,6 @@ class on_one_partition : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/withoutout_problems.cs index 14d50f6a3..cc1b3e8ff 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/withoutout_problems.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/withoutout_problems.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Machine.Specifications; @@ -24,7 +23,6 @@ class without_problems : given.single_tenant_and_event_handlers }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/withoutout_problems.cs index 3f2e2e88f..c6f121729 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/withoutout_problems.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/withoutout_problems.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Machine.Specifications; @@ -23,6 +22,5 @@ class without_problems : given.single_tenant_and_event_handlers }; It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/that_handles_no_event_types.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/that_handles_no_event_types.cs deleted file mode 100644 index 9657c6410..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/event_handler/without_implicit_filter/that_handles_no_event_types.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.event_handler.without_implicit_filter; - -class that_handles_no_event_types : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static Exception exception; - Establish context = () => - { - with_event_handlers_filtering_number_of_event_types(0); - event_handler = event_handlers_to_run.First(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler, 0); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 0).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler, 0!); - -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index b7b1cda32..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.given; - -class single_tenant_and_event_handlers : partitioned.given.single_tenant_and_event_handlers -{ - protected static void with_event_handlers_filtering_number_of_event_types(params (int max_event_types_to_filter, bool implicitFilter)[] event_handler_infos) - => with_event_handlers_filtering_number_of_event_types(event_handler_infos - .Select(_ => (_.max_event_types_to_filter, true, _.implicitFilter)) - .ToArray()); - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 04b357827..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.given; - -class single_tenant_and_event_handlers : fast_event_handler.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler, int num_events_to_handle) - => expect_stream_processor_state_with_failure(event_handler, num_events_to_handle, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, int num_events_to_handle, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state(event_handler, true, true, num_events_to_handle, failing_partitioned_state); - - protected static void with_event_handlers_filtering_number_of_event_types(params int[] max_event_types_to_filter) - => with_event_handlers_filtering_number_of_event_types(max_event_types_to_filter - .Select(_ => (_, true)) - .ToArray()); - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs deleted file mode 100644 index 83f4fa453..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((4, failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs deleted file mode 100644 index f967f59ef..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs deleted file mode 100644 index 57f0939a4..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index da2bd853a..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.given; - -class single_tenant_and_event_handlers : with_implicit_filter.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, number_of_event_types); - - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_with_failure(event_handler, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state_with_failure( - event_handler, - scoped_committed_events[event_handler_scope].Count, - failing_partitioned_state); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - number_of_event_types - } - .Select(_ => _) - .ToArray()); - return event_handlers_to_run.First(); - } - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index 16d7c1be7..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs deleted file mode 100644 index cf68abde5..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index d6052b5d3..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs deleted file mode 100644 index f6d332548..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.needing_catchup; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static EventSourceId event_source; - - Establish context = () => - { - event_source = "some_source"; - commit_events_for_each_event_type((2, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs deleted file mode 100644 index b7795ea3b..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => commit_events_after_starting_event_handler((2, "some_source")); - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs deleted file mode 100644 index a156755c8..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs deleted file mode 100644 index eddb5266c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs deleted file mode 100644 index 155c47eee..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 19565cc80..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.given; - -class single_tenant_and_event_handlers : with_implicit_filter.given.single_tenant_and_event_handlers -{ - - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, 1); - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_with_failure(event_handler, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state_with_failure(event_handler, scope_events_for_event_types(event_handler_scope, 1).Count(), failing_partitioned_state); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - 1 - } - .Select(_ => (_, true)) - .ToArray()); - return event_handlers_to_run.First(); - } -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index da6d14daf..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((4, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs deleted file mode 100644 index ff9165628..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index 9a48d4216..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs deleted file mode 100644 index f977d05c6..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.needing_catchup; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - commit_events_for_each_event_type((4, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs deleted file mode 100644 index fc50e885e..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/that_handles_no_event_types.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/that_handles_no_event_types.cs deleted file mode 100644 index ef5bb5272..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/with_implicit_filter/that_handles_no_event_types.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.with_implicit_filter; - -class that_handles_no_event_types : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static Exception exception; - Establish context = () => - { - with_event_handlers_filtering_number_of_event_types(0); - event_handler = event_handlers_to_run.First(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler, 0); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 0).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler, 0!); - -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index b9ec28f06..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.given; - -class single_tenant_and_event_handlers : fast_event_handler.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler, int num_events_to_handle) - => expect_stream_processor_state_with_failure(event_handler, num_events_to_handle, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, int num_events_to_handle, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state(event_handler, false, true, num_events_to_handle, failing_partitioned_state); - - protected static void with_event_handlers_filtering_number_of_event_types(params int[] max_event_types_to_filter) - => with_event_handlers_filtering_number_of_event_types(max_event_types_to_filter - .Select(_ => (_, false)) - .ToArray()); - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs deleted file mode 100644 index fcac6b003..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.and_failing; - - -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((4, failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs deleted file mode 100644 index a1c319df1..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.and_failing; - - -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs deleted file mode 100644 index 969bb5b27..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.and_failing; - - -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 355e386c7..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.given; - -class single_tenant_and_event_handlers : without_implicit_filter.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, number_of_event_types); - - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_with_failure(event_handler, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state_with_failure( - event_handler, - scoped_committed_events[event_handler_scope].Count, - failing_partitioned_state); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - number_of_event_types - } - .Select(_ => _) - .ToArray()); - return event_handlers_to_run.First(); - } - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index f230ad522..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - - -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs deleted file mode 100644 index 12d3c09a4..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - - -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index e17a5c0f6..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - - -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/withoutout_problems.cs deleted file mode 100644 index a47c0b625..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/withoutout_problems.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.needing_catchup; - - -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static EventSourceId event_source; - - Establish context = () => - { - event_source = "some_source"; - commit_events_for_each_event_type((2, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/withoutout_problems.cs deleted file mode 100644 index 2088fbc3e..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/withoutout_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types; - - -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => commit_events_after_starting_event_handler((2, "some_source")); - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, number_of_event_types).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs deleted file mode 100644 index b22a0357c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.and_failing; - - -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs deleted file mode 100644 index 9667cbf57..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.and_failing; - - -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs deleted file mode 100644 index 689c726ad..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.and_failing; - - -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 2efad4832..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.given; - -class single_tenant_and_event_handlers : without_implicit_filter.given.single_tenant_and_event_handlers -{ - - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, 1); - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_with_failure(event_handler, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state_with_failure(event_handler, scope_events_for_event_types(event_handler_scope, 1).Count(), failing_partitioned_state); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - 1 - } - .Select(_ => _) - .ToArray()); - return event_handlers_to_run.First(); - } -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index a48d53eec..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - - -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((4, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs deleted file mode 100644 index ad4e6d4bc..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - - -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index 34216681b..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - - -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/withoutout_problems.cs deleted file mode 100644 index b59ef29eb..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/withoutout_problems.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.needing_catchup; - - -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - commit_events_for_each_event_type((4, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/withoutout_problems.cs deleted file mode 100644 index 3ac13c614..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/withoutout_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type; - - -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, scope_events_for_event_types(event_handler_scope, 1).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/that_handles_no_event_types.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/that_handles_no_event_types.cs deleted file mode 100644 index 1f5e6b897..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/fast_event_handler/without_implicit_filter/that_handles_no_event_types.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.fast_event_handler.without_implicit_filter; - -class that_handles_no_event_types : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static Exception exception; - Establish context = () => - { - with_event_handlers_filtering_number_of_event_types(0); - event_handler = event_handlers_to_run.First(); - }; - - Because of = () => - { - exception = Catch.Exception(() => commit_events_after_starting_event_handler((2, "some_source"))); - }; - - It should_fail_starting_event_handler = () => exception.ShouldNotBeNull(); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/given/single_tenant_and_event_handlers.cs index 54cafb6b3..da2a73803 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/given/single_tenant_and_event_handlers.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/scoped/partitioned/given/single_tenant_and_event_handlers.cs @@ -5,7 +5,6 @@ using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; using Integration.Tests.Events.Processing.EventHandlers.given; namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.scoped.partitioned.given; @@ -15,11 +14,9 @@ class single_tenant_and_event_handlers : scoped.given.single_tenant_and_event_ha protected static void expect_stream_definition(IEventHandler event_handler, int max_handled_event_types) => expect_correct_stream_definition(event_handler, partitioned: true, public_stream: false, max_handled_event_types: max_handled_event_types); - protected static void expect_stream_processor_state(IEventHandler event_handler, bool implicit_filter, bool fast_event_handler, int num_events_to_handle, failing_partitioned_state failing_partitioned_state) + protected static void expect_stream_processor_state(IEventHandler event_handler, int num_events_to_handle, failing_partitioned_state failing_partitioned_state) => expect_stream_processor_state( event_handler, - implicit_filter: implicit_filter, - fast_event_handler: fast_event_handler, partitioned: true, num_events_to_handle: num_events_to_handle, failing_partitioned_state: failing_partitioned_state, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 6b5d11d6a..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.with_implicit_filter.given; - -class single_tenant_and_event_handlers : event_handler.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler, int num_events_to_handle) - => expect_stream_processor_state(event_handler, true, false, num_events_to_handle, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_unpartitioned_state failing_unpartitioned_state) - => expect_stream_processor_state(event_handler, true, false, (int)failing_unpartitioned_state.failing_position.Value, failing_unpartitioned_state); - - protected static void with_event_handlers_filtering_number_of_event_types(params int[] max_event_types_to_filter) - => with_event_handlers_filtering_number_of_event_types(max_event_types_to_filter - .Select(_ => (_, true)) - .ToArray()); - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs deleted file mode 100644 index 57f47a89c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((4, failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs deleted file mode 100644 index d02e05977..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 7fa7e9b17..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.with_implicit_filter.processing_all_event_types.given; - -class single_tenant_and_event_handlers : with_implicit_filter.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, number_of_event_types); - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_without_failure(event_handler, committed_events.Count); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - number_of_event_types - } - .Select(_ => _) - .ToArray()); - return event_handlers_to_run.First(); - } - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index 168a48144..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index cbc67e01d..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/without_problems.cs deleted file mode 100644 index 6c462e19f..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/without_problems.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.with_implicit_filter.processing_all_event_types.needing_catchup; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static EventSourceId event_source; - - Establish context = () => - { - event_source = "some_source"; - commit_events_for_each_event_type((2, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/without_problems.cs deleted file mode 100644 index 0fdc8f0c7..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_all_event_types/without_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.with_implicit_filter.processing_all_event_types; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => commit_events_after_starting_event_handler((2, "some_source")); - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs deleted file mode 100644 index 4c6761cc6..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs deleted file mode 100644 index 240db4c84..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 7dd7bb34f..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.with_implicit_filter.processing_one_event_type.given; - -class single_tenant_and_event_handlers : with_implicit_filter.given.single_tenant_and_event_handlers -{ - - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, 1); - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_without_failure(event_handler, committed_events_for_event_types(1).Count()); - - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - 1 - } - .Select(_ => (_, true)) - .ToArray()); - return event_handlers_to_run.First(); - } -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index 0db8e10c1..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((4, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index 11f3d898c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/without_problems.cs deleted file mode 100644 index 934f01c6c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/without_problems.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.with_implicit_filter.processing_one_event_type.needing_catchup; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - commit_events_for_each_event_type((4, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/without_problems.cs deleted file mode 100644 index 1e062056c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/not_processing_one_event_type/without_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.with_implicit_filter.processing_one_event_type; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/that_handles_no_event_types.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/that_handles_no_event_types.cs deleted file mode 100644 index 287d2b355..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/with_implicit_filter/that_handles_no_event_types.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.with_implicit_filter; - -class that_handles_no_event_types : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static Exception exception; - Establish context = () => - { - with_event_handlers_filtering_number_of_event_types(0); - event_handler = event_handlers_to_run.First(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler, 0); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(0).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler, 0!); - -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs index 380902cb0..6a21ca097 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs @@ -12,10 +12,10 @@ namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscop class single_tenant_and_event_handlers : event_handler.given.single_tenant_and_event_handlers { protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler, int num_events_to_handle) - => expect_stream_processor_state(event_handler, false, false, num_events_to_handle, null!); + => expect_stream_processor_state(event_handler, num_events_to_handle, null!); protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_unpartitioned_state failing_unpartitioned_state) - => expect_stream_processor_state(event_handler, false, false, (int)failing_unpartitioned_state.failing_position.Value, failing_unpartitioned_state); + => expect_stream_processor_state(event_handler, (int)failing_unpartitioned_state.failing_position.Value, failing_unpartitioned_state); protected static void with_event_handlers_filtering_number_of_event_types(params int[] max_event_types_to_filter) => with_event_handlers_filtering_number_of_event_types(max_event_types_to_filter diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs index 79a828de4..e2e7a0654 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs @@ -1,8 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store.Streams; using Integration.Tests.Events.Processing.EventHandlers.given; @@ -21,17 +19,15 @@ class after_2_events : given.single_tenant_and_event_handlers { failing_partition = "some event source"; failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); + fail_after_processing_number_of_events(3, failure_reason); event_handler = setup_event_handler(); }; Because of = () => { - commit_events_after_starting_event_handler((4, failing_partition.Value)); + commit_events_after_starting_event_handler((6, failing_partition.Value)); }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1)); + It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(2,failure_reason)); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs index 801e2c99d..64c477da6 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs @@ -32,9 +32,8 @@ class on_one_partition : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); + new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position, failure_reason)); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs index 028965415..d34e8e255 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs @@ -5,7 +5,6 @@ using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.without_implicit_filter.processing_all_event_types.given; diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs index 21ff47e45..e3aadaa27 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs @@ -1,15 +1,13 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store.Streams; using Integration.Tests.Events.Processing.EventHandlers.given; using Machine.Specifications; -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.without_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - +namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.without_implicit_filter. + processing_all_event_types.needing_catchup.and_failing; class after_2_events : given.single_tenant_and_event_handlers { @@ -26,12 +24,10 @@ class after_2_events : given.single_tenant_and_event_handlers event_handler = setup_event_handler(); }; - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; + Because of = () => { commit_events_after_starting_event_handler((2, failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1)); + + It should_have_the_correct_stream_processor_states = + () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1, failure_reason)); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs index 236a4ab9d..eb9a04633 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs @@ -33,9 +33,8 @@ class on_one_partition : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); + new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position, failure_reason)); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/withoutout_problems.cs index 29ba45b55..35ab062ba 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/withoutout_problems.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/withoutout_problems.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.Events; using Dolittle.Runtime.Events.Processing.EventHandlers; using Machine.Specifications; @@ -26,7 +25,6 @@ class without_problems : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, "some_source")); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/withoutout_problems.cs index 0fac05cf9..0c2dbdf5a 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/withoutout_problems.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_all_event_types/withoutout_problems.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Machine.Specifications; @@ -19,9 +18,6 @@ class without_problems : given.single_tenant_and_event_handlers Because of = () => commit_events_after_starting_event_handler((2, "some_source")); - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs index d8f8c711d..3a11af264 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs @@ -1,8 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store.Streams; using Integration.Tests.Events.Processing.EventHandlers.given; @@ -30,11 +28,9 @@ class after_2_events : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, - new failing_unpartitioned_state(1)); + new failing_unpartitioned_state(1, failure_reason)); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs index 016396ed0..0a2a6646b 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs @@ -32,10 +32,8 @@ class on_one_partition : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); + new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position, failure_reason)); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs index eeee0cb7e..8b3c62a25 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs @@ -5,7 +5,6 @@ using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.without_implicit_filter.processing_one_event_type.given; diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs index b5ce021c2..fd5b0036e 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs @@ -1,8 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store.Streams; using Integration.Tests.Events.Processing.EventHandlers.given; @@ -31,9 +29,8 @@ class after_2_events : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, - new failing_unpartitioned_state(1)); + new failing_unpartitioned_state(1, failure_reason)); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs index 5f84343b1..bf7208039 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs @@ -8,8 +8,8 @@ using Integration.Tests.Events.Processing.EventHandlers.given; using Machine.Specifications; -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.without_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - +namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.without_implicit_filter. + processing_one_event_type.needing_catchup.and_failing; class on_one_partition : given.single_tenant_and_event_handlers { @@ -24,18 +24,15 @@ class on_one_partition : given.single_tenant_and_event_handlers succeeding_partition = "some other event source"; failure_reason = "some reason"; commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); + fail_for_event_sources(new EventSourceId[] { failing_partition.Value }, failure_reason); event_handler = setup_event_handler(); }; - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; + Because of = () => { commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); + It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); + new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position, failure_reason)); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/withoutout_problems.cs index 7cf258dde..3420917c7 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/withoutout_problems.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/withoutout_problems.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Machine.Specifications; @@ -24,7 +23,6 @@ class without_problems : given.single_tenant_and_event_handlers }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/withoutout_problems.cs index 69fea3c00..55095c602 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/withoutout_problems.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/not_processing_one_event_type/withoutout_problems.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Machine.Specifications; @@ -23,6 +22,5 @@ class without_problems : given.single_tenant_and_event_handlers }; It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/that_handles_no_event_types.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/that_handles_no_event_types.cs deleted file mode 100644 index 09a01e30c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/event_handler/without_implicit_filter/that_handles_no_event_types.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.event_handler.without_implicit_filter; - -class that_handles_no_event_types : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static Exception exception; - Establish context = () => - { - with_event_handlers_filtering_number_of_event_types(0); - event_handler = event_handlers_to_run.First(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler, 0); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(0).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler, 0!); - -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 4b518f312..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.given; - -class single_tenant_and_event_handlers : not_partitioned.given.single_tenant_and_event_handlers -{ - protected static void with_event_handlers_filtering_number_of_event_types(params (int max_event_types_to_filter, bool implicitFilter)[] event_handler_infos) - => with_event_handlers_filtering_number_of_event_types(event_handler_infos - .Select(_ => (_.max_event_types_to_filter, true, _.implicitFilter)) - .ToArray()); - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 4f0ea4e7d..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.with_implicit_filter.given; - -class single_tenant_and_event_handlers : fast_event_handler.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler, int num_events_to_handle) - => expect_stream_processor_state(event_handler, true, true, num_events_to_handle, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_unpartitioned_state failing_unpartitioned_state) - => expect_stream_processor_state(event_handler, true, true, (int)failing_unpartitioned_state.failing_position.Value, failing_unpartitioned_state); - - protected static void with_event_handlers_filtering_number_of_event_types(params int[] max_event_types_to_filter) - => with_event_handlers_filtering_number_of_event_types(max_event_types_to_filter - .Select(_ => (_, true)) - .ToArray()); - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs deleted file mode 100644 index 10a716580..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((4, failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs deleted file mode 100644 index e5243da05..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index a8b8ded05..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.given; - -class single_tenant_and_event_handlers : with_implicit_filter.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, number_of_event_types); - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_without_failure(event_handler, committed_events.Count); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - number_of_event_types - } - .Select(_ => _) - .ToArray()); - return event_handlers_to_run.First(); - } - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index e3573e680..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index f118df7e7..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/without_problems.cs deleted file mode 100644 index 7b0be726d..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/needing_catchup/without_problems.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.needing_catchup; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static EventSourceId event_source; - - Establish context = () => - { - event_source = "some_source"; - commit_events_for_each_event_type((2, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/without_problems.cs deleted file mode 100644 index f0f1820e4..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_all_event_types/without_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => commit_events_after_starting_event_handler((2, "some_source")); - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs deleted file mode 100644 index 979a9fb74..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs deleted file mode 100644 index be5536c04..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index ca59fe87b..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.given; - -class single_tenant_and_event_handlers : with_implicit_filter.given.single_tenant_and_event_handlers -{ - - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, 1); - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_without_failure(event_handler, committed_events_for_event_types(1).Count()); - - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - 1 - } - .Select(_ => (_, true)) - .ToArray()); - return event_handlers_to_run.First(); - } -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index e9671705a..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((4, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index be46194ad..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/without_problems.cs deleted file mode 100644 index cb9103e5a..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/needing_catchup/without_problems.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.needing_catchup; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - commit_events_for_each_event_type((4, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/without_problems.cs deleted file mode 100644 index 5e1805aab..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/not_processing_one_event_type/without_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/that_handles_no_event_types.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/that_handles_no_event_types.cs deleted file mode 100644 index bf042ef73..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/with_implicit_filter/that_handles_no_event_types.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.with_implicit_filter; - -class that_handles_no_event_types : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static Exception exception; - Establish context = () => - { - with_event_handlers_filtering_number_of_event_types(0); - event_handler = event_handlers_to_run.First(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler, 0); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(0).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler, 0!); - -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index bd20abd65..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.without_implicit_filter.given; - -class single_tenant_and_event_handlers : fast_event_handler.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler, int num_events_to_handle) - => expect_stream_processor_state(event_handler, false, true, num_events_to_handle, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_unpartitioned_state failing_unpartitioned_state) - => expect_stream_processor_state(event_handler, false, true, (int)failing_unpartitioned_state.failing_position.Value, failing_unpartitioned_state); - - protected static void with_event_handlers_filtering_number_of_event_types(params int[] max_event_types_to_filter) - => with_event_handlers_filtering_number_of_event_types(max_event_types_to_filter - .Select(_ => (_, false)) - .ToArray()); - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs deleted file mode 100644 index a5857af8c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.and_failing; - - -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((4, failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs deleted file mode 100644 index 9cd6b1508..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/and_failing/on_one_partition.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.and_failing; - - -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 6c8f9f451..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.given; - -class single_tenant_and_event_handlers : without_implicit_filter.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, number_of_event_types); - - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_without_failure(event_handler, committed_events.Count); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - number_of_event_types - } - .Select(_ => _) - .ToArray()); - return event_handlers_to_run.First(); - } - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index 84608a611..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - - -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index 99b97db2a..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - - -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/withoutout_problems.cs deleted file mode 100644 index 1e80c1ae2..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/needing_catchup/withoutout_problems.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.needing_catchup; - - -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static EventSourceId event_source; - - Establish context = () => - { - event_source = "some_source"; - commit_events_for_each_event_type((2, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/withoutout_problems.cs deleted file mode 100644 index 9bfc25f77..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_all_event_types/withoutout_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types; - - -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => commit_events_after_starting_event_handler((2, "some_source")); - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs deleted file mode 100644 index 3083efe70..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/after_2_events.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.and_failing; - - -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs deleted file mode 100644 index 8f666ed4c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.and_failing; - - -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 9cfeef46c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.given; - -class single_tenant_and_event_handlers : without_implicit_filter.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, 1); - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_without_failure(event_handler, committed_events_for_event_types(1).Count()); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - 1 - } - .Select(_ => _) - .ToArray()); - return event_handlers_to_run.First(); - } -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index ae64d2b64..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - - -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((4, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(1)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index cc1dfc651..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - - -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_unpartitioned_state(get_partitioned_events_in_stream(event_handler, failing_partition).First().Position)); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/withoutout_problems.cs deleted file mode 100644 index 0dd4453b2..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/needing_catchup/withoutout_problems.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.needing_catchup; - - -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - commit_events_for_each_event_type((4, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/withoutout_problems.cs deleted file mode 100644 index 5f1c4b9a9..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/not_processing_one_event_type/withoutout_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type; - - -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/that_handles_no_event_types.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/that_handles_no_event_types.cs deleted file mode 100644 index db82ab888..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/fast_event_handler/without_implicit_filter/that_handles_no_event_types.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.not_partitioned.fast_event_handler.without_implicit_filter; - -class that_handles_no_event_types : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static Exception exception; - Establish context = () => - { - with_event_handlers_filtering_number_of_event_types(0); - event_handler = event_handlers_to_run.First(); - }; - - Because of = () => - { - exception = Catch.Exception(() => commit_events_after_starting_event_handler((2, "some_source"))); - }; - - It should_fail_starting_event_handler = () => exception.ShouldNotBeNull(); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/given/single_tenant_and_event_handlers.cs index 56cec7fa7..b00058211 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/given/single_tenant_and_event_handlers.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/not_partitioned/given/single_tenant_and_event_handlers.cs @@ -15,11 +15,9 @@ class single_tenant_and_event_handlers : unscoped.given.single_tenant_and_event_ protected static void expect_stream_definition(IEventHandler event_handler, int max_handled_event_types) => expect_correct_stream_definition(event_handler, partitioned: false, public_stream: false, max_handled_event_types: max_handled_event_types); - protected static void expect_stream_processor_state(IEventHandler event_handler, bool implicit_filter, bool fast_event_handler, int num_events_to_handle, failing_unpartitioned_state failing_unpartitioned_state) + protected static void expect_stream_processor_state(IEventHandler event_handler, int num_events_to_handle, failing_unpartitioned_state failing_unpartitioned_state) => expect_stream_processor_state( event_handler, - implicit_filter: implicit_filter, - fast_event_handler: fast_event_handler, partitioned: false, num_events_to_handle: num_events_to_handle, failing_partitioned_state: null, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/given/single_tenant_and_event_handlers.cs index 7466c83cf..e800544f7 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/given/single_tenant_and_event_handlers.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/given/single_tenant_and_event_handlers.cs @@ -4,10 +4,6 @@ #nullable enable using System.Linq; -using System.Threading.Tasks; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Integration.Tests.Events.Processing.EventHandlers.given; namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.given; diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 64436bf2c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.given; - -class single_tenant_and_event_handlers : event_handler.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler, int num_events_to_handle) - => expect_stream_processor_state_with_failure(event_handler, num_events_to_handle, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, int num_events_to_handle, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state(event_handler, true, false, num_events_to_handle, failing_partitioned_state); - - protected static void with_event_handlers_filtering_number_of_event_types(params int[] max_event_types_to_filter) - => with_event_handlers_filtering_number_of_event_types(max_event_types_to_filter - .Select(_ => (_, true)) - .ToArray()); - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs deleted file mode 100644 index e9978332e..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((4, failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs deleted file mode 100644 index d37697ef7..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs deleted file mode 100644 index 26905f9f6..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 24100060a..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types.given; - -class single_tenant_and_event_handlers : with_implicit_filter.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, number_of_event_types); - - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_with_failure(event_handler, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state_with_failure( - event_handler, - committed_events.Count, - failing_partitioned_state); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - number_of_event_types - } - .Select(_ => _) - .ToArray()); - return event_handlers_to_run.First(); - } - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index df38299b5..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs deleted file mode 100644 index 65248a608..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index 8b4c836bf..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs deleted file mode 100644 index d1f91c173..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types.needing_catchup; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static EventSourceId event_source; - - Establish context = () => - { - event_source = "some_source"; - commit_events_for_each_event_type((2, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs deleted file mode 100644 index c2e38aba2..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_all_event_types; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => commit_events_after_starting_event_handler((2, "some_source")); - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs deleted file mode 100644 index 368494d5b..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs deleted file mode 100644 index 7a153106a..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs deleted file mode 100644 index 989c80b43..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 3eae2c83b..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type.given; - -class single_tenant_and_event_handlers : with_implicit_filter.given.single_tenant_and_event_handlers -{ - - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, 1); - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_with_failure(event_handler, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state_with_failure(event_handler, committed_events_for_event_types(1).Count(), failing_partitioned_state); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - 1 - } - .Select(_ => (_, true)) - .ToArray()); - return event_handlers_to_run.First(); - } -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index cdda129ee..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((4, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs deleted file mode 100644 index 9393472cb..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index c6e793b72..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs deleted file mode 100644 index f3085b662..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type.needing_catchup; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - commit_events_for_each_event_type((4, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs deleted file mode 100644 index 1af60c437..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter.processing_one_event_type; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/that_handles_no_event_types.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/that_handles_no_event_types.cs deleted file mode 100644 index dd172dd2c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/with_implicit_filter/that_handles_no_event_types.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.with_implicit_filter; - -class that_handles_no_event_types : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static Exception exception; - Establish context = () => - { - with_event_handlers_filtering_number_of_event_types(0); - event_handler = event_handlers_to_run.First(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler, 0); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(0).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler, 0!); - -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs index e8408a4b7..60cd1a3f5 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs @@ -15,7 +15,7 @@ protected static void expect_stream_processor_state_without_failure(IEventHandle => expect_stream_processor_state_with_failure(event_handler, num_events_to_handle, null!); protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, int num_events_to_handle, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state(event_handler, false, false, num_events_to_handle, failing_partitioned_state); + => expect_stream_processor_state(event_handler, num_events_to_handle, failing_partitioned_state); protected static void with_event_handlers_filtering_number_of_event_types(params int[] max_event_types_to_filter) => with_event_handlers_filtering_number_of_event_types(max_event_types_to_filter diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs index 543cdc20d..71176d075 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store.Streams; using Integration.Tests.Events.Processing.EventHandlers.given; @@ -31,7 +30,6 @@ class after_2_events : given.single_tenant_and_event_handlers }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs index 7c6eaeeed..735320158 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs @@ -34,7 +34,6 @@ class on_both_partitions : given.single_tenant_and_event_handlers }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs index 0db220223..98f96a487 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs @@ -33,7 +33,6 @@ class on_one_partition : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs index 77d10266b..a5b3ff1f1 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store.Streams; using Integration.Tests.Events.Processing.EventHandlers.given; @@ -31,7 +30,6 @@ class after_2_events : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs index 356f34be3..d736b77ea 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs @@ -34,7 +34,6 @@ class on_both_partitions : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs index 54260febc..d2fda7a6d 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs @@ -34,7 +34,6 @@ class on_one_partition : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/withoutout_problems.cs index ca76cc627..f02ee70fb 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/withoutout_problems.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/withoutout_problems.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.Events; using Dolittle.Runtime.Events.Processing.EventHandlers; using Machine.Specifications; @@ -26,7 +25,6 @@ class without_problems : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, "some_source")); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/withoutout_problems.cs index 16bd7d5b5..0721e4ac6 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/withoutout_problems.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_all_event_types/withoutout_problems.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Machine.Specifications; @@ -20,7 +19,6 @@ class without_problems : given.single_tenant_and_event_handlers Because of = () => commit_events_after_starting_event_handler((2, "some_source")); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs index c5c46973b..aca73d771 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store.Streams; using Integration.Tests.Events.Processing.EventHandlers.given; @@ -30,8 +29,6 @@ class after_2_events : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs index 2f35bc36d..3042be659 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs @@ -33,8 +33,6 @@ class on_both_partitions : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs index 56574108f..05e75c0fc 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs @@ -33,8 +33,6 @@ class on_one_partition : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs index 958a9b58e..3063fe045 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Store.Streams; using Integration.Tests.Events.Processing.EventHandlers.given; @@ -31,7 +30,6 @@ class after_2_events : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs index 08a5e1e7a..e83ed4181 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs @@ -34,7 +34,6 @@ class on_both_partitions : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs index 423cdacfb..742b1992f 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs @@ -34,7 +34,6 @@ class on_one_partition : given.single_tenant_and_event_handlers commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( event_handler, diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/withoutout_problems.cs index 49a7c9248..b428104a3 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/withoutout_problems.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/withoutout_problems.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Machine.Specifications; @@ -24,7 +23,6 @@ class without_problems : given.single_tenant_and_event_handlers }; - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/withoutout_problems.cs index 01b4cdb77..3251556e0 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/withoutout_problems.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/processing_one_event_type/withoutout_problems.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.Events.Processing.EventHandlers; using Machine.Specifications; @@ -23,6 +22,5 @@ class without_problems : given.single_tenant_and_event_handlers }; It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); } \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/that_handles_no_event_types.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/that_handles_no_event_types.cs deleted file mode 100644 index 5899c2022..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/event_handler/without_implicit_filter/that_handles_no_event_types.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.event_handler.without_implicit_filter; - -class that_handles_no_event_types : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static Exception exception; - Establish context = () => - { - with_event_handlers_filtering_number_of_event_types(0); - event_handler = event_handlers_to_run.First(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler, 0); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(0).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler, 0!); - -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index e2d7ae71e..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.given; - -class single_tenant_and_event_handlers : partitioned.given.single_tenant_and_event_handlers -{ - protected static void with_event_handlers_filtering_number_of_event_types(params (int max_event_types_to_filter, bool implicitFilter)[] event_handler_infos) - => with_event_handlers_filtering_number_of_event_types(event_handler_infos - .Select(_ => (_.max_event_types_to_filter, true, _.implicitFilter)) - .ToArray()); - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 047aeac11..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.given; - -class single_tenant_and_event_handlers : fast_event_handler.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler, int num_events_to_handle) - => expect_stream_processor_state_with_failure(event_handler, num_events_to_handle, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, int num_events_to_handle, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state(event_handler, true, true, num_events_to_handle, failing_partitioned_state); - - protected static void with_event_handlers_filtering_number_of_event_types(params int[] max_event_types_to_filter) - => with_event_handlers_filtering_number_of_event_types(max_event_types_to_filter - .Select(_ => (_, true)) - .ToArray()); - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs deleted file mode 100644 index 8535aaeb6..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((4, failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs deleted file mode 100644 index 66522fb54..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs deleted file mode 100644 index 83c06d5f1..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index a0980b1da..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.given; - -class single_tenant_and_event_handlers : with_implicit_filter.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, number_of_event_types); - - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_with_failure(event_handler, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state_with_failure( - event_handler, - committed_events.Count, - failing_partitioned_state); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - number_of_event_types - } - .Select(_ => _) - .ToArray()); - return event_handlers_to_run.First(); - } - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index 3abd8d7d5..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs deleted file mode 100644 index bdea5012b..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index 99ddf1930..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs deleted file mode 100644 index f334a111a..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/needing_catchup/without_problems.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types.needing_catchup; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static EventSourceId event_source; - - Establish context = () => - { - event_source = "some_source"; - commit_events_for_each_event_type((2, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs deleted file mode 100644 index a936f5809..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_all_event_types/without_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_all_event_types; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => commit_events_after_starting_event_handler((2, "some_source")); - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs deleted file mode 100644 index c968a807c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs deleted file mode 100644 index d81d0cbbd..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs deleted file mode 100644 index e4d395261..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index f9dc34b28..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.given; - -class single_tenant_and_event_handlers : with_implicit_filter.given.single_tenant_and_event_handlers -{ - - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, 1); - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_with_failure(event_handler, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state_with_failure(event_handler, committed_events_for_event_types(1).Count(), failing_partitioned_state); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - 1 - } - .Select(_ => (_, true)) - .ToArray()); - return event_handlers_to_run.First(); - } -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index 4e6d0dfba..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((4, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs deleted file mode 100644 index 7cc9da491..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index f92fe6edd..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - -[Ignore("Implicit filter does not work yet with event handlers")] -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs deleted file mode 100644 index 0244f5a68..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/needing_catchup/without_problems.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type.needing_catchup; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - commit_events_for_each_event_type((4, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs deleted file mode 100644 index a521f17e6..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/processing_one_event_type/without_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter.processing_one_event_type; - -[Ignore("Implicit filter does not work yet with event handlers")] -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/that_handles_no_event_types.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/that_handles_no_event_types.cs deleted file mode 100644 index 1b1e18589..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/with_implicit_filter/that_handles_no_event_types.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.with_implicit_filter; - -class that_handles_no_event_types : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static Exception exception; - Establish context = () => - { - with_event_handlers_filtering_number_of_event_types(0); - event_handler = event_handlers_to_run.First(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler, 0); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(0).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler, 0!); - -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index 3d32048b2..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.given; - -class single_tenant_and_event_handlers : fast_event_handler.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler, int num_events_to_handle) - => expect_stream_processor_state_with_failure(event_handler, num_events_to_handle, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, int num_events_to_handle, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state(event_handler, false, true, num_events_to_handle, failing_partitioned_state); - - protected static void with_event_handlers_filtering_number_of_event_types(params int[] max_event_types_to_filter) - => with_event_handlers_filtering_number_of_event_types(max_event_types_to_filter - .Select(_ => (_, false)) - .ToArray()); - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs deleted file mode 100644 index ce6595748..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.and_failing; - - -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((4, failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs deleted file mode 100644 index a251997ac..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.and_failing; - - -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs deleted file mode 100644 index d022baba8..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/and_failing/on_one_partition.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.and_failing; - - -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index e31ffac8e..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.given; - -class single_tenant_and_event_handlers : without_implicit_filter.given.single_tenant_and_event_handlers -{ - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, number_of_event_types); - - - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_with_failure(event_handler, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state_with_failure( - event_handler, - committed_events.Count, - failing_partitioned_state); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - number_of_event_types - } - .Select(_ => _) - .ToArray()); - return event_handlers_to_run.First(); - } - -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index 4d3736d1c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - - -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure(event_handler, new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs deleted file mode 100644 index c638f6608..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - - -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index 9d642d7c8..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.needing_catchup.and_failing; - - -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/withoutout_problems.cs deleted file mode 100644 index 91837baa1..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/needing_catchup/withoutout_problems.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types.needing_catchup; - - -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static EventSourceId event_source; - - Establish context = () => - { - event_source = "some_source"; - commit_events_for_each_event_type((2, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/withoutout_problems.cs deleted file mode 100644 index 3040d0c55..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_all_event_types/withoutout_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_all_event_types; - - -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => commit_events_after_starting_event_handler((2, "some_source")); - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(number_of_event_types).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs deleted file mode 100644 index 666a1f820..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/after_2_events.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.and_failing; - - -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs deleted file mode 100644 index 6abaede87..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.and_failing; - - -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs deleted file mode 100644 index f226b9f2a..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.and_failing; - - -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs deleted file mode 100644 index de506ff02..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/given/single_tenant_and_event_handlers.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -#nullable enable - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Integration.Tests.Events.Processing.EventHandlers.given; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.given; - -class single_tenant_and_event_handlers : without_implicit_filter.given.single_tenant_and_event_handlers -{ - - protected static void expect_stream_definition(IEventHandler event_handler) - => expect_stream_definition(event_handler, 1); - protected static void expect_stream_processor_state_without_failure(IEventHandler event_handler) - => expect_stream_processor_state_with_failure(event_handler, null!); - - protected static void expect_stream_processor_state_with_failure(IEventHandler event_handler, failing_partitioned_state failing_partitioned_state) - => expect_stream_processor_state_with_failure(event_handler, committed_events_for_event_types(1).Count(), failing_partitioned_state); - - protected static IEventHandler setup_event_handler() - { - with_event_handlers_filtering_number_of_event_types(new[] - { - 1 - } - .Select(_ => _) - .ToArray()); - return event_handlers_to_run.First(); - } -} - - - \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs deleted file mode 100644 index cd6d65576..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/after_2_events.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - - -class after_2_events : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - - Establish context = () => - { - failing_partition = "some event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((4, failing_partition.Value)); - fail_after_processing_number_of_events(2, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{{failing_partition, 1}})); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs deleted file mode 100644 index e1bc520fa..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_both_partitions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - - -class on_both_partitions : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId first_failing_partition; - static PartitionId second_failing_partition; - - Establish context = () => - { - first_failing_partition = "some event source"; - second_failing_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - fail_for_event_sources(new EventSourceId[]{first_failing_partition.Value, second_failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, first_failing_partition.Value), (2, second_failing_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - first_failing_partition, - get_partitioned_events_in_stream(event_handler, first_failing_partition).First().Position - }, - { - second_failing_partition, - get_partitioned_events_in_stream(event_handler, second_failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs deleted file mode 100644 index fb336658c..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/and_failing/on_one_partition.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Dolittle.Runtime.Events.Store.Streams; -using Integration.Tests.Events.Processing.EventHandlers.given; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.needing_catchup.and_failing; - - -class on_one_partition : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static string failure_reason; - static PartitionId failing_partition; - static PartitionId succeeding_partition; - - Establish context = () => - { - failing_partition = "some event source"; - succeeding_partition = "some other event source"; - failure_reason = "some reason"; - commit_events_for_each_event_type((2, failing_partition.Value), (2, succeeding_partition.Value)); - fail_for_event_sources(new EventSourceId[]{failing_partition.Value}, failure_reason); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, failing_partition.Value), (2, succeeding_partition.Value)); - }; - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_with_failure( - event_handler, - new failing_partitioned_state(new Dictionary{ - { - failing_partition, - get_partitioned_events_in_stream(event_handler, failing_partition).First().Position - } - })); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/withoutout_problems.cs deleted file mode 100644 index 02b02a9da..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/needing_catchup/withoutout_problems.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type.needing_catchup; - - -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - commit_events_for_each_event_type((4, "some_source")); - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/withoutout_problems.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/withoutout_problems.cs deleted file mode 100644 index 33b000a8b..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/processing_one_event_type/withoutout_problems.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter.processing_one_event_type; - - -class without_problems : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - - Establish context = () => - { - event_handler = setup_event_handler(); - }; - - Because of = () => - { - commit_events_after_starting_event_handler((2, "some_source")); - }; - - It should_have_persisted_correct_stream = () => expect_stream_definition(event_handler); - It should_the_correct_number_of_events_in_stream = () => expect_number_of_filtered_events(event_handler, committed_events_for_event_types(1).LongCount()); - It should_have_the_correct_stream_processor_states = () => expect_stream_processor_state_without_failure(event_handler); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/that_handles_no_event_types.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/that_handles_no_event_types.cs deleted file mode 100644 index e34dab387..000000000 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/fast_event_handler/without_implicit_filter/that_handles_no_event_types.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using Dolittle.Runtime.Events.Processing.EventHandlers; -using Machine.Specifications; - -namespace Integration.Tests.Events.Processing.EventHandlers.with_a_single.unscoped.partitioned.fast_event_handler.without_implicit_filter; - -class that_handles_no_event_types : given.single_tenant_and_event_handlers -{ - static IEventHandler event_handler; - static Exception exception; - Establish context = () => - { - with_event_handlers_filtering_number_of_event_types(0); - event_handler = event_handlers_to_run.First(); - }; - - Because of = () => - { - exception = Catch.Exception(() => commit_events_after_starting_event_handler((2, "some_source"))); - }; - - It should_fail_starting_event_handler = () => exception.ShouldNotBeNull(); -} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/given/single_tenant_and_event_handlers.cs b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/given/single_tenant_and_event_handlers.cs index 187ebbca4..aeca25007 100644 --- a/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/given/single_tenant_and_event_handlers.cs +++ b/Integration/Tests/Events.Processing/EventHandlers/with_a_single/unscoped/partitioned/given/single_tenant_and_event_handlers.cs @@ -15,11 +15,9 @@ class single_tenant_and_event_handlers : unscoped.given.single_tenant_and_event_ protected static void expect_stream_definition(IEventHandler event_handler, int max_handled_event_types) => expect_correct_stream_definition(event_handler, partitioned: true, public_stream: false, max_handled_event_types: max_handled_event_types); - protected static void expect_stream_processor_state(IEventHandler event_handler, bool implicit_filter, bool fast_event_handler, int num_events_to_handle, failing_partitioned_state failing_partitioned_state) + protected static void expect_stream_processor_state(IEventHandler event_handler, int num_events_to_handle, failing_partitioned_state failing_partitioned_state) => expect_stream_processor_state( event_handler, - implicit_filter: implicit_filter, - fast_event_handler: fast_event_handler, partitioned: true, num_events_to_handle: num_events_to_handle, failing_partitioned_state: failing_partitioned_state, diff --git a/Integration/Tests/Events.Processing/Events.Processing.csproj b/Integration/Tests/Events.Processing/Events.Processing.csproj index 030eb9d00..48bc8a07f 100644 --- a/Integration/Tests/Events.Processing/Events.Processing.csproj +++ b/Integration/Tests/Events.Processing/Events.Processing.csproj @@ -8,7 +8,7 @@ - + diff --git a/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/non_default_scope/failing/nonpartitioned.cs b/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/non_default_scope/failing/nonpartitioned.cs new file mode 100644 index 000000000..52d2b1833 --- /dev/null +++ b/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/non_default_scope/failing/nonpartitioned.cs @@ -0,0 +1,44 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Rudimentary; +using FluentAssertions; +using Machine.Specifications; + +namespace Integration.Tests.Events.Processing.StreamProcessorStates.StreamProcessorId.non_default_scope.failing; + +class nonpartitioned : given.a_clean_event_store +{ + static readonly ScopeId scope_id = Guid.Parse("abef5f64-9916-4762-a234-527990bc6c7c"); + static readonly Guid event_processor_id = Guid.Parse("07f1ee20-ec03-41a1-8bf5-c66cf6359cdf"); + static readonly Guid source_stream_id = Guid.Parse("c9294a5d-2e85-4ae2-8411-878d5d4fb4ac"); + static readonly DateTimeOffset retry_time = DateTimeOffset.Now; + static readonly DateTimeOffset last_successfully_processed = DateTimeOffset.Now - TimeSpan.FromSeconds(10); + + static readonly Dolittle.Runtime.Events.Processing.Streams.StreamProcessorId stream_processor_id = new(scope_id, event_processor_id, + source_stream_id); + + + static readonly StreamProcessorState stream_processor_state = + new(new ProcessingPosition(10, 19), "Testing", retry_time, 1, last_successfully_processed, true); + + + Establish context = () => + { + stream_processor_states.Persist(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult(); + retrieved_stream_processor_state = stream_processor_states.TryGetFor(stream_processor_id, CancellationToken.None).GetAwaiter().GetResult(); + }; + + It should_have_retrieved_the_state_successfully = () => retrieved_stream_processor_state.Success.Should().BeTrue(); + + It should_have_the_correct_stream_processor_state_type = () => + retrieved_stream_processor_state.Result.Should().BeOfType(); + + It should_have_the_correct_stream_processor_state = () => retrieved_stream_processor_state.Result.Should().BeEquivalentTo(stream_processor_state); + static Try retrieved_stream_processor_state; +} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/non_default_scope/failing/partitioned.cs b/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/non_default_scope/failing/partitioned.cs new file mode 100644 index 000000000..b3f1290e5 --- /dev/null +++ b/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/non_default_scope/failing/partitioned.cs @@ -0,0 +1,49 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Rudimentary; +using FluentAssertions; +using Machine.Specifications; + +namespace Integration.Tests.Events.Processing.StreamProcessorStates.StreamProcessorId.non_default_scope.failing; + +class partitioned : given.a_clean_event_store +{ + static readonly ScopeId scope_id = Guid.Parse("abef5f64-9916-4762-a234-527990bc6c7c"); + static readonly Guid event_processor_id = Guid.Parse("07f1ee20-ec03-41a1-8bf5-c66cf6359cdf"); + static readonly Guid source_stream_id = Guid.Parse("c9294a5d-2e85-4ae2-8411-878d5d4fb4ac"); + + static readonly PartitionId failing_partition_id = new("some-partition"); + static readonly DateTimeOffset last_failed = DateTimeOffset.Now - TimeSpan.FromSeconds(10); + static readonly DateTimeOffset retry_time = last_failed + TimeSpan.FromSeconds(30); + + static readonly Dolittle.Runtime.Events.Processing.Streams.StreamProcessorId stream_processor_id = new(scope_id, event_processor_id, + source_stream_id); + + static readonly StreamProcessorState stream_processor_state = + new(new ProcessingPosition(10, 12), new Dictionary + { + {failing_partition_id, new FailingPartitionState(new StreamPosition(5), 5, retry_time, "testing",2, last_failed)} + }.ToImmutableDictionary(), DateTimeOffset.Now); + + Establish context = () => + { + stream_processor_states.Persist(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult(); + retrieved_stream_processor_state = stream_processor_states.TryGetFor(stream_processor_id, CancellationToken.None).GetAwaiter().GetResult(); + }; + + It should_have_retrieved_the_state_successfully = () => retrieved_stream_processor_state.Success.Should().BeTrue(); + + It should_have_the_correct_stream_processor_state_type = () => + retrieved_stream_processor_state.Result.Should().BeOfType(); + + It should_have_the_correct_stream_processor_state = () => retrieved_stream_processor_state.Result.Should().BeEquivalentTo(stream_processor_state); + static Try retrieved_stream_processor_state; +} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/non_default_scope/nonpartitioned.cs b/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/non_default_scope/nonpartitioned.cs new file mode 100644 index 000000000..2b17aac7b --- /dev/null +++ b/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/non_default_scope/nonpartitioned.cs @@ -0,0 +1,43 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Rudimentary; +using FluentAssertions; +using Machine.Specifications; + +namespace Integration.Tests.Events.Processing.StreamProcessorStates.StreamProcessorId.non_default_scope; + +class nonpartitioned : given.a_clean_event_store +{ + static readonly ScopeId scope_id = Guid.Parse("abef5f64-9916-4762-a234-527990bc6c7c"); + static readonly Guid event_processor_id = Guid.Parse("07f1ee20-ec03-41a1-8bf5-c66cf6359cdf"); + static readonly Guid source_stream_id = Guid.Parse("c9294a5d-2e85-4ae2-8411-878d5d4fb4ac"); + static readonly DateTimeOffset last_successfully_processed = DateTimeOffset.Now; + + static readonly Dolittle.Runtime.Events.Processing.Streams.StreamProcessorId stream_processor_id = new(scope_id, event_processor_id, + source_stream_id); + + + static readonly StreamProcessorState stream_processor_state = + new(new ProcessingPosition(10, 10), "", last_successfully_processed, 0, last_successfully_processed, false); + + + Establish context = () => + { + stream_processor_states.Persist(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult(); + retrieved_stream_processor_state = stream_processor_states.TryGetFor(stream_processor_id, CancellationToken.None).GetAwaiter().GetResult(); + }; + + It should_have_retrieved_the_state_successfully = () => retrieved_stream_processor_state.Success.Should().BeTrue(); + + It should_have_the_correct_stream_processor_state_type = () => + retrieved_stream_processor_state.Result.Should().BeOfType(); + + It should_have_the_correct_stream_processor_state = () => retrieved_stream_processor_state.Result.Should().BeEquivalentTo(stream_processor_state); + static Try retrieved_stream_processor_state; +} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/non_default_scope/partitioned.cs b/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/non_default_scope/partitioned.cs new file mode 100644 index 000000000..a77d53eaf --- /dev/null +++ b/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/non_default_scope/partitioned.cs @@ -0,0 +1,41 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Immutable; +using System.Threading; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Rudimentary; +using FluentAssertions; +using Machine.Specifications; + +namespace Integration.Tests.Events.Processing.StreamProcessorStates.StreamProcessorId.non_default_scope; + +class partitioned : given.a_clean_event_store +{ + static readonly ScopeId scope_id = Guid.Parse("abef5f64-9916-4762-a234-527990bc6c7c"); + static readonly Guid event_processor_id = Guid.Parse("07f1ee20-ec03-41a1-8bf5-c66cf6359cdf"); + static readonly Guid source_stream_id = Guid.Parse("c9294a5d-2e85-4ae2-8411-878d5d4fb4ac"); + + static readonly Dolittle.Runtime.Events.Processing.Streams.StreamProcessorId stream_processor_id = new(scope_id, event_processor_id, + source_stream_id); + + static readonly StreamProcessorState stream_processor_state = + new(new ProcessingPosition(10,10), ImmutableDictionary.Empty, DateTimeOffset.Now); + + Establish context = () => + { + stream_processor_states.Persist(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult(); + retrieved_stream_processor_state = stream_processor_states.TryGetFor(stream_processor_id, CancellationToken.None).GetAwaiter().GetResult(); + }; + + It should_have_retrieved_the_state_successfully = () => retrieved_stream_processor_state.Success.Should().BeTrue(); + + It should_have_the_correct_stream_processor_state_type = () => + retrieved_stream_processor_state.Result.Should().BeOfType(); + + It should_have_the_correct_stream_processor_state = () => retrieved_stream_processor_state.Result.Should().BeEquivalentTo(stream_processor_state); + static Try retrieved_stream_processor_state; +} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/with_default_scope/nonpartitioned.cs b/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/with_default_scope/nonpartitioned.cs new file mode 100644 index 000000000..0f1714029 --- /dev/null +++ b/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/with_default_scope/nonpartitioned.cs @@ -0,0 +1,43 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Rudimentary; +using FluentAssertions; +using Machine.Specifications; + +namespace Integration.Tests.Events.Processing.StreamProcessorStates.StreamProcessorId.with_default_scope; + +class nonpartitioned : given.a_clean_event_store +{ + static readonly Guid event_processor_id = Guid.Parse("07f1ee20-ec03-41a1-8bf5-c66cf6359cdf"); + static readonly Guid source_stream_id = Guid.Parse("c9294a5d-2e85-4ae2-8411-878d5d4fb4ac"); + static readonly DateTimeOffset last_successfully_processed = DateTimeOffset.Now; + + static readonly Dolittle.Runtime.Events.Processing.Streams.StreamProcessorId stream_processor_id = new(ScopeId.Default, event_processor_id, + source_stream_id); + + + static readonly StreamProcessorState stream_processor_state = + new(new ProcessingPosition(10, 20), "", last_successfully_processed, 0, last_successfully_processed, false); + + + Establish context = () => + { + stream_processor_states.Persist(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult(); + retrieved_stream_processor_state = stream_processor_states.TryGetFor(stream_processor_id, CancellationToken.None).GetAwaiter().GetResult(); + }; + + It should_have_retrieved_the_state_successfully = () => retrieved_stream_processor_state.Success.Should().BeTrue(); + + + It should_have_the_correct_stream_processor_state_type = () => + retrieved_stream_processor_state.Result.Should().BeOfType(); + + It should_have_the_correct_stream_processor_state = () => retrieved_stream_processor_state.Result.Should().BeEquivalentTo(stream_processor_state); + static Try retrieved_stream_processor_state; +} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/with_default_scope/partitioned.cs b/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/with_default_scope/partitioned.cs new file mode 100644 index 000000000..f1cad90ec --- /dev/null +++ b/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/with_default_scope/partitioned.cs @@ -0,0 +1,40 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Immutable; +using System.Threading; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Rudimentary; +using FluentAssertions; +using Machine.Specifications; + +namespace Integration.Tests.Events.Processing.StreamProcessorStates.StreamProcessorId.with_default_scope; + +class partitioned : given.a_clean_event_store +{ + static readonly Guid event_processor_id = Guid.Parse("07f1ee20-ec03-41a1-8bf5-c66cf6359cdf"); + static readonly Guid source_stream_id = Guid.Parse("c9294a5d-2e85-4ae2-8411-878d5d4fb4ac"); + + static readonly Dolittle.Runtime.Events.Processing.Streams.StreamProcessorId stream_processor_id = new(ScopeId.Default, event_processor_id, + source_stream_id); + + static readonly StreamProcessorState stream_processor_state = + new(new ProcessingPosition(10,10), ImmutableDictionary.Empty, DateTimeOffset.Now); + + Establish context = () => + { + stream_processor_states.Persist(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult(); + retrieved_stream_processor_state = stream_processor_states.TryGetFor(stream_processor_id, CancellationToken.None).GetAwaiter().GetResult(); + }; + + It should_have_retrieved_the_state_successfully = () => retrieved_stream_processor_state.Success.Should().BeTrue(); + + It should_have_the_correct_stream_processor_state_type = () => + retrieved_stream_processor_state.Result.Should().BeOfType(); + + It should_have_the_correct_stream_processor_state = () => retrieved_stream_processor_state.Result.Should().BeEquivalentTo(stream_processor_state); + static Try retrieved_stream_processor_state; +} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/with_no_events.cs b/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/with_no_events.cs new file mode 100644 index 000000000..69ede5ed5 --- /dev/null +++ b/Integration/Tests/Events.Processing/StreamProcessorStates/StreamProcessorId/with_no_events.cs @@ -0,0 +1,31 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Rudimentary; +using FluentAssertions; +using Machine.Specifications; +using It = Machine.Specifications.It; + +namespace Integration.Tests.Events.Processing.StreamProcessorStates.StreamProcessorId; + +class with_no_events : given.a_clean_event_store +{ + static readonly ScopeId scope_id = Guid.Parse("abef5f64-9916-4762-a234-527990bc6c7c"); + static readonly Guid event_processor_id = Guid.Parse("07f1ee20-ec03-41a1-8bf5-c66cf6359cdf"); + static readonly Guid source_stream_id = Guid.Parse("c9294a5d-2e85-4ae2-8411-878d5d4fb4ac"); + + static readonly Dolittle.Runtime.Events.Processing.Streams.StreamProcessorId stream_processor_id = new(scope_id, event_processor_id, + source_stream_id); + + static Try result; + + Establish context = () => { result = stream_processor_states.TryGetFor(stream_processor_id, CancellationToken.None).GetAwaiter().GetResult(); }; + + It should_return_a_failure = () => result.Success.Should().BeFalse(); + + It should_return_a_stream_processor_state_not_found_exception = () => result.Exception.Should().BeOfType(); +} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/StreamProcessorStates/SubscriptionId/non_default_scope/nonpartitioned.cs b/Integration/Tests/Events.Processing/StreamProcessorStates/SubscriptionId/non_default_scope/nonpartitioned.cs new file mode 100644 index 000000000..5a965fd69 --- /dev/null +++ b/Integration/Tests/Events.Processing/StreamProcessorStates/SubscriptionId/non_default_scope/nonpartitioned.cs @@ -0,0 +1,66 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using Dolittle.Runtime.Domain.Platform; +using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Rudimentary; +using FluentAssertions; +using Machine.Specifications; + +namespace Integration.Tests.Events.Processing.StreamProcessorStates.SubscriptionId.non_default_scope; + +class nonpartitioned : given.a_clean_event_store +{ + static readonly DateTimeOffset last_successfully_processed = DateTimeOffset.Now; + + static TenantId consumer_tenant_id; + static MicroserviceId producer_microservice_id; + static TenantId producer_tenant_id; + static ScopeId scope_id; + static StreamId stream_id; + static PartitionId partition_id; + + + static Dolittle.Runtime.EventHorizon.Consumer.SubscriptionId subscription_id; + static StreamProcessorState stream_processor_state; + static StreamProcessorState retrieved_stream_processor_state; + + + Establish context = () => + { + consumer_tenant_id = Guid.NewGuid(); + producer_microservice_id = Guid.NewGuid(); + producer_tenant_id = tenant; + scope_id = Guid.NewGuid(); + stream_id = Guid.NewGuid(); + partition_id = "partition"; + + subscription_id = new(consumer_tenant_id, + producer_microservice_id, + producer_tenant_id, + scope_id, + stream_id, + partition_id); + + stream_processor_state = new(new ProcessingPosition(10, 15), "", last_successfully_processed, 0, last_successfully_processed, false); + + stream_processor_states.Persist(subscription_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult(); + retrieved_stream_processor_state_response = stream_processor_states.TryGetFor(subscription_id, CancellationToken.None).GetAwaiter().GetResult(); + + retrieved_stream_processor_state = (StreamProcessorState)retrieved_stream_processor_state_response.Result; + }; + + It should_have_retrieved_the_state_successfully = () => retrieved_stream_processor_state_response.Success.Should().BeTrue(); + + + It should_have_the_correct_stream_processor_state_type = () => + retrieved_stream_processor_state_response.Result.Should().BeOfType(); + + It should_have_the_correct_stream_processor_state = () => retrieved_stream_processor_state.Should().BeEquivalentTo(stream_processor_state); + static Try retrieved_stream_processor_state_response; +} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/StreamProcessorStates/SubscriptionId/with_no_events.cs b/Integration/Tests/Events.Processing/StreamProcessorStates/SubscriptionId/with_no_events.cs new file mode 100644 index 000000000..291dbd577 --- /dev/null +++ b/Integration/Tests/Events.Processing/StreamProcessorStates/SubscriptionId/with_no_events.cs @@ -0,0 +1,54 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using Dolittle.Runtime.Domain.Platform; +using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Rudimentary; +using FluentAssertions; +using Machine.Specifications; +using It = Machine.Specifications.It; + +namespace Integration.Tests.Events.Processing.StreamProcessorStates.SubscriptionId; + +class with_no_events : given.a_clean_event_store +{ + static TenantId consumer_tenant_id; + static MicroserviceId producer_microservice_id; + static TenantId producer_tenant_id; + static ScopeId scope_id; + static StreamId stream_id; + static PartitionId partition_id; + + + static Dolittle.Runtime.EventHorizon.Consumer.SubscriptionId subscription_id; + + static Try result; + + Establish context = () => + { + consumer_tenant_id = Guid.NewGuid(); + producer_microservice_id = Guid.NewGuid(); + producer_tenant_id = tenant; + scope_id = Guid.NewGuid(); + stream_id = Guid.NewGuid(); + partition_id = "partition"; + + subscription_id = new(consumer_tenant_id, + producer_microservice_id, + producer_tenant_id, + scope_id, + stream_id, + partition_id); + + result = stream_processor_states.TryGetFor(subscription_id, CancellationToken.None).GetAwaiter().GetResult(); + }; + + + It should_return_a_failure = () => result.Success.Should().BeFalse(); + + It should_return_a_stream_processor_state_not_found_exception = () => result.Exception.Should().BeOfType(); +} \ No newline at end of file diff --git a/Integration/Tests/Events.Processing/given/a_clean_event_store.cs b/Integration/Tests/Events.Processing/given/a_clean_event_store.cs index 73ef80c0f..ece7c72cf 100644 --- a/Integration/Tests/Events.Processing/given/a_clean_event_store.cs +++ b/Integration/Tests/Events.Processing/given/a_clean_event_store.cs @@ -3,9 +3,7 @@ using System; using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Events.Processing.Streams; using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.MongoDB.Aggregates; using Dolittle.Runtime.Events.Store.MongoDB.Events; using Dolittle.Runtime.Events.Store.MongoDB.Streams; using Dolittle.Runtime.Events.Store.Streams; @@ -23,9 +21,9 @@ class a_clean_event_store : a_runtime_with_a_single_tenant protected static IEventContentConverter event_content_converter; protected static IStreams streams; protected static IEventFetchers event_fetchers; - protected static IResilientStreamProcessorStateRepository stream_processor_states; + protected static IStreamProcessorStates stream_processor_states; protected static IStreamDefinitionRepository stream_definition_repository; - + protected static IStreamEventSubscriber stream_event_subscriber; Establish context = () => { @@ -33,7 +31,9 @@ class a_clean_event_store : a_runtime_with_a_single_tenant event_content_converter = runtime.Host.Services.GetRequiredService(); streams = runtime.Host.Services.GetRequiredService>()(execution_context.Tenant); event_fetchers = runtime.Host.Services.GetRequiredService>()(tenant); - stream_processor_states = runtime.Host.Services.GetRequiredService>()(tenant); + stream_processor_states = runtime.Host.Services.GetRequiredService>()(tenant); stream_definition_repository = runtime.Host.Services.GetRequiredService>()(tenant); + stream_event_subscriber = runtime.Host.Services.GetRequiredService>()(tenant); + }; } \ No newline at end of file diff --git a/Integration/Tests/Events.Store.MongoDB/Events.Store.MongoDB.csproj b/Integration/Tests/Events.Store.MongoDB/Events.Store.MongoDB.csproj new file mode 100644 index 000000000..1e122e6fd --- /dev/null +++ b/Integration/Tests/Events.Store.MongoDB/Events.Store.MongoDB.csproj @@ -0,0 +1,14 @@ + + + + + + Integration.Tests.Events.Store.MongoDB + Integration.Tests.Events.Store.MongoDB + + + + + + + diff --git a/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/given/a_stream_processor_id.cs b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/given/a_stream_processor_id.cs new file mode 100644 index 000000000..1abcb4c38 --- /dev/null +++ b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/given/a_stream_processor_id.cs @@ -0,0 +1,21 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing.Streams; +using Machine.Specifications; + +namespace Integration.Tests.Events.Store.MongoDB.for_StreamProcessorStateRepository.for_one_tenant.given; + +public class a_stream_processor_id : MongoDB.given.a_clean_event_store +{ + protected static StreamProcessorId stream_processor_id; + + Establish context = () => + { + stream_processor_id = new StreamProcessorId("b7aa9a19-1f34-42ad-9e65-cd01a0239cb0", "bc15dd0b-1724-4716-9226-f0b722d22206", "b61ed8ba-4e3e-4369-a088-9f60d72777aa"); + }; + + protected static StreamProcessorState an_unpartitioned_state() => StreamProcessorState.New; + protected static Dolittle.Runtime.Events.Processing.Streams.Partitioned.StreamProcessorState a_partitioned_state() => Dolittle.Runtime.Events.Processing.Streams.Partitioned.StreamProcessorState.New; + +} \ No newline at end of file diff --git a/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/given/should_extensions.cs b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/given/should_extensions.cs new file mode 100644 index 000000000..39120454c --- /dev/null +++ b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/given/should_extensions.cs @@ -0,0 +1,54 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Events.Store.Streams; +using FluentAssertions; +using Machine.Specifications; +using Machine.Specifications.Utility; +using StreamProcessorState = Dolittle.Runtime.Events.Processing.Streams.StreamProcessorState; + +namespace Integration.Tests.Events.Store.MongoDB.for_StreamProcessorStateRepository.for_one_tenant.given; + +public static class should_extensions +{ + public static void should_be_the_same_unpartitioned_state_as(this IStreamProcessorState stored_state, IStreamProcessorState expected_state) + { + stored_state.ShouldBeOfExactType(); + + var stored_unpartitioned_state = (StreamProcessorState)stored_state; + var expected_unpartitioned_stated = (StreamProcessorState) expected_state; + + stored_unpartitioned_state.Partitioned.ShouldBeFalse(); + stored_unpartitioned_state.Position.ShouldEqual(expected_unpartitioned_stated.Position); + stored_unpartitioned_state.FailureReason.ShouldEqual(expected_unpartitioned_stated.FailureReason); + stored_unpartitioned_state.IsFailing.ShouldEqual(expected_unpartitioned_stated.IsFailing); + stored_unpartitioned_state.ProcessingAttempts.ShouldEqual(expected_unpartitioned_stated.ProcessingAttempts); + stored_unpartitioned_state.LastSuccessfullyProcessed.Should().BeCloseTo(expected_unpartitioned_stated.LastSuccessfullyProcessed, TimeSpan.FromSeconds(1)); + stored_unpartitioned_state.RetryTime.Should().BeCloseTo(expected_unpartitioned_stated.RetryTime, TimeSpan.FromSeconds(1)); + + } + public static void should_be_the_same_partitioned_state_as(this IStreamProcessorState stored_state, IStreamProcessorState expected_state) + { + stored_state.ShouldBeOfExactType(); + + var stored_unpartitioned_state = (Dolittle.Runtime.Events.Processing.Streams.Partitioned.StreamProcessorState)stored_state; + var expected_unpartitioned_stated = (Dolittle.Runtime.Events.Processing.Streams.Partitioned.StreamProcessorState) expected_state; + + stored_unpartitioned_state.Partitioned.ShouldBeTrue(); + stored_unpartitioned_state.Position.ShouldEqual(expected_unpartitioned_stated.Position); + stored_unpartitioned_state.LastSuccessfullyProcessed.Should().BeCloseTo(expected_unpartitioned_stated.LastSuccessfullyProcessed, TimeSpan.FromSeconds(1)); + stored_unpartitioned_state.FailingPartitions.Keys.ShouldContainOnly(expected_unpartitioned_stated.FailingPartitions.Keys); + stored_unpartitioned_state.FailingPartitions.Each(stored => stored.Value.should_be_the_same_failing_partition_as(expected_unpartitioned_stated.FailingPartitions[stored.Key])); + } + + public static void should_be_the_same_failing_partition_as(this FailingPartitionState stored, FailingPartitionState expected) + { + stored.Reason.ShouldEqual(expected.Reason); + stored.ProcessingAttempts.ShouldEqual(expected.ProcessingAttempts); + stored.RetryTime.Should().BeCloseTo(expected.RetryTime, TimeSpan.FromSeconds(1)); + stored.LastFailed.Should().BeCloseTo(expected.LastFailed, TimeSpan.FromSeconds(1)); + stored.Position.ShouldEqual(expected.Position); + } +} \ No newline at end of file diff --git a/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/given/all_dependencies.cs b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/given/all_dependencies.cs new file mode 100644 index 000000000..cc1778ce1 --- /dev/null +++ b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/given/all_dependencies.cs @@ -0,0 +1,21 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Rudimentary; + +namespace Integration.Tests.Events.Store.MongoDB.for_StreamProcessorStateRepository.for_one_tenant.when_getting.one.given; + +public class all_dependencies : for_one_tenant.given.a_stream_processor_id +{ + protected static Try retrieved_state; + protected static IStreamProcessorState stored_state; + + protected static void get_stream_processor_state() + { + retrieved_state = stream_processor_state_repository.TryGet(stream_processor_id, CancellationToken.None).GetAwaiter().GetResult(); + } + + +} \ No newline at end of file diff --git a/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/partitioned/and_the_state_is_not_persisted.cs b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/partitioned/and_the_state_is_not_persisted.cs new file mode 100644 index 000000000..f3924201e --- /dev/null +++ b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/partitioned/and_the_state_is_not_persisted.cs @@ -0,0 +1,37 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Threading; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store.Streams; +using Machine.Specifications; + +namespace Integration.Tests.Events.Store.MongoDB.for_StreamProcessorStateRepository.for_one_tenant.when_getting.one.scoped.partitioned; + +public class and_the_state_is_not_persisted : given.all_dependencies +{ + static protected (StreamProcessorId id, IStreamProcessorState state) another_stored_processor; + + Establish context = () => + { + stream_processor_id = stream_processor_id with + { + ScopeId = "c424eedc-dc60-4c34-9860-536e206fa9e8" + }; + another_stored_processor = (stream_processor_id with + { + EventProcessorId = "9ec32ae1-ed08-4781-8fc2-96ac7017aedd" + }, a_partitioned_state()); + + var to_store = new Dictionary(); + to_store.Add(another_stored_processor.id, another_stored_processor.state); + + stream_processor_state_repository.PersistForScope(another_stored_processor.id.ScopeId, to_store, CancellationToken.None).GetAwaiter().GetResult(); + }; + + Because of = get_stream_processor_state; + + It should_not_get_the_state = () => retrieved_state.Success.ShouldBeFalse(); + It should_fail_because_state_does_not_exist = () => retrieved_state.Exception.ShouldBeOfExactType(); +} \ No newline at end of file diff --git a/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/partitioned/and_the_state_is_persisted.cs b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/partitioned/and_the_state_is_persisted.cs new file mode 100644 index 000000000..7bf6ebbb7 --- /dev/null +++ b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/partitioned/and_the_state_is_persisted.cs @@ -0,0 +1,57 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Events.Store.Streams; +using Integration.Tests.Events.Store.MongoDB.for_StreamProcessorStateRepository.for_one_tenant.given; +using Machine.Specifications; + +namespace Integration.Tests.Events.Store.MongoDB.for_StreamProcessorStateRepository.for_one_tenant.when_getting.one.scoped.partitioned; + +public class and_the_state_is_persisted : given.all_dependencies +{ + static (StreamProcessorId id, IStreamProcessorState state) another_stored_processor; + + Establish context = () => + { + stream_processor_id = stream_processor_id with + { + ScopeId = "c424eedc-dc60-4c34-9860-536e206fa9e8" + }; + + var failing_partitions = new Dictionary(); + failing_partitions.Add("d2b8f91d-e838-4b34-b0a3-0468dc29ca0e", + new FailingPartitionState(2, 5, DateTimeOffset.UtcNow, "Some reason", 2, DateTimeOffset.UtcNow)); + + stored_state = a_partitioned_state() with + { + Position = new ProcessingPosition(2, 5), + FailingPartitions = failing_partitions.ToImmutableDictionary() + }; + another_stored_processor = (stream_processor_id with + { + EventProcessorId = "9ec32ae1-ed08-4781-8fc2-96ac7017aedd" + }, a_partitioned_state()); + + var to_store = new Dictionary(); + to_store.Add(stream_processor_id, stored_state); + to_store.Add(another_stored_processor.id, another_stored_processor.state); + + stream_processor_state_repository.PersistForScope(another_stored_processor.id.ScopeId, to_store, CancellationToken.None).GetAwaiter().GetResult(); + }; + + Because of = get_stream_processor_state; + + It should_get_the_state = () => retrieved_state.Success.ShouldBeTrue(); + It should_get_unpartitioned_state = () => retrieved_state.Result.Partitioned.ShouldBeTrue(); + + It should_get_unpartitioned_state_type = () => + retrieved_state.Result.ShouldBeOfExactType(); + + It should_get_the_correct_state = () => retrieved_state.Result.should_be_the_same_partitioned_state_as(stored_state); +} \ No newline at end of file diff --git a/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/partitioned/and_there_are_no_states.cs b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/partitioned/and_there_are_no_states.cs new file mode 100644 index 000000000..392e53812 --- /dev/null +++ b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/partitioned/and_there_are_no_states.cs @@ -0,0 +1,23 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Store.Streams; +using Machine.Specifications; + +namespace Integration.Tests.Events.Store.MongoDB.for_StreamProcessorStateRepository.for_one_tenant.when_getting.one.scoped.partitioned; + +public class and_there_are_no_states : given.all_dependencies +{ + Establish context = () => + { + stream_processor_id = stream_processor_id with + { + ScopeId = "c156f336-8e2d-496b-8324-0268bda3e339" + }; + }; + + Because of = get_stream_processor_state; + + It should_not_get_the_state = () => retrieved_state.Success.ShouldBeFalse(); + It should_fail_because_state_does_not_exist = () => retrieved_state.Exception.ShouldBeOfExactType(); +} \ No newline at end of file diff --git a/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/unpartitioned/and_the_state_is_not_persisted.cs b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/unpartitioned/and_the_state_is_not_persisted.cs new file mode 100644 index 000000000..5c638624c --- /dev/null +++ b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/unpartitioned/and_the_state_is_not_persisted.cs @@ -0,0 +1,37 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Threading; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store.Streams; +using Machine.Specifications; + +namespace Integration.Tests.Events.Store.MongoDB.for_StreamProcessorStateRepository.for_one_tenant.when_getting.one.scoped.unpartitioned; + +public class and_the_state_is_not_persisted : given.all_dependencies +{ + static protected (StreamProcessorId id, IStreamProcessorState state) another_stored_processor; + + Establish context = () => + { + stream_processor_id = stream_processor_id with + { + ScopeId = "c424eedc-dc60-4c34-9860-536e206fa9e8" + }; + another_stored_processor = (stream_processor_id with + { + EventProcessorId = "9ec32ae1-ed08-4781-8fc2-96ac7017aedd" + }, an_unpartitioned_state()); + + var to_store = new Dictionary(); + to_store.Add(another_stored_processor.id, another_stored_processor.state); + + stream_processor_state_repository.PersistForScope(another_stored_processor.id.ScopeId, to_store, CancellationToken.None).GetAwaiter().GetResult(); + }; + + Because of = get_stream_processor_state; + + It should_not_get_the_state = () => retrieved_state.Success.ShouldBeFalse(); + It should_fail_because_state_does_not_exist = () => retrieved_state.Exception.ShouldBeOfExactType(); +} \ No newline at end of file diff --git a/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/unpartitioned/and_the_state_is_persisted.cs b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/unpartitioned/and_the_state_is_persisted.cs new file mode 100644 index 000000000..b3f9c0f9d --- /dev/null +++ b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/unpartitioned/and_the_state_is_persisted.cs @@ -0,0 +1,45 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Threading; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store.Streams; +using Integration.Tests.Events.Store.MongoDB.for_StreamProcessorStateRepository.for_one_tenant.given; +using Machine.Specifications; + +namespace Integration.Tests.Events.Store.MongoDB.for_StreamProcessorStateRepository.for_one_tenant.when_getting.one.scoped.unpartitioned; + +public class and_the_state_is_persisted : given.all_dependencies +{ + static (StreamProcessorId id, IStreamProcessorState state) another_stored_processor; + + Establish context = () => + { + stream_processor_id = stream_processor_id with + { + ScopeId = "c424eedc-dc60-4c34-9860-536e206fa9e8" + }; + stored_state = an_unpartitioned_state() with + { + Position = new ProcessingPosition(2, 2) + }; + another_stored_processor = (stream_processor_id with + { + EventProcessorId = "9ec32ae1-ed08-4781-8fc2-96ac7017aedd" + }, an_unpartitioned_state()); + + var to_store = new Dictionary(); + to_store.Add(stream_processor_id, stored_state); + to_store.Add(another_stored_processor.id, another_stored_processor.state); + + stream_processor_state_repository.PersistForScope(another_stored_processor.id.ScopeId, to_store, CancellationToken.None).GetAwaiter().GetResult(); + }; + + Because of = get_stream_processor_state; + + It should_get_the_state = () => retrieved_state.Success.ShouldBeTrue(); + It should_get_unpartitioned_state = () => retrieved_state.Result.Partitioned.ShouldBeFalse(); + It should_get_unpartitioned_state_type = () => retrieved_state.Result.ShouldBeOfExactType(); + It should_get_the_correct_state = () => retrieved_state.Result.should_be_the_same_unpartitioned_state_as(stored_state); +} \ No newline at end of file diff --git a/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/unpartitioned/and_there_are_no_states.cs b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/unpartitioned/and_there_are_no_states.cs new file mode 100644 index 000000000..e9114649a --- /dev/null +++ b/Integration/Tests/Events.Store.MongoDB/for_StreamProcessorStateRepository/for_one_tenant/when_getting/one/scoped/unpartitioned/and_there_are_no_states.cs @@ -0,0 +1,23 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Store.Streams; +using Machine.Specifications; + +namespace Integration.Tests.Events.Store.MongoDB.for_StreamProcessorStateRepository.for_one_tenant.when_getting.one.scoped.unpartitioned; + +public class and_there_are_no_states : given.all_dependencies +{ + Establish context = () => + { + stream_processor_id = stream_processor_id with + { + ScopeId = "c156f336-8e2d-496b-8324-0268bda3e339" + }; + }; + + Because of = get_stream_processor_state; + + It should_not_get_the_state = () => retrieved_state.Success.ShouldBeFalse(); + It should_fail_because_state_does_not_exist = () => retrieved_state.Exception.ShouldBeOfExactType(); +} \ No newline at end of file diff --git a/Integration/Tests/Events.Store.MongoDB/given/a_clean_event_store.cs b/Integration/Tests/Events.Store.MongoDB/given/a_clean_event_store.cs new file mode 100644 index 000000000..89d514298 --- /dev/null +++ b/Integration/Tests/Events.Store.MongoDB/given/a_clean_event_store.cs @@ -0,0 +1,21 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Store; +using Machine.Specifications; +using Microsoft.Extensions.DependencyInjection; + +namespace Integration.Tests.Events.Store.MongoDB.given; + +public class a_clean_event_store : a_runtime_with_a_single_tenant +{ + protected static IStreamProcessorStateRepository stream_processor_state_repository; + + + Establish context = () => + { + stream_processor_state_repository = runtime.Host.Services.GetRequiredService>()(execution_context.Tenant); + }; +} \ No newline at end of file diff --git a/Integration/Tests/Events.Store.MongoDB/given/a_runtime_with_a_multiple_tenant.cs b/Integration/Tests/Events.Store.MongoDB/given/a_runtime_with_a_multiple_tenant.cs new file mode 100644 index 000000000..bca51b3a6 --- /dev/null +++ b/Integration/Tests/Events.Store.MongoDB/given/a_runtime_with_a_multiple_tenant.cs @@ -0,0 +1,31 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Linq; +using Dolittle.Runtime.Domain.Tenancy; +using Integration.Shared; +using Machine.Specifications; +using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; + +namespace Integration.Tests.Events.Store.MongoDB.given; + +public class a_runtime_with_a_multiple_tenant +{ + protected static RunningRuntime runtime; + protected static Dictionary execution_contexts; + protected static TenantId[] tenants; + + Establish context = () => + { + runtime = Runtime.CreateAndStart(2); + tenants = runtime.ConfiguredTenants.ToArray(); + execution_contexts = tenants.ToDictionary(tenant => tenant, Runtime.CreateExecutionContextFor); + }; + + Cleanup after = () => + { + Runtime.CleanAll(runtime).GetAwaiter().GetResult(); + }; + +} \ No newline at end of file diff --git a/Integration/Tests/Events.Store.MongoDB/given/a_runtime_with_a_single_tenant.cs b/Integration/Tests/Events.Store.MongoDB/given/a_runtime_with_a_single_tenant.cs new file mode 100644 index 000000000..d8a78be44 --- /dev/null +++ b/Integration/Tests/Events.Store.MongoDB/given/a_runtime_with_a_single_tenant.cs @@ -0,0 +1,30 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Linq; +using Dolittle.Runtime.Domain.Tenancy; +using Integration.Shared; +using Machine.Specifications; +using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; + +namespace Integration.Tests.Events.Store.MongoDB.given; + +[Tags("IntegrationTest")] +public class a_runtime_with_a_single_tenant +{ + protected static RunningRuntime runtime; + protected static ExecutionContext execution_context; + protected static TenantId tenant; + + Establish context = () => + { + runtime = Runtime.CreateAndStart(1); + tenant = runtime.ConfiguredTenants.First(); + execution_context = Runtime.CreateExecutionContextFor(tenant); + }; + + Cleanup mess = () => + { + Runtime.CleanAll(runtime).GetAwaiter().GetResult(); + }; +} \ No newline at end of file diff --git a/Integration/Tests/Events.Store.MongoDB/given/event_content_serializer.cs b/Integration/Tests/Events.Store.MongoDB/given/event_content_serializer.cs new file mode 100644 index 000000000..3432bfef3 --- /dev/null +++ b/Integration/Tests/Events.Store.MongoDB/given/event_content_serializer.cs @@ -0,0 +1,15 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using MongoDB.Bson.IO; + +namespace Integration.Tests.Events.Store.MongoDB.given; + +static class event_content_serializer +{ + public static readonly JsonWriterSettings json_settings = new() + { + OutputMode = JsonOutputMode.Strict, + Indent = false, + }; +} \ No newline at end of file diff --git a/Integration/Tests/Events.Store.MongoDB/given/event_to_commit.cs b/Integration/Tests/Events.Store.MongoDB/given/event_to_commit.cs new file mode 100644 index 000000000..b572b60ae --- /dev/null +++ b/Integration/Tests/Events.Store.MongoDB/given/event_to_commit.cs @@ -0,0 +1,59 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Dolittle.Runtime.Artifacts; +using Dolittle.Runtime.Events; +using Dolittle.Runtime.Events.Store; +using Newtonsoft.Json; + +namespace Integration.Tests.Events.Store.MongoDB.given; + +public static class event_to_commit +{ + + public static UncommittedEvent create() => with_content(new {Hello = 42}).build(); + public static UncommittedEvent create_with_type(ArtifactId event_type) => with_content(new {Hello = 42}).with_event_type(event_type).build(); + + public static event_builder with_content(object content) => new(content); + + public static event_builder with_large_content(int content_length) + { + var long_string = new string('a', Math.Max(0, content_length-8)); + var content_with_long_string = new {a = long_string}; + return new event_builder(content_with_long_string); + } + + public class event_builder + { + EventSourceId event_source_id = "some event source"; + Artifact event_type = new("a52f686f-c045-4c7a-9a5b-91ee4b107237", ArtifactGeneration.First); + bool is_public; + readonly string content; + + public event_builder(object content) + { + this.content = JsonConvert.SerializeObject(content, Formatting.None); + } + + public event_builder public_event() + { + is_public = true; + return this; + } + + public event_builder with_event_type(ArtifactId artifact) + { + event_type = event_type with {Id = artifact}; + return this; + } + + public event_builder with_event_source(EventSourceId event_source) + { + event_source_id = event_source; + return this; + } + + public UncommittedEvent build() => new(event_source_id, event_type, is_public, content); + } +} \ No newline at end of file diff --git a/Integration/Tests/Events.Store.Services.Grpc/Events.Store.Services.Grpc.csproj b/Integration/Tests/Events.Store.Services.Grpc/Events.Store.Services.Grpc.csproj index 79f1b3a8e..bdc250368 100644 --- a/Integration/Tests/Events.Store.Services.Grpc/Events.Store.Services.Grpc.csproj +++ b/Integration/Tests/Events.Store.Services.Grpc/Events.Store.Services.Grpc.csproj @@ -8,8 +8,8 @@ - - + + \ No newline at end of file diff --git a/Integration/Tests/Events.Store.Services.Grpc/given/a_clean_event_store_and_grpc_service.cs b/Integration/Tests/Events.Store.Services.Grpc/given/a_clean_event_store_and_grpc_service.cs index 81be1acb4..4406afab2 100644 --- a/Integration/Tests/Events.Store.Services.Grpc/given/a_clean_event_store_and_grpc_service.cs +++ b/Integration/Tests/Events.Store.Services.Grpc/given/a_clean_event_store_and_grpc_service.cs @@ -4,11 +4,8 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Dolittle.Runtime.Artifacts; using Dolittle.Runtime.Events.Contracts; -using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Services.Grpc; -using Dolittle.Runtime.Execution; using Grpc.Core; using Machine.Specifications; using Microsoft.Extensions.DependencyInjection; diff --git a/Integration/Tests/Events.Store/Events.Store.csproj b/Integration/Tests/Events.Store/Events.Store.csproj index d47a81bf8..6820579ed 100644 --- a/Integration/Tests/Events.Store/Events.Store.csproj +++ b/Integration/Tests/Events.Store/Events.Store.csproj @@ -8,7 +8,7 @@ - + diff --git a/Integration/Tests/Events.Store/when_committing/multiple_events_in/batch.cs b/Integration/Tests/Events.Store/when_committing/multiple_events_in/batch.cs index 19efc71f4..ad88a80fd 100644 --- a/Integration/Tests/Events.Store/when_committing/multiple_events_in/batch.cs +++ b/Integration/Tests/Events.Store/when_committing/multiple_events_in/batch.cs @@ -57,7 +57,7 @@ class not_for_aggregate { var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); response_before_subscribe = event_store.Commit(uncommitted_events, execution_context).GetAwaiter().GetResult(); - var subscribedEvents = event_log_stream.SubscribeAll(ScopeId.Default, 0, cts.Token).ReadAllAsync().ToListAsync(); + var subscribedEvents = event_log_stream.SubscribeAll(ScopeId.Default, 0, "batchtest",cts.Token).ReadAllAsync().ToListAsync(); response_after_subscribe = event_store.Commit(uncommitted_events_after_subscribe, execution_context).GetAwaiter().GetResult(); all_committed_events = response_before_subscribe.Events.Concat(response_after_subscribe.Events).ToList(); all_subscription_batch_results = subscribedEvents.GetAwaiter().GetResult(); diff --git a/Integration/Tests/Events.Store/when_committing/multiple_events_in/loop.cs b/Integration/Tests/Events.Store/when_committing/multiple_events_in/loop.cs index 81ff9bba6..1445ef16e 100644 --- a/Integration/Tests/Events.Store/when_committing/multiple_events_in/loop.cs +++ b/Integration/Tests/Events.Store/when_committing/multiple_events_in/loop.cs @@ -73,7 +73,7 @@ class not_for_aggregate It should_have_subscribable_events = () => { using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); - var reader = event_log_stream.SubscribeAll(ScopeId.Default, 0, cts.Token); + var reader = event_log_stream.SubscribeAll(ScopeId.Default, 0,"looptest", cts.Token); var hasData = reader.WaitToReadAsync().AsTask().GetAwaiter().GetResult(); hasData.ShouldBeTrue(); // Should get a single batch diff --git a/Integration/Tests/Events.Store/when_writing_to_stream/that_is_not_scoped/when_writing_to_stream.cs b/Integration/Tests/Events.Store/when_writing_to_stream/that_is_not_scoped/when_writing_to_stream.cs index 91003158d..c7155d3f0 100644 --- a/Integration/Tests/Events.Store/when_writing_to_stream/that_is_not_scoped/when_writing_to_stream.cs +++ b/Integration/Tests/Events.Store/when_writing_to_stream/that_is_not_scoped/when_writing_to_stream.cs @@ -8,9 +8,7 @@ using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; -using Microsoft.Extensions.DependencyInjection; using MongoDB.Driver; -using CommittedEvent = Dolittle.Runtime.Events.Store.CommittedEvent; using UncommittedEvent = Dolittle.Runtime.Events.Store.UncommittedEvent; using StreamEvent = Dolittle.Runtime.Events.Store.MongoDB.Events.StreamEvent; diff --git a/Integration/Tests/Events.Store/when_writing_to_stream/that_is_scoped/when_writing_to_stream.cs b/Integration/Tests/Events.Store/when_writing_to_stream/that_is_scoped/when_writing_to_stream.cs index d5ffd16b2..1373ddf46 100644 --- a/Integration/Tests/Events.Store/when_writing_to_stream/that_is_scoped/when_writing_to_stream.cs +++ b/Integration/Tests/Events.Store/when_writing_to_stream/that_is_scoped/when_writing_to_stream.cs @@ -5,13 +5,10 @@ using System.Collections.Generic; using System.Linq; using System.Threading; -using Dolittle.Runtime.Events.Contracts; using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; -using Microsoft.Extensions.DependencyInjection; using MongoDB.Driver; -using CommittedEvent = Dolittle.Runtime.Events.Store.CommittedEvent; using StreamEvent = Dolittle.Runtime.Events.Store.MongoDB.Events.StreamEvent; using UncommittedEvent = Dolittle.Runtime.Events.Store.UncommittedEvent; diff --git a/Integration/Tests/Services/Protobuf/ReverseCallBasicProtocol.proto b/Integration/Tests/Services/Protobuf/ReverseCallBasicProtocol.proto new file mode 100644 index 000000000..098381426 --- /dev/null +++ b/Integration/Tests/Services/Protobuf/ReverseCallBasicProtocol.proto @@ -0,0 +1,45 @@ +syntax = "proto3"; + +package dolittle.runtime; + +option csharp_namespace = "Integration.Tests.Services"; + +import "Services/ReverseCallContext.proto"; +import "Services/Ping.proto"; + +message RegistrationRequest { + services.ReverseCallArgumentsContext callContext = 1; + bool isValid = 2; +} + +message Response { + services.ReverseCallResponseContext callContext = 1; +} + +message ClientToRuntimeMessage { + oneof Message { + RegistrationRequest registrationRequest = 1; + Response response = 2; + services.Pong pong = 3; + } +} + +message RegistrationResponse { + bool failed = 1; +} + +message Request { + services.ReverseCallRequestContext callContext = 1; +} + +message RuntimeToClientMessage { + oneof Message { + RegistrationResponse registrationResponse = 1; + Request handleRequest = 2; + services.Ping ping = 3; + } +} + +service BasicReverseCallService { + rpc Connect (stream ClientToRuntimeMessage) returns (stream RuntimeToClientMessage); +} diff --git a/Integration/Tests/Services/ReverseCalls/given/all_dependencies_and_single_tenant.cs b/Integration/Tests/Services/ReverseCalls/given/all_dependencies_and_single_tenant.cs new file mode 100644 index 000000000..086899728 --- /dev/null +++ b/Integration/Tests/Services/ReverseCalls/given/all_dependencies_and_single_tenant.cs @@ -0,0 +1,65 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading.Tasks; +using Dolittle.Runtime.Rudimentary; +using Dolittle.Runtime.Services; +using Dolittle.Runtime.Services.Clients; +using Dolittle.Runtime.Services.Hosting; +using Grpc.Core; +using Integration.Tests.Services.given; +using Machine.Specifications; + +namespace Integration.Tests.Services.ReverseCalls.given; + +class all_dependencies_and_single_tenant : Services.given.all_dependencies_and_single_tenant +{ + internal static Func, IServerStreamWriter, ServerCallContext, Task> on_service_connect; + internal static TaskCompletionSource connect_completion_source; + protected static Try<(IReverseCallDispatcher, RegistrationArguments)> connect_result; + protected static IReverseCallClient reverse_call_client; + + Establish context = () => + { + connect_completion_source = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + reverse_call_client = null; + on_service_connect = null; + connect_result = null; + }; + + protected static void setup(Func, IServerStreamWriter, ServerCallContext, Task> on_service_connect, TimeSpan ping_interval) + { + all_dependencies_and_single_tenant.on_service_connect = on_service_connect; + reverse_call_client = reverse_call_clients.GetFor( + new basic_with_ping_pong_reverse_call_client_protocol(), + "localhost", + endpoints.Private.Port, + ping_interval); + + } + + Cleanup cleanup = () => reverse_call_client.Dispose(); +} + +[PrivateService] +public class service : BasicReverseCallService.BasicReverseCallServiceBase +{ + public override async Task Connect(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) + { + try + { + var waitForCancel = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + await using var registration = context.CancellationToken.Register(() => waitForCancel.TrySetResult()).ConfigureAwait(false); + await all_dependencies_and_single_tenant.on_service_connect(requestStream, responseStream, context).ConfigureAwait(false); + await waitForCancel.Task.ConfigureAwait(false); + + all_dependencies_and_single_tenant.connect_completion_source.SetResult(); + } + catch (Exception e) + { + all_dependencies_and_single_tenant.connect_completion_source.SetException(e); + throw; + } + } +} diff --git a/Integration/Tests/Services/ReverseCalls/when_initiating/and_everything_is_ok.cs b/Integration/Tests/Services/ReverseCalls/when_initiating/and_everything_is_ok.cs new file mode 100644 index 000000000..50fa170d2 --- /dev/null +++ b/Integration/Tests/Services/ReverseCalls/when_initiating/and_everything_is_ok.cs @@ -0,0 +1,34 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using Integration.Tests.Services.given; +using Machine.Specifications; + +namespace Integration.Tests.Services.ReverseCalls.when_initiating; + +[Tags("IntegrationTest")] +class and_everything_is_ok : given.all_dependencies_and_single_tenant +{ + Establish context = () => + { + setup( + async (reader, writer, context) => connect_result = await reverse_call_initiator.Connect(reader, writer, context, new basic_with_ping_pong_reverse_call_service_protocol(), context.CancellationToken), + TimeSpan.FromSeconds(5)); + }; + + Because of = () => + { + reverse_call_client.Connect(new RegistrationRequest + { + IsValid = true + }, execution_context, new CancellationTokenSource(500).Token).GetAwaiter().GetResult(); + given.all_dependencies_and_single_tenant.connect_completion_source.Task.GetAwaiter().GetResult(); + }; + + It should_not_fail = () => connect_result.Success.ShouldBeTrue(); + It should_return_the_non_failed_arguments = () => connect_result.Result.Item2.Valid.ShouldBeTrue(); + It should_return_a_dispatcher = () => connect_result.Result.Item1.ShouldNotBeNull(); + It should_return_dispatcher_with_the_correct_execution_context = () => connect_result.Result.Item1.ExecutionContext.ShouldEqual(execution_context); +} \ No newline at end of file diff --git a/Integration/Tests/Services/Services.csproj b/Integration/Tests/Services/Services.csproj new file mode 100644 index 000000000..3aee00da3 --- /dev/null +++ b/Integration/Tests/Services/Services.csproj @@ -0,0 +1,26 @@ + + + + + + Integration.Tests.Services + Integration.Tests.Services + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/Integration/Tests/Services/given/a_runtime_with_2_tenants.cs b/Integration/Tests/Services/given/a_runtime_with_2_tenants.cs new file mode 100644 index 000000000..b27ad5021 --- /dev/null +++ b/Integration/Tests/Services/given/a_runtime_with_2_tenants.cs @@ -0,0 +1,30 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Linq; +using Dolittle.Runtime.Domain.Tenancy; +using Integration.Shared; +using Machine.Specifications; +using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; + +namespace Integration.Tests.Services.given; + +class a_runtime_with_2_tenants +{ + protected static RunningRuntime runtime; + protected static Dictionary execution_contexts; + protected static TenantId[] tenants; + + Establish context = () => + { + runtime = Runtime.CreateAndStart(2); + tenants = runtime.ConfiguredTenants.ToArray(); + execution_contexts = tenants.ToDictionary(tenant => tenant, Runtime.CreateExecutionContextFor); + }; + + Cleanup after = () => + { + Runtime.CleanAll(runtime).GetAwaiter().GetResult(); + }; +} \ No newline at end of file diff --git a/Integration/Tests/Services/given/a_runtime_with_a_single_tenant.cs b/Integration/Tests/Services/given/a_runtime_with_a_single_tenant.cs new file mode 100644 index 000000000..e778fd538 --- /dev/null +++ b/Integration/Tests/Services/given/a_runtime_with_a_single_tenant.cs @@ -0,0 +1,29 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Linq; +using Dolittle.Runtime.Domain.Tenancy; +using Integration.Shared; +using Machine.Specifications; +using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; + +namespace Integration.Tests.Services.given; + +class a_runtime_with_a_single_tenant +{ + protected static RunningRuntime runtime; + protected static ExecutionContext execution_context; + protected static TenantId tenant; + + Establish context = () => + { + runtime = Runtime.CreateAndStart(1); + tenant = runtime.ConfiguredTenants.First(); + execution_context = Runtime.CreateExecutionContextFor(tenant); + }; + + Cleanup mess = () => + { + Runtime.CleanAll(runtime).GetAwaiter().GetResult(); + }; +} \ No newline at end of file diff --git a/Integration/Tests/Services/given/all_dependencies_and_single_tenant.cs b/Integration/Tests/Services/given/all_dependencies_and_single_tenant.cs new file mode 100644 index 000000000..f34003ead --- /dev/null +++ b/Integration/Tests/Services/given/all_dependencies_and_single_tenant.cs @@ -0,0 +1,25 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Services; +using Dolittle.Runtime.Services.Clients; +using Dolittle.Runtime.Services.Configuration; +using Machine.Specifications; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace Integration.Tests.Services.given; + +class all_dependencies_and_single_tenant : a_runtime_with_a_single_tenant +{ + protected static IInitiateReverseCallServices reverse_call_initiator; + protected static IReverseCallClients reverse_call_clients; + protected static EndpointsConfiguration endpoints; + + Establish context = () => + { + reverse_call_initiator = runtime.Host.Services.GetRequiredService(); + reverse_call_clients = runtime.Host.Services.GetRequiredService(); + endpoints = runtime.Host.Services.GetRequiredService>().Value; + }; +} \ No newline at end of file diff --git a/Integration/Tests/Services/given/basic_with_ping_pong_reverse_call_client_protocol.cs b/Integration/Tests/Services/given/basic_with_ping_pong_reverse_call_client_protocol.cs new file mode 100644 index 000000000..35c8fa02c --- /dev/null +++ b/Integration/Tests/Services/given/basic_with_ping_pong_reverse_call_client_protocol.cs @@ -0,0 +1,62 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Dolittle.Runtime.Protobuf; +using Dolittle.Runtime.Services.Clients; +using Dolittle.Services.Contracts; +using Grpc.Core; +using Failure = Dolittle.Protobuf.Contracts.Failure; + +namespace Integration.Tests.Services.given; + +class basic_with_ping_pong_reverse_call_client_protocol : IReverseCallClientProtocol +{ + public AsyncDuplexStreamingCall Call(BasicReverseCallService.BasicReverseCallServiceClient client, CallOptions callOptions) + => client.Connect(callOptions); + + public void SetConnectArgumentsContext(ReverseCallArgumentsContext context, RegistrationRequest arguments) + { + arguments.CallContext = context; + } + + public void SetConnectArguments(RegistrationRequest arguments, ClientToRuntimeMessage message) + { + message.RegistrationRequest = arguments; + } + + public RegistrationResponse GetConnectResponse(RuntimeToClientMessage message) + => message.RegistrationResponse; + + public Failure GetFailureFromConnectResponse(RegistrationResponse response) + => response.Failed ? new Failure + { + Id = Guid.NewGuid().ToProtobuf(), + Reason = "Not valid" + } + : null; + + public Ping GetPing(RuntimeToClientMessage message) + => message.Ping; + + public void SetPong(Pong pong, ClientToRuntimeMessage message) + { + message.Pong = pong; + } + + public Request GetRequest(RuntimeToClientMessage message) + => message.HandleRequest; + + public ReverseCallRequestContext GetRequestContext(Request message) + => message.CallContext; + + public void SetResponseContext(ReverseCallResponseContext context, Response response) + { + response.CallContext = context; + } + + public void SetResponse(Response response, ClientToRuntimeMessage message) + { + message.Response = response; + } +} \ No newline at end of file diff --git a/Integration/Tests/Services/given/basic_with_ping_pong_reverse_call_service_protocol.cs b/Integration/Tests/Services/given/basic_with_ping_pong_reverse_call_service_protocol.cs new file mode 100644 index 000000000..1e9de5c91 --- /dev/null +++ b/Integration/Tests/Services/given/basic_with_ping_pong_reverse_call_service_protocol.cs @@ -0,0 +1,57 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Protobuf; +using Dolittle.Runtime.Services; +using Dolittle.Services.Contracts; + +namespace Integration.Tests.Services.given; + +record RegistrationArguments(bool Valid); + +class basic_with_ping_pong_reverse_call_service_protocol : IReverseCallServiceProtocol +{ + public RegistrationRequest GetConnectArguments(ClientToRuntimeMessage message) + => message.RegistrationRequest; + + public void SetConnectResponse(RegistrationResponse arguments, RuntimeToClientMessage message) + { + message.RegistrationResponse = arguments; + } + + public void SetRequest(Request request, RuntimeToClientMessage message) + { + message.HandleRequest = request; + } + + public Response GetResponse(ClientToRuntimeMessage message) + => message.Response; + + public ReverseCallArgumentsContext GetArgumentsContext(RegistrationRequest message) + => message.CallContext; + + public void SetRequestContext(ReverseCallRequestContext context, Request request) + { + request.CallContext = context; + } + + public ReverseCallResponseContext GetResponseContext(Response message) + => message.CallContext; + + public void SetPing(RuntimeToClientMessage message, Ping ping) + { + message.Ping = ping; + } + + public Pong GetPong(ClientToRuntimeMessage message) + => message.Pong; + + public RegistrationResponse CreateFailedConnectResponse(FailureReason failureMessage) + => new(){Failed = true}; + + public RegistrationArguments ConvertConnectArguments(RegistrationRequest arguments) + => new(arguments.IsValid); + + public ConnectArgumentsValidationResult ValidateConnectArguments(RegistrationArguments arguments) + => arguments.Valid ? ConnectArgumentsValidationResult.Ok : ConnectArgumentsValidationResult.Failed("Not valid"); +} \ No newline at end of file diff --git a/Integration/Tests/Services/given/event_content_serializer.cs b/Integration/Tests/Services/given/event_content_serializer.cs new file mode 100644 index 000000000..a3800ee27 --- /dev/null +++ b/Integration/Tests/Services/given/event_content_serializer.cs @@ -0,0 +1,15 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using MongoDB.Bson.IO; + +namespace Integration.Tests.Services.given; + +static class event_content_serializer +{ + public static readonly JsonWriterSettings json_settings = new() + { + OutputMode = JsonOutputMode.Strict, + Indent = false, + }; +} \ No newline at end of file diff --git a/Integration/Tests/Services/given/event_to_commit.cs b/Integration/Tests/Services/given/event_to_commit.cs new file mode 100644 index 000000000..2975692fe --- /dev/null +++ b/Integration/Tests/Services/given/event_to_commit.cs @@ -0,0 +1,49 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Artifacts; +using Dolittle.Runtime.Events; +using Dolittle.Runtime.Events.Store; +using Newtonsoft.Json; + +namespace Integration.Tests.Services.given; + +static class event_to_commit +{ + public static UncommittedEvent create() => with_content(new {Hello = 42}).build(); + + public static event_builder with_content(object content) => new(content); + + public class event_builder + { + EventSourceId event_source_id = "some event source"; + Artifact artifact = new("a52f686f-c045-4c7a-9a5b-91ee4b107237", ArtifactGeneration.First); + bool is_public; + readonly string content; + + public event_builder(object content) + { + this.content = JsonConvert.SerializeObject(content, Formatting.None); + } + + public event_builder public_event() + { + is_public = true; + return this; + } + + public event_builder with_artifact(ArtifactId artifact_id) + { + artifact = new Artifact(artifact_id, ArtifactGeneration.First); + return this; + } + + public event_builder with_event_source(EventSourceId event_source) + { + event_source_id = event_source; + return this; + } + + public UncommittedEvent build() => new UncommittedEvent(event_source_id, artifact, is_public, content); + } +} \ No newline at end of file diff --git a/README.md b/README.md index 83d73b85e..477a050e1 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,6 @@ Latest Docker image Build status CodeQL status - - -

diff --git a/Runtime.sln b/Runtime.sln index 44a3004ed..11eea8b5e 100644 --- a/Runtime.sln +++ b/Runtime.sln @@ -9,24 +9,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artifacts", "Source\Artifac EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DependencyInversion", "Source\DependencyInversion\DependencyInversion.csproj", "{F27275C6-45AB-44C9-B814-E2D351163736}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Embeddings.Processing", "Source\Embeddings.Processing\Embeddings.Processing.csproj", "{D39537F2-9731-4088-AC29-AC770C4822A1}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Embeddings.Store.MongoDB", "Source\Embeddings.Store.MongoDB\Embeddings.Store.MongoDB.csproj", "{B32C8559-AFC3-4507-AA99-9FFA544B3CE2}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Embeddings.Store", "Source\Embeddings.Store\Embeddings.Store.csproj", "{625883A4-0E94-4EAD-BEFA-895712DEDB0D}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventHorizon", "Source\EventHorizon\EventHorizon.csproj", "{C3E061F9-8CE0-46F9-A58F-2EBB70535B11}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Events.Processing", "Source\Events.Processing\Events.Processing.csproj", "{EBF87F46-A8F0-4165-944E-D7D2C3CA7F67}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Events.Store.MongoDB", "Source\Events.Store.MongoDB\Events.Store.MongoDB.csproj", "{DC8E4F7A-92D5-486F-AC2B-83CA265BB835}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Events.Store.Services.Grpc", "Source\Events.Store.Services.Grpc\Events.Store.Services.Grpc.csproj", "{624A912F-2F01-46E9-993E-D4479237B54A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Events.Store.Services.WebAPI", "Source\Events.Store.Services.WebAPI\Events.Store.Services.WebAPI.csproj", "{0A88FAF6-B67D-40C3-ABF7-F248B5449642}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Events.Store", "Source\Events.Store\Events.Store.csproj", "{EE187BA5-6BBD-46B1-8C6A-7C669B2AC670}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Execution", "Source\Execution\Execution.csproj", "{B1E8DD62-1D14-442D-B561-8F0199330A94}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Metrics", "Source\Metrics\Metrics.csproj", "{2B79D282-9373-442F-9785-0C23583E07FE}" @@ -41,8 +31,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Projections.Store.Services. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Projections.Store.Services", "Source\Projections.Store.Services\Projections.Store.Services.csproj", "{C0997BD9-E240-444C-BAD9-9C10689174AF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Projections.Store", "Source\Projections.Store\Projections.Store.csproj", "{442B178D-C454-43CE-B6FA-B201945757C4}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Protobuf", "Source\Protobuf\Protobuf.csproj", "{3CB60320-8148-4326-B3FB-EDECBAAE8FB8}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rudimentary", "Source\Rudimentary\Rudimentary.csproj", "{076897DB-000E-4C6F-9A6C-5BC038805876}" @@ -59,12 +47,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Specifications", "Specifica EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DependencyInversion", "Specifications\DependencyInversion\DependencyInversion.csproj", "{C76BA196-CA54-4B0B-8F26-2C1D77EEBD54}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Embeddings.Processing", "Specifications\Embeddings.Processing\Embeddings.Processing.csproj", "{98AE62BE-E045-4207-B8AF-854E411251FD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Embeddings.Store.MongoDB", "Specifications\Embeddings.Store.MongoDB\Embeddings.Store.MongoDB.csproj", "{5327B8F9-2B7C-48FE-9406-B3F771006C44}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Embeddings.Store", "Specifications\Embeddings.Store\Embeddings.Store.csproj", "{2C8A01C5-CBF8-4A02-BA67-BC3FE33037A9}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventHorizon", "Specifications\EventHorizon\EventHorizon.csproj", "{476F5C82-9C39-4E68-8F97-8B47ED388E62}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Events.Processing", "Specifications\Events.Processing\Events.Processing.csproj", "{1805FACA-1DA1-4A7E-9148-8CE723054445}" @@ -85,30 +67,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Services.Clients", "Specifi EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Services", "Specifications\Services\Services.csproj", "{AD4B3DD4-056E-4039-B802-1D696698559C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Embeddings.Store.Services.Grpc", "Source\Embeddings.Store.Services.Grpc\Embeddings.Store.Services.Grpc.csproj", "{1F21CF7D-0876-4F29-9CC4-BFAE0FD7BA79}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Embeddings.Store.Services", "Source\Embeddings.Store.Services\Embeddings.Store.Services.csproj", "{A4F26F29-D576-4C8F-8A56-BEDB544F884F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Embeddings.Store.Services", "Specifications\Embeddings.Store.Services\Embeddings.Store.Services.csproj", "{2AE953FF-3FCD-4D0A-BE5E-F8000FF21FF5}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Embeddings.Store.Services.Grpc", "Specifications\Embeddings.Store.Services.Grpc\Embeddings.Store.Services.Grpc.csproj", "{14C46406-450C-4A7B-B12B-D6059561E37A}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CLI", "Source\CLI\CLI.csproj", "{E41F088D-0357-4B9A-A6CB-EAF1A0F6F656}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Events.Processing.Management", "Source\Events.Processing.Management\Events.Processing.Management.csproj", "{D7696D25-712B-4921-8EAA-ABFA767D7C91}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Events", "Source\Events\Events.csproj", "{2C43489A-FE58-41E3-B6BB-25BF3A4B2E47}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Events", "Specifications\Events\Events.csproj", "{3DF9830F-B929-4BE0-B71A-608439364843}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aggregates", "Source\Aggregates\Aggregates.csproj", "{9C02A6FC-DAC6-408B-B56B-EC0C4D0B7D5A}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aggregates", "Specifications\Aggregates\Aggregates.csproj", "{F8BDD9B1-64AA-4038-B7ED-FB12F360DA62}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aggregates.Management", "Source\Aggregates.Management\Aggregates.Management.csproj", "{D5CD6014-99D7-46EC-A149-9ECCD72687AC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Events.Management", "Source\Events.Management\Events.Management.csproj", "{493EF936-F918-4A78-8AD9-A6A6F93D761A}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Resources", "Source\Resources\Resources.csproj", "{C70D8ED8-A701-4697-BE87-B623E37D8976}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Platform", "Source\Platform\Platform.csproj", "{9F665E30-4E54-40FD-B2BC-1E1782222F7E}" @@ -153,13 +119,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Events.Processing", "Integr EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Diagnostics", "Source\Diagnostics\Diagnostics.csproj", "{0B94A905-F24E-4097-ACEE-D4152A17CFF8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client.Management", "Source\Client.Management\Client.Management.csproj", "{D405DE86-99D4-4FF5-9938-1069DC6EB3C8}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "Source\Client\Client.csproj", "{ACAF1983-1EFC-4E42-932A-9396D0C4E228}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Events.Store.Services.Grpc", "Integration\Tests\Events.Store.Services.Grpc\Events.Store.Services.Grpc.csproj", "{4D838304-13DE-4B16-BBDD-E061F2E65300}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Meta", "Meta", "{CAF1D781-37E5-4C33-A114-7991B4AC4299}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".meta", ".meta", "{CAF1D781-37E5-4C33-A114-7991B4AC4299}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig default.props = default.props @@ -182,6 +146,26 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{89A4 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Configuration.Management", "Source\Configuration.Management\Configuration.Management.csproj", "{9ACC3932-CD9F-429A-A1F3-6476C9A12BC0}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Services", "Integration\Tests\Services\Services.csproj", "{C4C5230B-13BC-43A4-84D6-1BD408A694B0}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docker", "docker", "{C4446054-773D-4B63-A88B-3D35B71F6F66}" + ProjectSection(SolutionItems) = preProject + .dockerignore = .dockerignore + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "production", "production", "{A901E5CA-6ED3-465D-AB76-93FB0E20D17E}" + ProjectSection(SolutionItems) = preProject + Docker\Production\Dockerfile = Docker\Production\Dockerfile + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "development", "development", "{AC1D9095-A820-4B4B-BD98-A88E08790C16}" + ProjectSection(SolutionItems) = preProject + Docker\Development\Dockerfile = Docker\Development\Dockerfile + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Events.Store.MongoDB", "Integration\Tests\Events.Store.MongoDB\Events.Store.MongoDB.csproj", "{02CE4263-12B0-4DDC-AB20-452D2257D4D5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Events.Processing.Tests", "Specifications\Events.Processing.Tests\Events.Processing.Tests.csproj", "{F83E289C-91DC-42B9-BD8C-ED15E0D044E0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -219,42 +203,6 @@ Global {F27275C6-45AB-44C9-B814-E2D351163736}.Release|x64.Build.0 = Release|Any CPU {F27275C6-45AB-44C9-B814-E2D351163736}.Release|x86.ActiveCfg = Release|Any CPU {F27275C6-45AB-44C9-B814-E2D351163736}.Release|x86.Build.0 = Release|Any CPU - {D39537F2-9731-4088-AC29-AC770C4822A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D39537F2-9731-4088-AC29-AC770C4822A1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D39537F2-9731-4088-AC29-AC770C4822A1}.Debug|x64.ActiveCfg = Debug|Any CPU - {D39537F2-9731-4088-AC29-AC770C4822A1}.Debug|x64.Build.0 = Debug|Any CPU - {D39537F2-9731-4088-AC29-AC770C4822A1}.Debug|x86.ActiveCfg = Debug|Any CPU - {D39537F2-9731-4088-AC29-AC770C4822A1}.Debug|x86.Build.0 = Debug|Any CPU - {D39537F2-9731-4088-AC29-AC770C4822A1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D39537F2-9731-4088-AC29-AC770C4822A1}.Release|Any CPU.Build.0 = Release|Any CPU - {D39537F2-9731-4088-AC29-AC770C4822A1}.Release|x64.ActiveCfg = Release|Any CPU - {D39537F2-9731-4088-AC29-AC770C4822A1}.Release|x64.Build.0 = Release|Any CPU - {D39537F2-9731-4088-AC29-AC770C4822A1}.Release|x86.ActiveCfg = Release|Any CPU - {D39537F2-9731-4088-AC29-AC770C4822A1}.Release|x86.Build.0 = Release|Any CPU - {B32C8559-AFC3-4507-AA99-9FFA544B3CE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B32C8559-AFC3-4507-AA99-9FFA544B3CE2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B32C8559-AFC3-4507-AA99-9FFA544B3CE2}.Debug|x64.ActiveCfg = Debug|Any CPU - {B32C8559-AFC3-4507-AA99-9FFA544B3CE2}.Debug|x64.Build.0 = Debug|Any CPU - {B32C8559-AFC3-4507-AA99-9FFA544B3CE2}.Debug|x86.ActiveCfg = Debug|Any CPU - {B32C8559-AFC3-4507-AA99-9FFA544B3CE2}.Debug|x86.Build.0 = Debug|Any CPU - {B32C8559-AFC3-4507-AA99-9FFA544B3CE2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B32C8559-AFC3-4507-AA99-9FFA544B3CE2}.Release|Any CPU.Build.0 = Release|Any CPU - {B32C8559-AFC3-4507-AA99-9FFA544B3CE2}.Release|x64.ActiveCfg = Release|Any CPU - {B32C8559-AFC3-4507-AA99-9FFA544B3CE2}.Release|x64.Build.0 = Release|Any CPU - {B32C8559-AFC3-4507-AA99-9FFA544B3CE2}.Release|x86.ActiveCfg = Release|Any CPU - {B32C8559-AFC3-4507-AA99-9FFA544B3CE2}.Release|x86.Build.0 = Release|Any CPU - {625883A4-0E94-4EAD-BEFA-895712DEDB0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {625883A4-0E94-4EAD-BEFA-895712DEDB0D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {625883A4-0E94-4EAD-BEFA-895712DEDB0D}.Debug|x64.ActiveCfg = Debug|Any CPU - {625883A4-0E94-4EAD-BEFA-895712DEDB0D}.Debug|x64.Build.0 = Debug|Any CPU - {625883A4-0E94-4EAD-BEFA-895712DEDB0D}.Debug|x86.ActiveCfg = Debug|Any CPU - {625883A4-0E94-4EAD-BEFA-895712DEDB0D}.Debug|x86.Build.0 = Debug|Any CPU - {625883A4-0E94-4EAD-BEFA-895712DEDB0D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {625883A4-0E94-4EAD-BEFA-895712DEDB0D}.Release|Any CPU.Build.0 = Release|Any CPU - {625883A4-0E94-4EAD-BEFA-895712DEDB0D}.Release|x64.ActiveCfg = Release|Any CPU - {625883A4-0E94-4EAD-BEFA-895712DEDB0D}.Release|x64.Build.0 = Release|Any CPU - {625883A4-0E94-4EAD-BEFA-895712DEDB0D}.Release|x86.ActiveCfg = Release|Any CPU - {625883A4-0E94-4EAD-BEFA-895712DEDB0D}.Release|x86.Build.0 = Release|Any CPU {C3E061F9-8CE0-46F9-A58F-2EBB70535B11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C3E061F9-8CE0-46F9-A58F-2EBB70535B11}.Debug|Any CPU.Build.0 = Debug|Any CPU {C3E061F9-8CE0-46F9-A58F-2EBB70535B11}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -267,18 +215,6 @@ Global {C3E061F9-8CE0-46F9-A58F-2EBB70535B11}.Release|x64.Build.0 = Release|Any CPU {C3E061F9-8CE0-46F9-A58F-2EBB70535B11}.Release|x86.ActiveCfg = Release|Any CPU {C3E061F9-8CE0-46F9-A58F-2EBB70535B11}.Release|x86.Build.0 = Release|Any CPU - {EBF87F46-A8F0-4165-944E-D7D2C3CA7F67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EBF87F46-A8F0-4165-944E-D7D2C3CA7F67}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EBF87F46-A8F0-4165-944E-D7D2C3CA7F67}.Debug|x64.ActiveCfg = Debug|Any CPU - {EBF87F46-A8F0-4165-944E-D7D2C3CA7F67}.Debug|x64.Build.0 = Debug|Any CPU - {EBF87F46-A8F0-4165-944E-D7D2C3CA7F67}.Debug|x86.ActiveCfg = Debug|Any CPU - {EBF87F46-A8F0-4165-944E-D7D2C3CA7F67}.Debug|x86.Build.0 = Debug|Any CPU - {EBF87F46-A8F0-4165-944E-D7D2C3CA7F67}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EBF87F46-A8F0-4165-944E-D7D2C3CA7F67}.Release|Any CPU.Build.0 = Release|Any CPU - {EBF87F46-A8F0-4165-944E-D7D2C3CA7F67}.Release|x64.ActiveCfg = Release|Any CPU - {EBF87F46-A8F0-4165-944E-D7D2C3CA7F67}.Release|x64.Build.0 = Release|Any CPU - {EBF87F46-A8F0-4165-944E-D7D2C3CA7F67}.Release|x86.ActiveCfg = Release|Any CPU - {EBF87F46-A8F0-4165-944E-D7D2C3CA7F67}.Release|x86.Build.0 = Release|Any CPU {DC8E4F7A-92D5-486F-AC2B-83CA265BB835}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DC8E4F7A-92D5-486F-AC2B-83CA265BB835}.Debug|Any CPU.Build.0 = Debug|Any CPU {DC8E4F7A-92D5-486F-AC2B-83CA265BB835}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -315,18 +251,6 @@ Global {0A88FAF6-B67D-40C3-ABF7-F248B5449642}.Release|x64.Build.0 = Release|Any CPU {0A88FAF6-B67D-40C3-ABF7-F248B5449642}.Release|x86.ActiveCfg = Release|Any CPU {0A88FAF6-B67D-40C3-ABF7-F248B5449642}.Release|x86.Build.0 = Release|Any CPU - {EE187BA5-6BBD-46B1-8C6A-7C669B2AC670}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EE187BA5-6BBD-46B1-8C6A-7C669B2AC670}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EE187BA5-6BBD-46B1-8C6A-7C669B2AC670}.Debug|x64.ActiveCfg = Debug|Any CPU - {EE187BA5-6BBD-46B1-8C6A-7C669B2AC670}.Debug|x64.Build.0 = Debug|Any CPU - {EE187BA5-6BBD-46B1-8C6A-7C669B2AC670}.Debug|x86.ActiveCfg = Debug|Any CPU - {EE187BA5-6BBD-46B1-8C6A-7C669B2AC670}.Debug|x86.Build.0 = Debug|Any CPU - {EE187BA5-6BBD-46B1-8C6A-7C669B2AC670}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EE187BA5-6BBD-46B1-8C6A-7C669B2AC670}.Release|Any CPU.Build.0 = Release|Any CPU - {EE187BA5-6BBD-46B1-8C6A-7C669B2AC670}.Release|x64.ActiveCfg = Release|Any CPU - {EE187BA5-6BBD-46B1-8C6A-7C669B2AC670}.Release|x64.Build.0 = Release|Any CPU - {EE187BA5-6BBD-46B1-8C6A-7C669B2AC670}.Release|x86.ActiveCfg = Release|Any CPU - {EE187BA5-6BBD-46B1-8C6A-7C669B2AC670}.Release|x86.Build.0 = Release|Any CPU {B1E8DD62-1D14-442D-B561-8F0199330A94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B1E8DD62-1D14-442D-B561-8F0199330A94}.Debug|Any CPU.Build.0 = Debug|Any CPU {B1E8DD62-1D14-442D-B561-8F0199330A94}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -411,18 +335,6 @@ Global {C0997BD9-E240-444C-BAD9-9C10689174AF}.Release|x64.Build.0 = Release|Any CPU {C0997BD9-E240-444C-BAD9-9C10689174AF}.Release|x86.ActiveCfg = Release|Any CPU {C0997BD9-E240-444C-BAD9-9C10689174AF}.Release|x86.Build.0 = Release|Any CPU - {442B178D-C454-43CE-B6FA-B201945757C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {442B178D-C454-43CE-B6FA-B201945757C4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {442B178D-C454-43CE-B6FA-B201945757C4}.Debug|x64.ActiveCfg = Debug|Any CPU - {442B178D-C454-43CE-B6FA-B201945757C4}.Debug|x64.Build.0 = Debug|Any CPU - {442B178D-C454-43CE-B6FA-B201945757C4}.Debug|x86.ActiveCfg = Debug|Any CPU - {442B178D-C454-43CE-B6FA-B201945757C4}.Debug|x86.Build.0 = Debug|Any CPU - {442B178D-C454-43CE-B6FA-B201945757C4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {442B178D-C454-43CE-B6FA-B201945757C4}.Release|Any CPU.Build.0 = Release|Any CPU - {442B178D-C454-43CE-B6FA-B201945757C4}.Release|x64.ActiveCfg = Release|Any CPU - {442B178D-C454-43CE-B6FA-B201945757C4}.Release|x64.Build.0 = Release|Any CPU - {442B178D-C454-43CE-B6FA-B201945757C4}.Release|x86.ActiveCfg = Release|Any CPU - {442B178D-C454-43CE-B6FA-B201945757C4}.Release|x86.Build.0 = Release|Any CPU {3CB60320-8148-4326-B3FB-EDECBAAE8FB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3CB60320-8148-4326-B3FB-EDECBAAE8FB8}.Debug|Any CPU.Build.0 = Debug|Any CPU {3CB60320-8148-4326-B3FB-EDECBAAE8FB8}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -507,42 +419,6 @@ Global {C76BA196-CA54-4B0B-8F26-2C1D77EEBD54}.Release|x64.Build.0 = Release|Any CPU {C76BA196-CA54-4B0B-8F26-2C1D77EEBD54}.Release|x86.ActiveCfg = Release|Any CPU {C76BA196-CA54-4B0B-8F26-2C1D77EEBD54}.Release|x86.Build.0 = Release|Any CPU - {98AE62BE-E045-4207-B8AF-854E411251FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {98AE62BE-E045-4207-B8AF-854E411251FD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {98AE62BE-E045-4207-B8AF-854E411251FD}.Debug|x64.ActiveCfg = Debug|Any CPU - {98AE62BE-E045-4207-B8AF-854E411251FD}.Debug|x64.Build.0 = Debug|Any CPU - {98AE62BE-E045-4207-B8AF-854E411251FD}.Debug|x86.ActiveCfg = Debug|Any CPU - {98AE62BE-E045-4207-B8AF-854E411251FD}.Debug|x86.Build.0 = Debug|Any CPU - {98AE62BE-E045-4207-B8AF-854E411251FD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {98AE62BE-E045-4207-B8AF-854E411251FD}.Release|Any CPU.Build.0 = Release|Any CPU - {98AE62BE-E045-4207-B8AF-854E411251FD}.Release|x64.ActiveCfg = Release|Any CPU - {98AE62BE-E045-4207-B8AF-854E411251FD}.Release|x64.Build.0 = Release|Any CPU - {98AE62BE-E045-4207-B8AF-854E411251FD}.Release|x86.ActiveCfg = Release|Any CPU - {98AE62BE-E045-4207-B8AF-854E411251FD}.Release|x86.Build.0 = Release|Any CPU - {5327B8F9-2B7C-48FE-9406-B3F771006C44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5327B8F9-2B7C-48FE-9406-B3F771006C44}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5327B8F9-2B7C-48FE-9406-B3F771006C44}.Debug|x64.ActiveCfg = Debug|Any CPU - {5327B8F9-2B7C-48FE-9406-B3F771006C44}.Debug|x64.Build.0 = Debug|Any CPU - {5327B8F9-2B7C-48FE-9406-B3F771006C44}.Debug|x86.ActiveCfg = Debug|Any CPU - {5327B8F9-2B7C-48FE-9406-B3F771006C44}.Debug|x86.Build.0 = Debug|Any CPU - {5327B8F9-2B7C-48FE-9406-B3F771006C44}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5327B8F9-2B7C-48FE-9406-B3F771006C44}.Release|Any CPU.Build.0 = Release|Any CPU - {5327B8F9-2B7C-48FE-9406-B3F771006C44}.Release|x64.ActiveCfg = Release|Any CPU - {5327B8F9-2B7C-48FE-9406-B3F771006C44}.Release|x64.Build.0 = Release|Any CPU - {5327B8F9-2B7C-48FE-9406-B3F771006C44}.Release|x86.ActiveCfg = Release|Any CPU - {5327B8F9-2B7C-48FE-9406-B3F771006C44}.Release|x86.Build.0 = Release|Any CPU - {2C8A01C5-CBF8-4A02-BA67-BC3FE33037A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2C8A01C5-CBF8-4A02-BA67-BC3FE33037A9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2C8A01C5-CBF8-4A02-BA67-BC3FE33037A9}.Debug|x64.ActiveCfg = Debug|Any CPU - {2C8A01C5-CBF8-4A02-BA67-BC3FE33037A9}.Debug|x64.Build.0 = Debug|Any CPU - {2C8A01C5-CBF8-4A02-BA67-BC3FE33037A9}.Debug|x86.ActiveCfg = Debug|Any CPU - {2C8A01C5-CBF8-4A02-BA67-BC3FE33037A9}.Debug|x86.Build.0 = Debug|Any CPU - {2C8A01C5-CBF8-4A02-BA67-BC3FE33037A9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2C8A01C5-CBF8-4A02-BA67-BC3FE33037A9}.Release|Any CPU.Build.0 = Release|Any CPU - {2C8A01C5-CBF8-4A02-BA67-BC3FE33037A9}.Release|x64.ActiveCfg = Release|Any CPU - {2C8A01C5-CBF8-4A02-BA67-BC3FE33037A9}.Release|x64.Build.0 = Release|Any CPU - {2C8A01C5-CBF8-4A02-BA67-BC3FE33037A9}.Release|x86.ActiveCfg = Release|Any CPU - {2C8A01C5-CBF8-4A02-BA67-BC3FE33037A9}.Release|x86.Build.0 = Release|Any CPU {476F5C82-9C39-4E68-8F97-8B47ED388E62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {476F5C82-9C39-4E68-8F97-8B47ED388E62}.Debug|Any CPU.Build.0 = Debug|Any CPU {476F5C82-9C39-4E68-8F97-8B47ED388E62}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -663,54 +539,6 @@ Global {AD4B3DD4-056E-4039-B802-1D696698559C}.Release|x64.Build.0 = Release|Any CPU {AD4B3DD4-056E-4039-B802-1D696698559C}.Release|x86.ActiveCfg = Release|Any CPU {AD4B3DD4-056E-4039-B802-1D696698559C}.Release|x86.Build.0 = Release|Any CPU - {1F21CF7D-0876-4F29-9CC4-BFAE0FD7BA79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1F21CF7D-0876-4F29-9CC4-BFAE0FD7BA79}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1F21CF7D-0876-4F29-9CC4-BFAE0FD7BA79}.Debug|x64.ActiveCfg = Debug|Any CPU - {1F21CF7D-0876-4F29-9CC4-BFAE0FD7BA79}.Debug|x64.Build.0 = Debug|Any CPU - {1F21CF7D-0876-4F29-9CC4-BFAE0FD7BA79}.Debug|x86.ActiveCfg = Debug|Any CPU - {1F21CF7D-0876-4F29-9CC4-BFAE0FD7BA79}.Debug|x86.Build.0 = Debug|Any CPU - {1F21CF7D-0876-4F29-9CC4-BFAE0FD7BA79}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1F21CF7D-0876-4F29-9CC4-BFAE0FD7BA79}.Release|Any CPU.Build.0 = Release|Any CPU - {1F21CF7D-0876-4F29-9CC4-BFAE0FD7BA79}.Release|x64.ActiveCfg = Release|Any CPU - {1F21CF7D-0876-4F29-9CC4-BFAE0FD7BA79}.Release|x64.Build.0 = Release|Any CPU - {1F21CF7D-0876-4F29-9CC4-BFAE0FD7BA79}.Release|x86.ActiveCfg = Release|Any CPU - {1F21CF7D-0876-4F29-9CC4-BFAE0FD7BA79}.Release|x86.Build.0 = Release|Any CPU - {A4F26F29-D576-4C8F-8A56-BEDB544F884F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A4F26F29-D576-4C8F-8A56-BEDB544F884F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A4F26F29-D576-4C8F-8A56-BEDB544F884F}.Debug|x64.ActiveCfg = Debug|Any CPU - {A4F26F29-D576-4C8F-8A56-BEDB544F884F}.Debug|x64.Build.0 = Debug|Any CPU - {A4F26F29-D576-4C8F-8A56-BEDB544F884F}.Debug|x86.ActiveCfg = Debug|Any CPU - {A4F26F29-D576-4C8F-8A56-BEDB544F884F}.Debug|x86.Build.0 = Debug|Any CPU - {A4F26F29-D576-4C8F-8A56-BEDB544F884F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A4F26F29-D576-4C8F-8A56-BEDB544F884F}.Release|Any CPU.Build.0 = Release|Any CPU - {A4F26F29-D576-4C8F-8A56-BEDB544F884F}.Release|x64.ActiveCfg = Release|Any CPU - {A4F26F29-D576-4C8F-8A56-BEDB544F884F}.Release|x64.Build.0 = Release|Any CPU - {A4F26F29-D576-4C8F-8A56-BEDB544F884F}.Release|x86.ActiveCfg = Release|Any CPU - {A4F26F29-D576-4C8F-8A56-BEDB544F884F}.Release|x86.Build.0 = Release|Any CPU - {2AE953FF-3FCD-4D0A-BE5E-F8000FF21FF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2AE953FF-3FCD-4D0A-BE5E-F8000FF21FF5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2AE953FF-3FCD-4D0A-BE5E-F8000FF21FF5}.Debug|x64.ActiveCfg = Debug|Any CPU - {2AE953FF-3FCD-4D0A-BE5E-F8000FF21FF5}.Debug|x64.Build.0 = Debug|Any CPU - {2AE953FF-3FCD-4D0A-BE5E-F8000FF21FF5}.Debug|x86.ActiveCfg = Debug|Any CPU - {2AE953FF-3FCD-4D0A-BE5E-F8000FF21FF5}.Debug|x86.Build.0 = Debug|Any CPU - {2AE953FF-3FCD-4D0A-BE5E-F8000FF21FF5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2AE953FF-3FCD-4D0A-BE5E-F8000FF21FF5}.Release|Any CPU.Build.0 = Release|Any CPU - {2AE953FF-3FCD-4D0A-BE5E-F8000FF21FF5}.Release|x64.ActiveCfg = Release|Any CPU - {2AE953FF-3FCD-4D0A-BE5E-F8000FF21FF5}.Release|x64.Build.0 = Release|Any CPU - {2AE953FF-3FCD-4D0A-BE5E-F8000FF21FF5}.Release|x86.ActiveCfg = Release|Any CPU - {2AE953FF-3FCD-4D0A-BE5E-F8000FF21FF5}.Release|x86.Build.0 = Release|Any CPU - {14C46406-450C-4A7B-B12B-D6059561E37A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {14C46406-450C-4A7B-B12B-D6059561E37A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {14C46406-450C-4A7B-B12B-D6059561E37A}.Debug|x64.ActiveCfg = Debug|Any CPU - {14C46406-450C-4A7B-B12B-D6059561E37A}.Debug|x64.Build.0 = Debug|Any CPU - {14C46406-450C-4A7B-B12B-D6059561E37A}.Debug|x86.ActiveCfg = Debug|Any CPU - {14C46406-450C-4A7B-B12B-D6059561E37A}.Debug|x86.Build.0 = Debug|Any CPU - {14C46406-450C-4A7B-B12B-D6059561E37A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {14C46406-450C-4A7B-B12B-D6059561E37A}.Release|Any CPU.Build.0 = Release|Any CPU - {14C46406-450C-4A7B-B12B-D6059561E37A}.Release|x64.ActiveCfg = Release|Any CPU - {14C46406-450C-4A7B-B12B-D6059561E37A}.Release|x64.Build.0 = Release|Any CPU - {14C46406-450C-4A7B-B12B-D6059561E37A}.Release|x86.ActiveCfg = Release|Any CPU - {14C46406-450C-4A7B-B12B-D6059561E37A}.Release|x86.Build.0 = Release|Any CPU {E41F088D-0357-4B9A-A6CB-EAF1A0F6F656}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E41F088D-0357-4B9A-A6CB-EAF1A0F6F656}.Debug|Any CPU.Build.0 = Debug|Any CPU {E41F088D-0357-4B9A-A6CB-EAF1A0F6F656}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -723,18 +551,6 @@ Global {E41F088D-0357-4B9A-A6CB-EAF1A0F6F656}.Release|x64.Build.0 = Release|Any CPU {E41F088D-0357-4B9A-A6CB-EAF1A0F6F656}.Release|x86.ActiveCfg = Release|Any CPU {E41F088D-0357-4B9A-A6CB-EAF1A0F6F656}.Release|x86.Build.0 = Release|Any CPU - {D7696D25-712B-4921-8EAA-ABFA767D7C91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D7696D25-712B-4921-8EAA-ABFA767D7C91}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D7696D25-712B-4921-8EAA-ABFA767D7C91}.Debug|x64.ActiveCfg = Debug|Any CPU - {D7696D25-712B-4921-8EAA-ABFA767D7C91}.Debug|x64.Build.0 = Debug|Any CPU - {D7696D25-712B-4921-8EAA-ABFA767D7C91}.Debug|x86.ActiveCfg = Debug|Any CPU - {D7696D25-712B-4921-8EAA-ABFA767D7C91}.Debug|x86.Build.0 = Debug|Any CPU - {D7696D25-712B-4921-8EAA-ABFA767D7C91}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D7696D25-712B-4921-8EAA-ABFA767D7C91}.Release|Any CPU.Build.0 = Release|Any CPU - {D7696D25-712B-4921-8EAA-ABFA767D7C91}.Release|x64.ActiveCfg = Release|Any CPU - {D7696D25-712B-4921-8EAA-ABFA767D7C91}.Release|x64.Build.0 = Release|Any CPU - {D7696D25-712B-4921-8EAA-ABFA767D7C91}.Release|x86.ActiveCfg = Release|Any CPU - {D7696D25-712B-4921-8EAA-ABFA767D7C91}.Release|x86.Build.0 = Release|Any CPU {2C43489A-FE58-41E3-B6BB-25BF3A4B2E47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2C43489A-FE58-41E3-B6BB-25BF3A4B2E47}.Debug|Any CPU.Build.0 = Debug|Any CPU {2C43489A-FE58-41E3-B6BB-25BF3A4B2E47}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -759,18 +575,6 @@ Global {3DF9830F-B929-4BE0-B71A-608439364843}.Release|x64.Build.0 = Release|Any CPU {3DF9830F-B929-4BE0-B71A-608439364843}.Release|x86.ActiveCfg = Release|Any CPU {3DF9830F-B929-4BE0-B71A-608439364843}.Release|x86.Build.0 = Release|Any CPU - {9C02A6FC-DAC6-408B-B56B-EC0C4D0B7D5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9C02A6FC-DAC6-408B-B56B-EC0C4D0B7D5A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9C02A6FC-DAC6-408B-B56B-EC0C4D0B7D5A}.Debug|x64.ActiveCfg = Debug|Any CPU - {9C02A6FC-DAC6-408B-B56B-EC0C4D0B7D5A}.Debug|x64.Build.0 = Debug|Any CPU - {9C02A6FC-DAC6-408B-B56B-EC0C4D0B7D5A}.Debug|x86.ActiveCfg = Debug|Any CPU - {9C02A6FC-DAC6-408B-B56B-EC0C4D0B7D5A}.Debug|x86.Build.0 = Debug|Any CPU - {9C02A6FC-DAC6-408B-B56B-EC0C4D0B7D5A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9C02A6FC-DAC6-408B-B56B-EC0C4D0B7D5A}.Release|Any CPU.Build.0 = Release|Any CPU - {9C02A6FC-DAC6-408B-B56B-EC0C4D0B7D5A}.Release|x64.ActiveCfg = Release|Any CPU - {9C02A6FC-DAC6-408B-B56B-EC0C4D0B7D5A}.Release|x64.Build.0 = Release|Any CPU - {9C02A6FC-DAC6-408B-B56B-EC0C4D0B7D5A}.Release|x86.ActiveCfg = Release|Any CPU - {9C02A6FC-DAC6-408B-B56B-EC0C4D0B7D5A}.Release|x86.Build.0 = Release|Any CPU {F8BDD9B1-64AA-4038-B7ED-FB12F360DA62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F8BDD9B1-64AA-4038-B7ED-FB12F360DA62}.Debug|Any CPU.Build.0 = Debug|Any CPU {F8BDD9B1-64AA-4038-B7ED-FB12F360DA62}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -783,30 +587,6 @@ Global {F8BDD9B1-64AA-4038-B7ED-FB12F360DA62}.Release|x64.Build.0 = Release|Any CPU {F8BDD9B1-64AA-4038-B7ED-FB12F360DA62}.Release|x86.ActiveCfg = Release|Any CPU {F8BDD9B1-64AA-4038-B7ED-FB12F360DA62}.Release|x86.Build.0 = Release|Any CPU - {D5CD6014-99D7-46EC-A149-9ECCD72687AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D5CD6014-99D7-46EC-A149-9ECCD72687AC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D5CD6014-99D7-46EC-A149-9ECCD72687AC}.Debug|x64.ActiveCfg = Debug|Any CPU - {D5CD6014-99D7-46EC-A149-9ECCD72687AC}.Debug|x64.Build.0 = Debug|Any CPU - {D5CD6014-99D7-46EC-A149-9ECCD72687AC}.Debug|x86.ActiveCfg = Debug|Any CPU - {D5CD6014-99D7-46EC-A149-9ECCD72687AC}.Debug|x86.Build.0 = Debug|Any CPU - {D5CD6014-99D7-46EC-A149-9ECCD72687AC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D5CD6014-99D7-46EC-A149-9ECCD72687AC}.Release|Any CPU.Build.0 = Release|Any CPU - {D5CD6014-99D7-46EC-A149-9ECCD72687AC}.Release|x64.ActiveCfg = Release|Any CPU - {D5CD6014-99D7-46EC-A149-9ECCD72687AC}.Release|x64.Build.0 = Release|Any CPU - {D5CD6014-99D7-46EC-A149-9ECCD72687AC}.Release|x86.ActiveCfg = Release|Any CPU - {D5CD6014-99D7-46EC-A149-9ECCD72687AC}.Release|x86.Build.0 = Release|Any CPU - {493EF936-F918-4A78-8AD9-A6A6F93D761A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {493EF936-F918-4A78-8AD9-A6A6F93D761A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {493EF936-F918-4A78-8AD9-A6A6F93D761A}.Debug|x64.ActiveCfg = Debug|Any CPU - {493EF936-F918-4A78-8AD9-A6A6F93D761A}.Debug|x64.Build.0 = Debug|Any CPU - {493EF936-F918-4A78-8AD9-A6A6F93D761A}.Debug|x86.ActiveCfg = Debug|Any CPU - {493EF936-F918-4A78-8AD9-A6A6F93D761A}.Debug|x86.Build.0 = Debug|Any CPU - {493EF936-F918-4A78-8AD9-A6A6F93D761A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {493EF936-F918-4A78-8AD9-A6A6F93D761A}.Release|Any CPU.Build.0 = Release|Any CPU - {493EF936-F918-4A78-8AD9-A6A6F93D761A}.Release|x64.ActiveCfg = Release|Any CPU - {493EF936-F918-4A78-8AD9-A6A6F93D761A}.Release|x64.Build.0 = Release|Any CPU - {493EF936-F918-4A78-8AD9-A6A6F93D761A}.Release|x86.ActiveCfg = Release|Any CPU - {493EF936-F918-4A78-8AD9-A6A6F93D761A}.Release|x86.Build.0 = Release|Any CPU {C70D8ED8-A701-4697-BE87-B623E37D8976}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C70D8ED8-A701-4697-BE87-B623E37D8976}.Debug|Any CPU.Build.0 = Debug|Any CPU {C70D8ED8-A701-4697-BE87-B623E37D8976}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -1047,18 +827,6 @@ Global {0B94A905-F24E-4097-ACEE-D4152A17CFF8}.Release|x64.Build.0 = Release|Any CPU {0B94A905-F24E-4097-ACEE-D4152A17CFF8}.Release|x86.ActiveCfg = Release|Any CPU {0B94A905-F24E-4097-ACEE-D4152A17CFF8}.Release|x86.Build.0 = Release|Any CPU - {D405DE86-99D4-4FF5-9938-1069DC6EB3C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D405DE86-99D4-4FF5-9938-1069DC6EB3C8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D405DE86-99D4-4FF5-9938-1069DC6EB3C8}.Debug|x64.ActiveCfg = Debug|Any CPU - {D405DE86-99D4-4FF5-9938-1069DC6EB3C8}.Debug|x64.Build.0 = Debug|Any CPU - {D405DE86-99D4-4FF5-9938-1069DC6EB3C8}.Debug|x86.ActiveCfg = Debug|Any CPU - {D405DE86-99D4-4FF5-9938-1069DC6EB3C8}.Debug|x86.Build.0 = Debug|Any CPU - {D405DE86-99D4-4FF5-9938-1069DC6EB3C8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D405DE86-99D4-4FF5-9938-1069DC6EB3C8}.Release|Any CPU.Build.0 = Release|Any CPU - {D405DE86-99D4-4FF5-9938-1069DC6EB3C8}.Release|x64.ActiveCfg = Release|Any CPU - {D405DE86-99D4-4FF5-9938-1069DC6EB3C8}.Release|x64.Build.0 = Release|Any CPU - {D405DE86-99D4-4FF5-9938-1069DC6EB3C8}.Release|x86.ActiveCfg = Release|Any CPU - {D405DE86-99D4-4FF5-9938-1069DC6EB3C8}.Release|x86.Build.0 = Release|Any CPU {ACAF1983-1EFC-4E42-932A-9396D0C4E228}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {ACAF1983-1EFC-4E42-932A-9396D0C4E228}.Debug|Any CPU.Build.0 = Debug|Any CPU {ACAF1983-1EFC-4E42-932A-9396D0C4E228}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -1095,19 +863,50 @@ Global {9ACC3932-CD9F-429A-A1F3-6476C9A12BC0}.Release|x64.Build.0 = Release|Any CPU {9ACC3932-CD9F-429A-A1F3-6476C9A12BC0}.Release|x86.ActiveCfg = Release|Any CPU {9ACC3932-CD9F-429A-A1F3-6476C9A12BC0}.Release|x86.Build.0 = Release|Any CPU + {C4C5230B-13BC-43A4-84D6-1BD408A694B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C4C5230B-13BC-43A4-84D6-1BD408A694B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C4C5230B-13BC-43A4-84D6-1BD408A694B0}.Debug|x64.ActiveCfg = Debug|Any CPU + {C4C5230B-13BC-43A4-84D6-1BD408A694B0}.Debug|x64.Build.0 = Debug|Any CPU + {C4C5230B-13BC-43A4-84D6-1BD408A694B0}.Debug|x86.ActiveCfg = Debug|Any CPU + {C4C5230B-13BC-43A4-84D6-1BD408A694B0}.Debug|x86.Build.0 = Debug|Any CPU + {C4C5230B-13BC-43A4-84D6-1BD408A694B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C4C5230B-13BC-43A4-84D6-1BD408A694B0}.Release|Any CPU.Build.0 = Release|Any CPU + {C4C5230B-13BC-43A4-84D6-1BD408A694B0}.Release|x64.ActiveCfg = Release|Any CPU + {C4C5230B-13BC-43A4-84D6-1BD408A694B0}.Release|x64.Build.0 = Release|Any CPU + {C4C5230B-13BC-43A4-84D6-1BD408A694B0}.Release|x86.ActiveCfg = Release|Any CPU + {C4C5230B-13BC-43A4-84D6-1BD408A694B0}.Release|x86.Build.0 = Release|Any CPU + {02CE4263-12B0-4DDC-AB20-452D2257D4D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {02CE4263-12B0-4DDC-AB20-452D2257D4D5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {02CE4263-12B0-4DDC-AB20-452D2257D4D5}.Debug|x64.ActiveCfg = Debug|Any CPU + {02CE4263-12B0-4DDC-AB20-452D2257D4D5}.Debug|x64.Build.0 = Debug|Any CPU + {02CE4263-12B0-4DDC-AB20-452D2257D4D5}.Debug|x86.ActiveCfg = Debug|Any CPU + {02CE4263-12B0-4DDC-AB20-452D2257D4D5}.Debug|x86.Build.0 = Debug|Any CPU + {02CE4263-12B0-4DDC-AB20-452D2257D4D5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {02CE4263-12B0-4DDC-AB20-452D2257D4D5}.Release|Any CPU.Build.0 = Release|Any CPU + {02CE4263-12B0-4DDC-AB20-452D2257D4D5}.Release|x64.ActiveCfg = Release|Any CPU + {02CE4263-12B0-4DDC-AB20-452D2257D4D5}.Release|x64.Build.0 = Release|Any CPU + {02CE4263-12B0-4DDC-AB20-452D2257D4D5}.Release|x86.ActiveCfg = Release|Any CPU + {02CE4263-12B0-4DDC-AB20-452D2257D4D5}.Release|x86.Build.0 = Release|Any CPU + {F83E289C-91DC-42B9-BD8C-ED15E0D044E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F83E289C-91DC-42B9-BD8C-ED15E0D044E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F83E289C-91DC-42B9-BD8C-ED15E0D044E0}.Debug|x64.ActiveCfg = Debug|Any CPU + {F83E289C-91DC-42B9-BD8C-ED15E0D044E0}.Debug|x64.Build.0 = Debug|Any CPU + {F83E289C-91DC-42B9-BD8C-ED15E0D044E0}.Debug|x86.ActiveCfg = Debug|Any CPU + {F83E289C-91DC-42B9-BD8C-ED15E0D044E0}.Debug|x86.Build.0 = Debug|Any CPU + {F83E289C-91DC-42B9-BD8C-ED15E0D044E0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F83E289C-91DC-42B9-BD8C-ED15E0D044E0}.Release|Any CPU.Build.0 = Release|Any CPU + {F83E289C-91DC-42B9-BD8C-ED15E0D044E0}.Release|x64.ActiveCfg = Release|Any CPU + {F83E289C-91DC-42B9-BD8C-ED15E0D044E0}.Release|x64.Build.0 = Release|Any CPU + {F83E289C-91DC-42B9-BD8C-ED15E0D044E0}.Release|x86.ActiveCfg = Release|Any CPU + {F83E289C-91DC-42B9-BD8C-ED15E0D044E0}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {79AB0F5F-4DA5-40C5-9A0B-BE392F16B7C0} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {F27275C6-45AB-44C9-B814-E2D351163736} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} - {D39537F2-9731-4088-AC29-AC770C4822A1} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} - {B32C8559-AFC3-4507-AA99-9FFA544B3CE2} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} - {625883A4-0E94-4EAD-BEFA-895712DEDB0D} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {C3E061F9-8CE0-46F9-A58F-2EBB70535B11} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} - {EBF87F46-A8F0-4165-944E-D7D2C3CA7F67} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {DC8E4F7A-92D5-486F-AC2B-83CA265BB835} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {624A912F-2F01-46E9-993E-D4479237B54A} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {0A88FAF6-B67D-40C3-ABF7-F248B5449642} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} - {EE187BA5-6BBD-46B1-8C6A-7C669B2AC670} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {B1E8DD62-1D14-442D-B561-8F0199330A94} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {2B79D282-9373-442F-9785-0C23583E07FE} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {39CBF77F-92EF-4DC4-9553-DEEFA6AE0A66} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} @@ -1115,7 +914,6 @@ Global {78072792-44A9-4C0D-B632-0A5CEB75DAE6} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {30E6CE57-4F3A-4D48-9F5A-FF06E96C278C} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {C0997BD9-E240-444C-BAD9-9C10689174AF} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} - {442B178D-C454-43CE-B6FA-B201945757C4} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {3CB60320-8148-4326-B3FB-EDECBAAE8FB8} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {076897DB-000E-4C6F-9A6C-5BC038805876} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {6E0D6D3F-99EF-415A-86A5-24238521171F} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} @@ -1123,9 +921,6 @@ Global {A37AF291-25ED-46E1-99C3-C73A5EE51FE2} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {D30BC35F-4849-4725-BC96-127CAACE6A86} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {C76BA196-CA54-4B0B-8F26-2C1D77EEBD54} = {95D3ED76-BB5F-442F-A99A-F48FF34FEDA6} - {98AE62BE-E045-4207-B8AF-854E411251FD} = {95D3ED76-BB5F-442F-A99A-F48FF34FEDA6} - {5327B8F9-2B7C-48FE-9406-B3F771006C44} = {95D3ED76-BB5F-442F-A99A-F48FF34FEDA6} - {2C8A01C5-CBF8-4A02-BA67-BC3FE33037A9} = {95D3ED76-BB5F-442F-A99A-F48FF34FEDA6} {476F5C82-9C39-4E68-8F97-8B47ED388E62} = {95D3ED76-BB5F-442F-A99A-F48FF34FEDA6} {1805FACA-1DA1-4A7E-9148-8CE723054445} = {95D3ED76-BB5F-442F-A99A-F48FF34FEDA6} {E4A9FD76-7D13-4ADC-BEA9-B81D815DB3A9} = {95D3ED76-BB5F-442F-A99A-F48FF34FEDA6} @@ -1136,18 +931,10 @@ Global {06EF9A15-F2C6-478D-A6F0-630C101658E1} = {95D3ED76-BB5F-442F-A99A-F48FF34FEDA6} {8AC3B083-931F-469F-BD2C-6F12E98304F1} = {95D3ED76-BB5F-442F-A99A-F48FF34FEDA6} {AD4B3DD4-056E-4039-B802-1D696698559C} = {95D3ED76-BB5F-442F-A99A-F48FF34FEDA6} - {1F21CF7D-0876-4F29-9CC4-BFAE0FD7BA79} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} - {A4F26F29-D576-4C8F-8A56-BEDB544F884F} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} - {2AE953FF-3FCD-4D0A-BE5E-F8000FF21FF5} = {95D3ED76-BB5F-442F-A99A-F48FF34FEDA6} - {14C46406-450C-4A7B-B12B-D6059561E37A} = {95D3ED76-BB5F-442F-A99A-F48FF34FEDA6} {E41F088D-0357-4B9A-A6CB-EAF1A0F6F656} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} - {D7696D25-712B-4921-8EAA-ABFA767D7C91} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {2C43489A-FE58-41E3-B6BB-25BF3A4B2E47} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {3DF9830F-B929-4BE0-B71A-608439364843} = {95D3ED76-BB5F-442F-A99A-F48FF34FEDA6} - {9C02A6FC-DAC6-408B-B56B-EC0C4D0B7D5A} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {F8BDD9B1-64AA-4038-B7ED-FB12F360DA62} = {95D3ED76-BB5F-442F-A99A-F48FF34FEDA6} - {D5CD6014-99D7-46EC-A149-9ECCD72687AC} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} - {493EF936-F918-4A78-8AD9-A6A6F93D761A} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {C70D8ED8-A701-4697-BE87-B623E37D8976} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {9F665E30-4E54-40FD-B2BC-1E1782222F7E} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {73EC0F56-B3D6-4EDA-8C5A-8CB4A38F3CF3} = {95D3ED76-BB5F-442F-A99A-F48FF34FEDA6} @@ -1169,9 +956,14 @@ Global {58C4B7DD-EBEA-437C-AB18-72FE1B6AE1E0} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {519C1542-5C04-4E87-B255-0B0E98FB1B34} = {37343684-7BA7-40C1-9904-B8C434B8BD19} {0B94A905-F24E-4097-ACEE-D4152A17CFF8} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} - {D405DE86-99D4-4FF5-9938-1069DC6EB3C8} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {ACAF1983-1EFC-4E42-932A-9396D0C4E228} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} {4D838304-13DE-4B16-BBDD-E061F2E65300} = {37343684-7BA7-40C1-9904-B8C434B8BD19} {9ACC3932-CD9F-429A-A1F3-6476C9A12BC0} = {562DC4C5-91AB-4280-B40C-A2E0C43AA21C} + {C4C5230B-13BC-43A4-84D6-1BD408A694B0} = {37343684-7BA7-40C1-9904-B8C434B8BD19} + {C4446054-773D-4B63-A88B-3D35B71F6F66} = {CAF1D781-37E5-4C33-A114-7991B4AC4299} + {A901E5CA-6ED3-465D-AB76-93FB0E20D17E} = {C4446054-773D-4B63-A88B-3D35B71F6F66} + {AC1D9095-A820-4B4B-BD98-A88E08790C16} = {C4446054-773D-4B63-A88B-3D35B71F6F66} + {02CE4263-12B0-4DDC-AB20-452D2257D4D5} = {37343684-7BA7-40C1-9904-B8C434B8BD19} + {F83E289C-91DC-42B9-BD8C-ED15E0D044E0} = {95D3ED76-BB5F-442F-A99A-F48FF34FEDA6} EndGlobalSection EndGlobal diff --git a/Source/Actors/GrainAndActor.cs b/Source/Actors/GrainAndActor.cs index 85f6849c4..055c0c082 100644 --- a/Source/Actors/GrainAndActor.cs +++ b/Source/Actors/GrainAndActor.cs @@ -3,7 +3,6 @@ using System; using Proto; -using Proto.Cluster; namespace Dolittle.Runtime.Actors; diff --git a/Source/Actors/Hosting/ApplicationLifecycleHooks.cs b/Source/Actors/Hosting/ApplicationLifecycleHooks.cs index 0acd513a3..3eb114375 100644 --- a/Source/Actors/Hosting/ApplicationLifecycleHooks.cs +++ b/Source/Actors/Hosting/ApplicationLifecycleHooks.cs @@ -11,15 +11,16 @@ namespace Dolittle.Runtime.Actors.Hosting; /// -/// Shutdown hooks allow the registrant to perform necessary cleanup actions on asynchronously on shutdown before marking the hook complete, +/// Shutdown hooks allow the registrant to perform necessary cleanup actions asynchronously on shutdown before marking the hook complete, /// allowing the shutdown to continue /// -public interface IShutdownHook +public interface IShutdownHook : IDisposable { /// /// Gets a that completes when shutdown is triggered. /// Task ShuttingDown { get; } + CancellationToken SystemStoppingToken { get; } /// /// Marks the shutdown. @@ -34,10 +35,11 @@ public interface IApplicationLifecycleHooks { /// /// Register a shutdown hook. + /// It will prevent the application from shutting down until the hook is completed. /// /// The registered . IShutdownHook RegisterShutdownHook(); - + /// /// Shutdown all the hooks gracefully. /// @@ -56,40 +58,56 @@ public class ApplicationLifecycleHooks : IApplicationLifecycleHooks int _i = 0; readonly TaskCompletionSource _shutdownSource = new(); + readonly CancellationTokenSource _shutdownTokenSource = new(); readonly ConcurrentDictionary _registered = new(); - + /// public IShutdownHook RegisterShutdownHook() { + _shutdownTokenSource.Token.ThrowIfCancellationRequested(); var id = Interlocked.Increment(ref _i); var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); _registered.TryAdd(id, tcs.Task); return new ShutdownHook(() => { - tcs.TrySetResult(); - _registered.Remove(id, out _); - }, _shutdownSource.Task); + if (tcs.TrySetResult()) + { + _registered.Remove(id, out _); + } + }, _shutdownSource.Task, _shutdownTokenSource.Token); } /// public Task ShutdownGracefully(CancellationToken cancellationToken) { + try + { + _shutdownTokenSource.Cancel(); + } + catch + { + // ignored + } _shutdownSource.SetResult(); return Task.WhenAll(_registered.Values).WaitAsync(cancellationToken); } - + class ShutdownHook : IShutdownHook { readonly Action _onCompleted; - public ShutdownHook(Action onCompleted, Task shuttingDown) + public ShutdownHook(Action onCompleted, Task shuttingDown, CancellationToken systemStoppingToken) { _onCompleted = onCompleted; + SystemStoppingToken = systemStoppingToken; ShuttingDown = shuttingDown; } public Task ShuttingDown { get; } + public CancellationToken SystemStoppingToken { get; } public void MarkCompleted() => _onCompleted(); + + public void Dispose() => _onCompleted(); } } diff --git a/Source/Actors/Hosting/HostBuilderExtensions.cs b/Source/Actors/Hosting/HostBuilderExtensions.cs index e2da97870..04633c64e 100644 --- a/Source/Actors/Hosting/HostBuilderExtensions.cs +++ b/Source/Actors/Hosting/HostBuilderExtensions.cs @@ -7,9 +7,7 @@ using Proto; using Proto.Cluster; using Proto.Remote; -using Proto.Cluster.Partition; using Proto.Cluster.SingleNode; -using Proto.Cluster.Testing; using Proto.DependencyInjection; using Proto.OpenTelemetry; using Proto.Remote.GrpcNet; diff --git a/Source/Actors/Hosting/ProtoInternalsLoggerFactoryProxy.cs b/Source/Actors/Hosting/ProtoInternalsLoggerFactoryProxy.cs index b5e575564..c91298a49 100644 --- a/Source/Actors/Hosting/ProtoInternalsLoggerFactoryProxy.cs +++ b/Source/Actors/Hosting/ProtoInternalsLoggerFactoryProxy.cs @@ -49,12 +49,12 @@ static LogLevel GetLogLevel(LogLevel logLevel) => public bool IsEnabled(LogLevel logLevel) => _logger.IsEnabled(GetLogLevel(logLevel)); public void Log(LogLevel logLevel, int eventId, object state, - Exception exception, Func formatter) + Exception exception, Func formatter) { _logger.Log(GetLogLevel(logLevel), eventId, state, exception, formatter); } - public IDisposable BeginScope(TState state) => _logger.BeginScope(state); + public IDisposable? BeginScope(TState state) where TState: notnull=> _logger.BeginScope(state); public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) => _logger.Log(GetLogLevel(logLevel), eventId, state, exception, formatter); diff --git a/Source/Actors/Services.cs b/Source/Actors/Services.cs new file mode 100644 index 000000000..5c350ce9e --- /dev/null +++ b/Source/Actors/Services.cs @@ -0,0 +1,13 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.DependencyInversion; +using Microsoft.Extensions.DependencyInjection; + +namespace Dolittle.Runtime.Actors; + +public class Services : ICanAddServices +{ + public void AddTo(IServiceCollection services) + => services.AddSingleton(_ => new CreateProps(_)); +} diff --git a/Source/Aggregates.Management/Aggregates.Management.csproj b/Source/Aggregates.Management/Aggregates.Management.csproj deleted file mode 100644 index e32b5461b..000000000 --- a/Source/Aggregates.Management/Aggregates.Management.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Dolittle.Runtime.Aggregates.Management - Dolittle.Runtime.Aggregates.Management - - - - - - - - - - - - - diff --git a/Source/Aggregates/Aggregates.csproj b/Source/Aggregates/Aggregates.csproj deleted file mode 100644 index a2fe3e486..000000000 --- a/Source/Aggregates/Aggregates.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - Dolittle.Runtime.Aggregates - Dolittle.Runtime.Aggregates - - - - - - - - - - - - diff --git a/Source/Bootstrap/BoostrapProcedures.cs b/Source/Bootstrap/BoostrapProcedures.cs index bdc97496d..1296ce2c3 100644 --- a/Source/Bootstrap/BoostrapProcedures.cs +++ b/Source/Bootstrap/BoostrapProcedures.cs @@ -40,7 +40,7 @@ public Task PerformAll() foreach (var procedure in _procedures) { tasks.Add(procedure.Perform()); - tasks.AddRange(_tenants.Select(tenant => procedure.PerformForTenant(tenant))); + tasks.AddRange(_tenants.Select(procedure.PerformForTenant)); } return Task.WhenAll(tasks); } diff --git a/Source/Bootstrap/Bootstrap.csproj b/Source/Bootstrap/Bootstrap.csproj index d6dc4bbf3..9cb639675 100644 --- a/Source/Bootstrap/Bootstrap.csproj +++ b/Source/Bootstrap/Bootstrap.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/Source/CLI/CLI.csproj b/Source/CLI/CLI.csproj index 1eced54ae..5bbabf9c5 100644 --- a/Source/CLI/CLI.csproj +++ b/Source/CLI/CLI.csproj @@ -16,11 +16,8 @@ - - - - - + + diff --git a/Source/CLI/Configuration/Files/Serializer.cs b/Source/CLI/Configuration/Files/Serializer.cs index c4f986109..8fd2adda8 100644 --- a/Source/CLI/Configuration/Files/Serializer.cs +++ b/Source/CLI/Configuration/Files/Serializer.cs @@ -4,7 +4,6 @@ using System; using System.IO; using Microsoft.Extensions.FileProviders; -using Newtonsoft.Json; using IContentSerializer = Dolittle.Runtime.CLI.Serialization.ISerializer; namespace Dolittle.Runtime.CLI.Configuration.Files; diff --git a/Source/CLI/Runtime/EventHandlers/Get/Command.cs b/Source/CLI/Runtime/EventHandlers/Get/Command.cs index 12d9827ac..9c32cf8e6 100644 --- a/Source/CLI/Runtime/EventHandlers/Get/Command.cs +++ b/Source/CLI/Runtime/EventHandlers/Get/Command.cs @@ -40,7 +40,7 @@ public Command(ICanLocateRuntimes runtimes, IManagementClient client, IResolveEv /// The "--tenant" argument used to provide a Tenant Id. /// [Option("--tenant", CommandOptionType.SingleValue, Description = "Only show Event Handler information for the specified Tenant")] - TenantId Tenant { get; init; } + TenantId? Tenant { get; init; } /// /// The Event Handler identifier argument used to provide the unique identifier of the Event Handler to get. diff --git a/Source/CLI/Runtime/EventHandlers/IManagementClient.cs b/Source/CLI/Runtime/EventHandlers/IManagementClient.cs index c1eb6dfa5..1ba4f9dfa 100644 --- a/Source/CLI/Runtime/EventHandlers/IManagementClient.cs +++ b/Source/CLI/Runtime/EventHandlers/IManagementClient.cs @@ -40,7 +40,7 @@ public interface IManagementClient /// The address of the Runtime to connect to. /// The Tenant to get Stream Processor states for, or null to get all. /// A that, when resolved, returns the of all registered Projections. - Task> GetAll(MicroserviceAddress runtime, TenantId tenant = null); + Task> GetAll(MicroserviceAddress runtime, TenantId? tenant = null); /// /// Get the of a registered Event Handler by . diff --git a/Source/CLI/Runtime/EventHandlers/List/Command.cs b/Source/CLI/Runtime/EventHandlers/List/Command.cs index 7c746b66b..cc52c80a6 100644 --- a/Source/CLI/Runtime/EventHandlers/List/Command.cs +++ b/Source/CLI/Runtime/EventHandlers/List/Command.cs @@ -38,7 +38,7 @@ public Command(ICanLocateRuntimes runtimes, IManagementClient client, IResolveEv /// The "--tenant" argument used to provide a Tenant Id. /// [Option("--tenant", CommandOptionType.SingleValue, Description = "Only show Event Handler information for the specified Tenant")] - TenantId Tenant { get; init; } + TenantId? Tenant { get; init; } /// /// The entrypoint for the "dolittle runtime eventhandlers list" command. diff --git a/Source/CLI/Runtime/EventHandlers/ManagementClient.cs b/Source/CLI/Runtime/EventHandlers/ManagementClient.cs index 2b5573fb4..3ee8dbefe 100644 --- a/Source/CLI/Runtime/EventHandlers/ManagementClient.cs +++ b/Source/CLI/Runtime/EventHandlers/ManagementClient.cs @@ -76,7 +76,7 @@ public async Task ReprocessAllEvents(EventHandlerId eventHandler, MicroserviceAd } /// - public async Task> GetAll(MicroserviceAddress runtime, TenantId tenant = null) + public async Task> GetAll(MicroserviceAddress runtime, TenantId? tenant = null) { var client = _clients.CreateClientFor(runtime); var request = new GetAllRequest diff --git a/Source/CLI/Runtime/Projections/Get/Command.cs b/Source/CLI/Runtime/Projections/Get/Command.cs index 206df5b38..a1d6eb7f0 100644 --- a/Source/CLI/Runtime/Projections/Get/Command.cs +++ b/Source/CLI/Runtime/Projections/Get/Command.cs @@ -42,7 +42,7 @@ public Command(IManagementClient client, IResolveProjectionIdAndScope resolver, /// The "--tenant" argument used to provide a Tenant Id. /// [Option("--tenant", CommandOptionType.SingleValue, Description = "Only show Projection information for the specified Tenant")] - TenantId Tenant { get; init; } + TenantId? Tenant { get; init; } /// /// The Projection identifier argument used to provide the identifier of the Projection to get. diff --git a/Source/CLI/Runtime/Projections/ManagementClient.cs b/Source/CLI/Runtime/Projections/ManagementClient.cs index e5e959cfc..9ddceda8a 100644 --- a/Source/CLI/Runtime/Projections/ManagementClient.cs +++ b/Source/CLI/Runtime/Projections/ManagementClient.cs @@ -92,7 +92,7 @@ public async Task Replay(MicroserviceAddress runtime, ScopeId scope, Projec return new ReplayProjectionFailed(scope, projection, response.Failure.Reason); } - return Try.Succeeded(); + return Try.Succeeded; } ProjectionStatus CreateProjectionStatus(ManagementContracts.ProjectionStatus status) diff --git a/Source/CLI/Runtime/Projections/Replay/Command.cs b/Source/CLI/Runtime/Projections/Replay/Command.cs index c754678bf..7b6ecda39 100644 --- a/Source/CLI/Runtime/Projections/Replay/Command.cs +++ b/Source/CLI/Runtime/Projections/Replay/Command.cs @@ -67,7 +67,7 @@ public async Task OnExecuteAsync(CommandLineApplication cli) return; } - var getIdentity= await _resolver.Resolve(runtimeAddress, IdentifierOrAlias, Scope); + var getIdentity= await _resolver.Resolve(runtimeAddress.Result, IdentifierOrAlias, Scope); if (!getIdentity.Success) { throw getIdentity.Exception; diff --git a/Source/Client.Management/Client.Management.csproj b/Source/Client.Management/Client.Management.csproj deleted file mode 100644 index 6ac0a7332..000000000 --- a/Source/Client.Management/Client.Management.csproj +++ /dev/null @@ -1,22 +0,0 @@ - - - - - Dolittle.Runtime.Client.Management - Dolittle.Runtime.Client.Management - - - - - - - - - - - - - - - - diff --git a/Source/Client/BuildResultExtensions.cs b/Source/Client/BuildResultExtensions.cs index ac42f34dc..7dc74cac5 100644 --- a/Source/Client/BuildResultExtensions.cs +++ b/Source/Client/BuildResultExtensions.cs @@ -3,7 +3,6 @@ using System.Linq; using Dolittle.Runtime.Protobuf; -using Google.Protobuf.Collections; namespace Dolittle.Runtime.Client; diff --git a/Source/Client/BuildResultsForHeads.cs b/Source/Client/BuildResultsForHeads.cs index f7ebe47f0..43934778b 100644 --- a/Source/Client/BuildResultsForHeads.cs +++ b/Source/Client/BuildResultsForHeads.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Linq; using Dolittle.Runtime.DependencyInversion.Lifecycle; using Dolittle.Runtime.Services; using Microsoft.Extensions.Logging; diff --git a/Source/Client/Client.csproj b/Source/Client/Client.csproj index 68160e823..d1b80e989 100644 --- a/Source/Client/Client.csproj +++ b/Source/Client/Client.csproj @@ -12,7 +12,7 @@ - + diff --git a/Source/Client.Management/ClientService.cs b/Source/Client/Management/ClientService.cs similarity index 100% rename from Source/Client.Management/ClientService.cs rename to Source/Client/Management/ClientService.cs diff --git a/Source/Client.Management/LoggerExtensions.cs b/Source/Client/Management/LoggerExtensions.cs similarity index 100% rename from Source/Client.Management/LoggerExtensions.cs rename to Source/Client/Management/LoggerExtensions.cs diff --git a/Source/Configuration/Parsing/ConfigurationParser.cs b/Source/Configuration/Parsing/ConfigurationParser.cs index a025ec0ce..e533adafa 100644 --- a/Source/Configuration/Parsing/ConfigurationParser.cs +++ b/Source/Configuration/Parsing/ConfigurationParser.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; @@ -16,7 +17,9 @@ namespace Dolittle.Runtime.Configuration.Parsing; public class ConfigurationParser : IParseConfigurationObjects { /// - public bool TryParseFrom(IConfigurationSection configuration, out TOptions parsed, out Exception error) + public bool TryParseFrom(IConfigurationSection configuration, + [NotNullWhen(true)] out TOptions? parsed, + [NotNullWhen(false)] out Exception? error) where TOptions : class { parsed = default; diff --git a/Source/Configuration/Parsing/IParseConfigurationObjects.cs b/Source/Configuration/Parsing/IParseConfigurationObjects.cs index 74d0c598f..ca72bad58 100644 --- a/Source/Configuration/Parsing/IParseConfigurationObjects.cs +++ b/Source/Configuration/Parsing/IParseConfigurationObjects.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.Configuration; namespace Dolittle.Runtime.Configuration.Parsing; @@ -19,6 +20,8 @@ public interface IParseConfigurationObjects /// The outputted . /// The type of the configuration. /// True if successfully parsed, false if not. - bool TryParseFrom(IConfigurationSection configuration, out TOptions parsed, out Exception error) + bool TryParseFrom(IConfigurationSection configuration, + [NotNullWhen(true)] out TOptions? parsed, + [NotNullWhen(false)] out Exception? error) where TOptions : class; } diff --git a/Source/DependencyInversion/Tenancy/GeneratedTenantFactoryRegistrationSource.cs b/Source/DependencyInversion/Tenancy/GeneratedTenantFactoryRegistrationSource.cs index 1d56e59dd..a45c19c4f 100644 --- a/Source/DependencyInversion/Tenancy/GeneratedTenantFactoryRegistrationSource.cs +++ b/Source/DependencyInversion/Tenancy/GeneratedTenantFactoryRegistrationSource.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -78,7 +79,11 @@ public IEnumerable RegistrationsFor(Service service, Fun }; } - static bool IsDelegateWithTenantIdAsFirstParameter(Service service, out Type delegateType, out ParameterInfo[] parameters, out Type returnType) + static bool IsDelegateWithTenantIdAsFirstParameter( + Service service, + [NotNullWhen(true)] out Type? delegateType, + [NotNullWhen(true)] out ParameterInfo[]? parameters, + [NotNullWhen(true)] out Type? returnType) { delegateType = default; parameters = default; diff --git a/Source/DependencyInversion/Types/TypeScanner.cs b/Source/DependencyInversion/Types/TypeScanner.cs index 2659383fb..b4836c917 100644 --- a/Source/DependencyInversion/Types/TypeScanner.cs +++ b/Source/DependencyInversion/Types/TypeScanner.cs @@ -23,9 +23,9 @@ public static IEnumerable GetAllClassesInRuntimeAssemblies() { var assemblies = AssemblyFinder.FindAssemblies( _ => { }, - assembly => assembly.FullName != default + assembly => (assembly.FullName != default && assembly.FullName.StartsWith("Dolittle.Runtime", StringComparison.InvariantCulture) - && !assembly.FullName.Contains("Contracts", StringComparison.InvariantCulture), + && !assembly.FullName.Contains("Contracts", StringComparison.InvariantCulture)) || assembly.FullName?.StartsWith("Integration.Tests", StringComparison.InvariantCulture) == true, true); return assemblies.SelectMany(_ => _.ExportedTypes).Where(_ => _.IsClass); } diff --git a/Source/Diagnostics/Diagnostics.csproj b/Source/Diagnostics/Diagnostics.csproj index 0df1f7306..64264c352 100644 --- a/Source/Diagnostics/Diagnostics.csproj +++ b/Source/Diagnostics/Diagnostics.csproj @@ -7,7 +7,7 @@ - + diff --git a/Source/Diagnostics/OpenTelemetry/OpenTelemetryConfiguration.cs b/Source/Diagnostics/OpenTelemetry/OpenTelemetryConfiguration.cs index c01999549..0252f0e87 100644 --- a/Source/Diagnostics/OpenTelemetry/OpenTelemetryConfiguration.cs +++ b/Source/Diagnostics/OpenTelemetry/OpenTelemetryConfiguration.cs @@ -11,7 +11,7 @@ public class OpenTelemetryConfiguration /// /// OTLP reporting endpoint /// - public string Endpoint { get; set; } + public string? Endpoint { get; set; } public string ServiceName { get; set; } = "dolittle-runtime"; diff --git a/Source/Domain/Platform/VersionConverter.cs b/Source/Domain/Platform/VersionConverter.cs index 5ff45b84e..5dc3a133a 100644 --- a/Source/Domain/Platform/VersionConverter.cs +++ b/Source/Domain/Platform/VersionConverter.cs @@ -9,18 +9,19 @@ namespace Dolittle.Runtime.Domain.Platform; /// /// Represents an implementation of . /// -public class VersionConverter : IVersionConverter +public partial class VersionConverter : IVersionConverter { - static readonly Regex _versionRegex = new("(\\d+).(\\d+).(\\d+)-*([\\w]+)*[+-.]*(\\d+)*", RegexOptions.Compiled); + [GeneratedRegex("(\\d+).(\\d+).(\\d+)-*([\\w]+)*[+-.]*(\\d+)*", RegexOptions.Compiled)] + private static partial Regex MyRegex(); + + static readonly Regex _versionRegex = MyRegex(); /// public Version FromString(string versionAsString) { var result = _versionRegex.Match(versionAsString); if (!result.Success) - { throw new InvalidVersionString(versionAsString); - } var major = int.Parse(result.Groups[1].Value, CultureInfo.InvariantCulture); var minor = int.Parse(result.Groups[2].Value, CultureInfo.InvariantCulture); var patch = int.Parse(result.Groups[3].Value, CultureInfo.InvariantCulture); @@ -29,9 +30,7 @@ public Version FromString(string versionAsString) var isRelease = result.Groups[4].Value?.Length == 0; if (!isRelease) - { return new Version(major, minor, patch, build, result.Groups[4].Value); - } return new Version(major, minor, patch, build); } diff --git a/Source/Embeddings.Processing/CalculateStateTransitionEventsCancelled.cs b/Source/Embeddings.Processing/CalculateStateTransitionEventsCancelled.cs deleted file mode 100644 index 7ef209c83..000000000 --- a/Source/Embeddings.Processing/CalculateStateTransitionEventsCancelled.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Threading; -using Dolittle.Runtime.Embeddings.Store; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Exception that gets thrown when while calculating state transition events for an . -/// -public class CalculateStateTransitionEventsCancelled : Exception -{ - /// - /// Initializes an instance of the class. - /// - /// The embedding identifier. - public CalculateStateTransitionEventsCancelled(EmbeddingId embedding) - : base($"A cancellation was request while calculating state transition events fro embedding {embedding.Value}") - { - } -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/CompareEmbeddingDefinitionsForAllTenants.cs b/Source/Embeddings.Processing/CompareEmbeddingDefinitionsForAllTenants.cs deleted file mode 100644 index 3ec2e403b..000000000 --- a/Source/Embeddings.Processing/CompareEmbeddingDefinitionsForAllTenants.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.DependencyInversion.Lifecycle; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Embeddings.Store.Definition; -using Dolittle.Runtime.Tenancy; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents an implementation of . -/// -[Singleton] -public class CompareEmbeddingDefinitionsForAllTenants : ICompareEmbeddingDefinitionsForAllTenants -{ - readonly IPerformActionsForAllTenants _forAllTenants; - readonly Func _getDefinitionsFor; - - /// - /// Initializes an instance of the class. - /// - /// The tool for performing an action on all tenants. - /// The factory for getting Embedding definitions. - public CompareEmbeddingDefinitionsForAllTenants( - IPerformActionsForAllTenants forAllTenants, - Func getDefinitionsFor) - { - _forAllTenants = forAllTenants; - _getDefinitionsFor = getDefinitionsFor; - } - - /// - public async Task> DiffersFromPersisted( - EmbeddingDefinition definition, - CancellationToken token) - { - var results = new Dictionary(); - await _forAllTenants.PerformAsync(async (tenant, _) => - { - var definitions = _getDefinitionsFor(tenant); - var tryGetDefinition = await definitions.TryGet(definition.Embedding, token).ConfigureAwait(false); - var comparisonResult = tryGetDefinition.Success switch - { - true => DefinitionsAreEqual(definition, tryGetDefinition), - false => EmbeddingDefinitionComparisonResult.Equal - }; - results.Add(tenant, comparisonResult); - }).ConfigureAwait(false); - - return results; - } - - static EmbeddingDefinitionComparisonResult DefinitionsAreEqual( - EmbeddingDefinition newDefinition, - EmbeddingDefinition oldDefinition) - { - if (newDefinition.Embedding != oldDefinition.Embedding) - { - return EmbeddingDefinitionComparisonResult.Unequal($"The new Embedding identifier {newDefinition.Embedding.Value} is not the same as the persisted embedding identifier {oldDefinition.Embedding.Value}"); - } - if (!InitialStatesAreEqual(newDefinition, oldDefinition, out var failedComparison)) - { - return failedComparison; - } - return !EventsAreEqual(newDefinition, oldDefinition, out failedComparison) - ? failedComparison - : EmbeddingDefinitionComparisonResult.Equal; - } - - static bool InitialStatesAreEqual(EmbeddingDefinition newDefinition, EmbeddingDefinition oldDefinition, out EmbeddingDefinitionComparisonResult failedComparison) - { - failedComparison = null; - if (newDefinition.InititalState == oldDefinition.InititalState) - { - return true; - } - failedComparison = EmbeddingDefinitionComparisonResult.Unequal("The initial Embedding state is not the same as the persisted definition"); - return false; - } - - static bool EventsAreEqual(EmbeddingDefinition newDefinition, EmbeddingDefinition oldDefinition, out EmbeddingDefinitionComparisonResult failedComparison) - { - failedComparison = null; - if (newDefinition.Events.Count() != oldDefinition.Events.Count()) - { - failedComparison = EmbeddingDefinitionComparisonResult.Unequal("The definitions does not have the same number of events"); - return false; - } - - foreach (var newEvent in newDefinition.Events) - { - var oldEvent = oldDefinition.Events.FirstOrDefault(oldEvent => oldEvent.Id == newEvent.Id); - if (oldEvent != default) - { - continue; - } - failedComparison = EmbeddingDefinitionComparisonResult.Unequal($"Event {newEvent.Id.Value} was not in previous Embedding definition"); - return false; - } - - return true; - } -} diff --git a/Source/Embeddings.Processing/CompareProjectionStates.cs b/Source/Embeddings.Processing/CompareProjectionStates.cs deleted file mode 100644 index fd61916bc..000000000 --- a/Source/Embeddings.Processing/CompareProjectionStates.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Rudimentary; -using Newtonsoft.Json.Linq; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents an implementation of . -/// -public class CompareProjectionStates : ICompareStates -{ - /// - public Try TryCheckEquality(ProjectionState left, ProjectionState right) - { - try - { - var leftObject = JObject.Parse(left.Value); - var rightObject = JObject.Parse(right.Value); - return JToken.DeepEquals(leftObject, rightObject); - } - catch (Exception ex) - { - return ex; - } - } -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/CouldNotProjectAllEvents.cs b/Source/Embeddings.Processing/CouldNotProjectAllEvents.cs deleted file mode 100644 index 0de3f0082..000000000 --- a/Source/Embeddings.Processing/CouldNotProjectAllEvents.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Embeddings.Store; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Exception that gets thrown when we could not project all events. -/// -public class CouldNotProjectAllEvents : Exception -{ - /// - /// Initializes a new instance of the class. - /// - /// The - /// The inner - public CouldNotProjectAllEvents(EmbeddingId embedding, Exception inner) - : base($"Not all events could be projected for embedding {embedding.Value}", inner) - { - } -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/CreateEmbeddingProcessor.cs b/Source/Embeddings.Processing/CreateEmbeddingProcessor.cs deleted file mode 100644 index 7fae853b1..000000000 --- a/Source/Embeddings.Processing/CreateEmbeddingProcessor.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Domain.Tenancy; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// A delegate represeting something that can create instances of for a specific tenant. -/// -/// The to create a processor for. -/// A scoped to the specified tenant. -public delegate IEmbeddingProcessor CreateEmbeddingProcessorForTenant(TenantId tenant); diff --git a/Source/Embeddings.Processing/DetectingEmbeddingLoopFailed.cs b/Source/Embeddings.Processing/DetectingEmbeddingLoopFailed.cs deleted file mode 100644 index af3ff63ce..000000000 --- a/Source/Embeddings.Processing/DetectingEmbeddingLoopFailed.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Embeddings.Store; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Exception that gets thrown when a failure occurred while detecting embedding loop. -/// -public class DetectingEmbeddingLoopFailed : Exception -{ - /// - /// Initializes a new instance of the class. - /// - /// The . - public DetectingEmbeddingLoopFailed() - : base($"An error occurred while detecting embedding loop") - { - } -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/Embedding.cs b/Source/Embeddings.Processing/Embedding.cs deleted file mode 100644 index ecb161c6b..000000000 --- a/Source/Embeddings.Processing/Embedding.cs +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Artifacts; -using Dolittle.Runtime.DependencyInversion; -using Dolittle.Runtime.Embeddings.Contracts; -using Dolittle.Runtime.Embeddings.Store; -using Dolittle.Runtime.Events; -using Dolittle.Runtime.Events.Processing.Projections; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Protobuf; -using Dolittle.Runtime.Rudimentary; -using Microsoft.Extensions.Logging; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; -using ReverseCallDispatcherType = Dolittle.Runtime.Services.IReverseCallDispatcher< - Dolittle.Runtime.Embeddings.Contracts.EmbeddingClientToRuntimeMessage, - Dolittle.Runtime.Embeddings.Contracts.EmbeddingRuntimeToClientMessage, - Dolittle.Runtime.Embeddings.Contracts.EmbeddingRegistrationRequest, - Dolittle.Runtime.Embeddings.Contracts.EmbeddingRegistrationResponse, - Dolittle.Runtime.Embeddings.Contracts.EmbeddingRequest, - Dolittle.Runtime.Embeddings.Contracts.EmbeddingResponse>; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents an implementation of . -/// -[DisableAutoRegistration] -public class Embedding : IEmbedding -{ - readonly EmbeddingId _embeddingId; - readonly ReverseCallDispatcherType _dispatcher; - readonly IEmbeddingRequestFactory _requestFactory; - readonly ILogger _logger; - - /// - /// Initializes an instance of the class. - /// - /// The identifier for this embedding. - /// The reverse call dispatcher to use to dispatch update and delete calls to the client. - /// The factory to use to create requests to the client. - /// The logger to use for logging. - public Embedding( - EmbeddingId embeddingId, - ReverseCallDispatcherType dispatcher, - IEmbeddingRequestFactory requestFactory, - ILogger logger) - { - _embeddingId = embeddingId; - _dispatcher = dispatcher; - _requestFactory = requestFactory; - _logger = logger; - } - - /// - public async Task Project(ProjectionCurrentState state, UncommittedEvent @event, ExecutionContext executionContext, CancellationToken cancellationToken) - { - try - { - _logger.ProjectEventThroughDispatcher(_embeddingId, state); - var response = await _dispatcher.Call( - _requestFactory.Create(state, @event), - executionContext, - cancellationToken).ConfigureAwait(false); - - if (IsFailureResponse(response)) - { - return new ProjectionFailedResult(GetFailureReason(response)); - } - return response.ResponseCase switch - { - EmbeddingResponse.ResponseOneofCase.ProjectionDelete => new ProjectionDeleteResult(), - EmbeddingResponse.ResponseOneofCase.ProjectionReplace => new ProjectionReplaceResult(response.ProjectionReplace.State), - EmbeddingResponse.ResponseOneofCase.Compare - => new ProjectionFailedResult(new UnexpectedEmbeddingResponse(_embeddingId, response.ResponseCase)), - EmbeddingResponse.ResponseOneofCase.Delete - => new ProjectionFailedResult(new UnexpectedEmbeddingResponse(_embeddingId, response.ResponseCase)), - _ => new ProjectionFailedResult(new UnexpectedEmbeddingResponse(_embeddingId, response.ResponseCase)) - }; - } - catch (Exception ex) - { - return new ProjectionFailedResult(ex); - } - } - - /// - public async Task> TryCompare(EmbeddingCurrentState currentState, ProjectionState desiredState, ExecutionContext executionContext, CancellationToken cancellationToken) - { - _logger.CompareStatesForEmbedding(_embeddingId, currentState, desiredState); - var request = _requestFactory.TryCreate(currentState, desiredState); - if (!request.Success) - { - return request.Exception; - } - return await DispatchAndHandleEmbeddingResponse( - currentState, - request, - EmbeddingResponse.ResponseOneofCase.Compare, - response => response.Compare.Events, - (embedding, failureReason) => new EmbeddingRemoteCompareCallFailed(embedding, failureReason), - executionContext, - cancellationToken).ConfigureAwait(false); - } - - /// - public async Task> TryDelete(EmbeddingCurrentState currentState, ExecutionContext executionContext, CancellationToken cancellationToken) - { - _logger.DeletingStateForEmbedding(_embeddingId, currentState); - var request = _requestFactory.TryCreate(currentState); - if (!request.Success) - { - return request.Exception; - } - return await DispatchAndHandleEmbeddingResponse( - currentState, - request, - EmbeddingResponse.ResponseOneofCase.Delete, - response => response.Delete.Events, - (embedding, failureReason) => new EmbeddingRemoteDeleteCallFailed(embedding, failureReason), - executionContext, - cancellationToken).ConfigureAwait(false); - } - - async Task> DispatchAndHandleEmbeddingResponse( - EmbeddingCurrentState currentState, - EmbeddingRequest request, - EmbeddingResponse.ResponseOneofCase expectedResponse, - Func> getEvents, - Func createFailedException, - ExecutionContext executionContext, - CancellationToken cancellationToken) - { - try - { - var response = await _dispatcher.Call(request, executionContext, cancellationToken).ConfigureAwait(false); - if (IsFailureResponse(response)) - { - return createFailedException(_embeddingId, GetFailureReason(response)); - } - - return response.ResponseCase == expectedResponse - ? ToUncommittedEvents(currentState.Key.Value, getEvents(response)) - : new UnexpectedEmbeddingResponse(_embeddingId, response.ResponseCase); - } - catch (Exception ex) - { - return ex; - } - } - - - bool IsFailureResponse(EmbeddingResponse response) - => response.Failure is not null || response.ProcessorFailure is not null; - - string GetFailureReason(EmbeddingResponse response) => response.ProcessorFailure?.Reason ?? response.Failure.Reason; - - UncommittedEvents ToUncommittedEvents(EventSourceId eventSourceId, IEnumerable events) - => new( - new ReadOnlyCollection(events.Select(_ => - new UncommittedEvent( - eventSourceId, - new Artifact(_.EventType.Id.ToGuid(), - _.EventType.Generation), - _.Public, - _.Content)).ToList())); -} diff --git a/Source/Embeddings.Processing/EmbeddingCurrentStateExtensions.cs b/Source/Embeddings.Processing/EmbeddingCurrentStateExtensions.cs deleted file mode 100644 index a7d4e613f..000000000 --- a/Source/Embeddings.Processing/EmbeddingCurrentStateExtensions.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Embeddings.Store; -using ContractsProjectionCurrentState = Dolittle.Runtime.Projections.Contracts.ProjectionCurrentState; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Extensions for . -/// -public static class EmbeddingCurrentStateExtensions -{ - /// - /// Convert to a protobuf representation of . - /// - /// to convert. - /// Converted . - public static ContractsProjectionCurrentState ToProtobuf(this EmbeddingCurrentState state) - => new() - { - Type = state.Type.ToProtobuf(), - State = state.State, - Key = state.Key - }; - - /// - /// Convert to an of protobuf representations of . - /// - /// The of type to convert. - /// Converted of type . - public static IEnumerable ToProtobuf(this IEnumerable states) - => states.Select(_ => _.ToProtobuf()); -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/EmbeddingCurrentStateTypeExtensions.cs b/Source/Embeddings.Processing/EmbeddingCurrentStateTypeExtensions.cs deleted file mode 100644 index 5537c9eba..000000000 --- a/Source/Embeddings.Processing/EmbeddingCurrentStateTypeExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Embeddings.Store; -using ContractsProjectionCurrentStateType = Dolittle.Runtime.Projections.Contracts.ProjectionCurrentStateType; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Extensions for . -/// -public static class EmbeddingCurrentStateTypeExtensions -{ - /// - /// Convert to a protobuf representation of . - /// - /// to convert. - /// Converted . - public static ContractsProjectionCurrentStateType ToProtobuf(this EmbeddingCurrentStateType type) - => type switch - { - EmbeddingCurrentStateType.CreatedFromInitialState => ContractsProjectionCurrentStateType.CreatedFromInitialState, - EmbeddingCurrentStateType.Persisted => ContractsProjectionCurrentStateType.Persisted, - _ => throw new UnknownEmbeddingCurrentStateType(type), - }; -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/EmbeddingDefinitionComparisonResult.cs b/Source/Embeddings.Processing/EmbeddingDefinitionComparisonResult.cs deleted file mode 100644 index 6bbfb5492..000000000 --- a/Source/Embeddings.Processing/EmbeddingDefinitionComparisonResult.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Embeddings.Store.Definition; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents the result of the comparison of a . -/// -public class EmbeddingDefinitionComparisonResult -{ - /// - /// Creates a successful . - /// - /// The successful . - public static EmbeddingDefinitionComparisonResult Equal => new(); - - /// - /// Creates a failed . - /// - /// The reason why they're unequal. - /// The failed . - public static EmbeddingDefinitionComparisonResult Unequal(FailedEmbeddingDefinitionComparisonReason reason) - => new(reason); - - /// - /// Initializes a new instance of the class. - /// - EmbeddingDefinitionComparisonResult() => Succeeded = true; - - /// - /// Initializes a new instance of the class. - /// - /// The . - EmbeddingDefinitionComparisonResult(FailedEmbeddingDefinitionComparisonReason reason) => FailureReason = reason; - - /// - /// Gets a value indicating whether the validation succeeded or not. - /// - public bool Succeeded { get; } - - /// - /// Gets the . - /// - public FailedEmbeddingDefinitionComparisonReason FailureReason { get; } -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/EmbeddingFailures.cs b/Source/Embeddings.Processing/EmbeddingFailures.cs deleted file mode 100644 index c9c50d7f1..000000000 --- a/Source/Embeddings.Processing/EmbeddingFailures.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Protobuf; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Holds the unique failure ids unique to the Embeddings. -/// -public static class EmbeddingFailures -{ - /// - /// Gets the that represents the 'NoEmbeddingRegistrationReceived' failure type. - /// - public static FailureId NoEmbeddingRegistrationReceived => FailureId.Create("bda8fb78-1cbb-4b1b-962c-eb8f90087bb0"); - - /// - /// Gets the that represents the 'NoEmbeddingRegisteredForTenant' failure type. - /// s - public static FailureId NoEmbeddingRegisteredForTenant => FailureId.Create("d76e5522-9bbd-4bb1-87df-b167e42acf02"); - - /// - /// Gets the that represents the 'FailedToRegisterEmbedding' failure type. - /// - public static FailureId FailedToRegisterEmbedding => FailureId.Create("77cd99ec-9939-43ae-83dc-3c770ef65a4c"); - - /// - /// Gets the that represents the 'FailedToUpdateEmbedding' failure type. - /// - public static FailureId FailedToUpdateEmbedding => FailureId.Create("4f765146-c635-497a-a14b-b7f80d5cf875"); - - /// - /// Gets the that represents the 'FailedToDeleteEmbedding' failure type. - /// - public static FailureId FailedToDeleteEmbedding => FailureId.Create("dcfba172-9348-4b2c-b518-17603798c0ec"); -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/EmbeddingLoopDetected.cs b/Source/Embeddings.Processing/EmbeddingLoopDetected.cs deleted file mode 100644 index 41adc9dfc..000000000 --- a/Source/Embeddings.Processing/EmbeddingLoopDetected.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Embeddings.Store; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Exception that gets thrown when a loop is detected in an embedding. -/// -public class EmbeddingLoopDetected : Exception -{ - /// - /// Initializes a new instance of the class. - /// - /// The - public EmbeddingLoopDetected(EmbeddingId embedding) - : base($"Embedding loop was detected for embedding {embedding.Value}") - { - } -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/EmbeddingLoopsDetector.cs b/Source/Embeddings.Processing/EmbeddingLoopsDetector.cs deleted file mode 100644 index 0a2008f7d..000000000 --- a/Source/Embeddings.Processing/EmbeddingLoopsDetector.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents an implementation of . -/// -public class EmbeddingLoopsDetector : IDetectEmbeddingLoops -{ - readonly ICompareStates _comparer; - - /// - /// Initializes a new instance of the class. - /// - /// The to use for comparing current and previous states. - public EmbeddingLoopsDetector(ICompareStates comparer) - { - _comparer = comparer; - } - - /// - public Try TryCheckForProjectionStateLoop(ProjectionState currentState, IEnumerable previousStates) - { - var equalityResults = previousStates.AsParallel() - .Select(previousState => _comparer.TryCheckEquality(previousState, currentState)) - // The query execution is deferred so need to call for ToList here - // https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/introduction-to-plinq#the-forall-operator - .ToList(); - var failure = equalityResults.FirstOrDefault(_ => !_.Success); - if (failure is not null) - { - return failure.Exception; - } - return equalityResults.Any(_ => _.Result); - } -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/EmbeddingProcessor.cs b/Source/Embeddings.Processing/EmbeddingProcessor.cs deleted file mode 100644 index 06f8838ab..000000000 --- a/Source/Embeddings.Processing/EmbeddingProcessor.cs +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Concurrent; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Aggregates; -using Dolittle.Runtime.DependencyInversion; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Embeddings.Store; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Projections.Store; -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Protobuf; -using Dolittle.Runtime.Rudimentary; -using Microsoft.Extensions.Logging; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; -using UncommittedAggregateEvents = Dolittle.Runtime.Events.Store.UncommittedAggregateEvents; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents an implementation of . -/// -[DisableAutoRegistration] -public class EmbeddingProcessor : IEmbeddingProcessor -{ - readonly ConcurrentQueue> _jobs = new(); - readonly EmbeddingId _embedding; - readonly TenantId _tenant; - readonly ExecutionContext _executionContext; - readonly IUpdateEmbeddingStates _stateUpdater; - readonly IStreamEventWatcher _eventWaiter; - readonly IEventStore _eventStore; - readonly IEmbeddingStore _embeddingStore; - readonly ICalculateStateTransitionEvents _transitionCalculator; - readonly ILogger _logger; - CancellationToken _cancellationToken; - CancellationTokenSource _waitForEvent; - bool _started; - - /// - /// Initializes a new instance of the class. - /// - /// The that identifies the embedding. - /// The that this processor is processing for. - /// The execution context to run the processor in. - /// The to use for recalculating embedding states from aggregate root events. - /// The to use for waiting on events to be committed to the event log. - /// The to use for fetching and committing aggregate root events. - /// The to use for fetching, replacing and removing embedding states. - /// The to use for calculating state transition events. - /// The . - public EmbeddingProcessor( - EmbeddingId embedding, - TenantId tenant, - ExecutionContext executionContext, - IUpdateEmbeddingStates stateUpdater, - IStreamEventWatcher eventWaiter, - IEventStore eventStore, - IEmbeddingStore embeddingStore, - ICalculateStateTransitionEvents transitionCalculator, - ILogger logger) - { - _embedding = embedding; - _tenant = tenant; - _executionContext = CreateExecutionContextForProcessor(executionContext, tenant); - _stateUpdater = stateUpdater; - _eventWaiter = eventWaiter; - _eventStore = eventStore; - _embeddingStore = embeddingStore; - _transitionCalculator = transitionCalculator; - _logger = logger; - } - - /// - public Task Start(CancellationToken cancellationToken) - { - if (HasStarted()) - { - return Task.FromResult(new EmbeddingProcessorAlreadyStarted(_embedding)); - } - _started = true; - _cancellationToken = cancellationToken; - return Task.Run(Loop, cancellationToken); - } - - /// - public async Task> Update(ProjectionKey key, ProjectionState state, ExecutionContext executionContext, CancellationToken cancellationToken) - => (await ScheduleJob(() => DoWork( - key, - currentState => _transitionCalculator.TryConverge(currentState, state, executionContext, cancellationToken), - aggregateRootVersion => _embeddingStore.TryReplace(_embedding, key, aggregateRootVersion, state, cancellationToken), - executionContext, - cancellationToken), - executionContext) - .ConfigureAwait(false)) - .With(state); - - /// - public Task Delete(ProjectionKey key, ExecutionContext executionContext, CancellationToken cancellationToken) - => ScheduleJob(() => DoWork( - key, - currentState => _transitionCalculator.TryDelete(currentState, executionContext, cancellationToken), - aggregateRootVersion => _embeddingStore.TryRemove(_embedding, key, aggregateRootVersion, cancellationToken), - executionContext, - cancellationToken), - executionContext); - - async Task Loop() - { - try - { - while (!_cancellationToken.IsCancellationRequested) - { - var tryRefresh = await EnsureAllStatesAreFresh().ConfigureAwait(false); - if (!tryRefresh.Success) - { - return tryRefresh; - } - - await WaitForEventOrJob().ConfigureAwait(false); - await PerformNextJobs().ConfigureAwait(false); - } - } - catch (Exception ex) - { - return ex; - } - finally - { - await CancelRemainingJobs().ConfigureAwait(false); - } - return Try.Succeeded(); - } - - async Task DoWork( - ProjectionKey key, - Func>> getUncommittedEvents, - Func> replaceOrRemoveEmbedding, - ExecutionContext executionContext, - CancellationToken cancellationToken) - { - try - { - if (cancellationToken.IsCancellationRequested) - { - _logger.EventProcessorWorkWasCancelled(_embedding, key); - return new OperationCanceledException(); - } - - var currentState = await _embeddingStore.TryGet(_embedding, key, cancellationToken).ConfigureAwait(false); - if (!currentState.Success) - { - return currentState.Exception; - } - var uncommittedEvents = await getUncommittedEvents(currentState.Result).ConfigureAwait(false); - if (!uncommittedEvents.Success) - { - return uncommittedEvents.Exception; - } - if (uncommittedEvents.Result.Count <= 0) - { - return Try.Succeeded(); - } - _logger.CommittingTransitionEvents(_embedding, key, uncommittedEvents); - var response = await _eventStore.CommitAggregateEvents(uncommittedEvents.Result.ToCommitRequest(executionContext), cancellationToken).ConfigureAwait(false); - if (response.Failure != default) - { - return new FailedToCommitEmbeddingEvents(response.Failure.ToFailure()); - } - - var committedEvents = response.Events.ToCommittedEvents(); - await replaceOrRemoveEmbedding(committedEvents.AggregateRootVersion).ConfigureAwait(false); - return Try.Succeeded(); - } - catch (Exception ex) - { - - _logger.EventProcessorWorkFailed(_embedding, key, ex); - return ex; - } - } - - async Task WaitForEventOrJob() - { - _waitForEvent?.Dispose(); - _waitForEvent = null; - if (_jobs.TryPeek(out var _)) - { - return; - } - _waitForEvent = CancellationTokenSource.CreateLinkedTokenSource(_cancellationToken); - try - { - await _eventWaiter.WaitForEvent(ScopeId.Default, StreamId.EventLog, _waitForEvent.Token); - } - catch (TaskCanceledException) - { - // An job has been scheduled - } - } - - Task ScheduleJob(Func> job, ExecutionContext requestExecutionContext) - { - if (_cancellationToken.IsCancellationRequested) - { - return Task.FromResult(new OperationCanceledException()); - } - - if (requestExecutionContext.Tenant != _tenant) - { - throw new EmbeddingRequestWorkScheduledForWrongTenant(requestExecutionContext.Tenant, _tenant); - } - - var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - _jobs.Enqueue(async shouldRun => - { - if (!shouldRun || _cancellationToken.IsCancellationRequested) - { - completionSource.SetResult(new OperationCanceledException()); - } - else - { - var result = await job().ConfigureAwait(false); - completionSource.SetResult(result); - } - }); - _waitForEvent?.Cancel(); - return completionSource.Task; - } - - async Task PerformNextJobs() - { - while (_jobs.TryDequeue(out var job)) - { - await job(true).ConfigureAwait(false); - } - } - - async Task CancelRemainingJobs() - { - while (_jobs.TryDequeue(out var job)) - { - await job(false).ConfigureAwait(false); - } - } - - async Task EnsureAllStatesAreFresh() - { - var result = await _stateUpdater.TryUpdateAll(_executionContext, _cancellationToken).ConfigureAwait(false); - if (!result.Success) - { - _logger.FailedEnsuringAllStatesAreFresh(_embedding, result.Exception); - } - return result; - } - - bool HasStarted() => _started; - - static ExecutionContext CreateExecutionContextForProcessor(ExecutionContext registrationContext, TenantId tenant) - => registrationContext with - { - Tenant = tenant, - // TODO: Does this make sense? - }; -} diff --git a/Source/Embeddings.Processing/EmbeddingProcessorAlreadyStarted.cs b/Source/Embeddings.Processing/EmbeddingProcessorAlreadyStarted.cs deleted file mode 100644 index 9d90e3db0..000000000 --- a/Source/Embeddings.Processing/EmbeddingProcessorAlreadyStarted.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Embeddings.Store; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Exception that gets thrown when starting an more than once. -/// -public class EmbeddingProcessorAlreadyStarted : Exception -{ - /// - /// Initializes a new instance of the class. - /// - /// The - public EmbeddingProcessorAlreadyStarted(EmbeddingId embedding) - : base($"EmbeddingProcessor for embedding {embedding.Value} is already started") - { - } -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/EmbeddingProcessorFactory.cs b/Source/Embeddings.Processing/EmbeddingProcessorFactory.cs deleted file mode 100644 index 1247e9c29..000000000 --- a/Source/Embeddings.Processing/EmbeddingProcessorFactory.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.DependencyInversion.Lifecycle; -using Dolittle.Runtime.DependencyInversion.Scoping; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Embeddings.Store; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Execution; -using Dolittle.Runtime.Projections.Store.State; -using Microsoft.Extensions.Logging; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents an implementation of . -/// -[Singleton, PerTenant] -public class EmbeddingProcessorFactory : IEmbeddingProcessorFactory -{ - readonly TenantId _tenant; - readonly IEventStore _eventStore; - readonly IFetchCommittedEvents _committedEventsFetcher; - readonly IEmbeddingStore _embeddingStore; - readonly IStreamEventWatcher _streamEventWatcher; - readonly ICompareStates _stateComparer; - readonly IDetectEmbeddingLoops _loopDetector; - readonly ILoggerFactory _loggerFactory; - - /// - /// Initializes an instance of the class. - /// - public EmbeddingProcessorFactory( - TenantId tenant, - IEventStore eventStore, - IFetchCommittedEvents committedEventsFetcher, - IEmbeddingStore embeddingStore, - IStreamEventWatcher streamEventWatcher, - ICompareStates stateComparer, - IDetectEmbeddingLoops loopDetector, - ILoggerFactory loggerFactory - ) - { - _tenant = tenant; - _eventStore = eventStore; - _committedEventsFetcher = committedEventsFetcher; - _embeddingStore = embeddingStore; - _streamEventWatcher = streamEventWatcher; - _stateComparer = stateComparer; - _loopDetector = loopDetector; - _loggerFactory = loggerFactory; - } - - /// - public IEmbeddingProcessor Create(EmbeddingId embeddingId, IEmbedding embedding, ProjectionState initialState, ExecutionContext executionContext) - { - var projectManyEvents = CreateProjectManyEvents(embeddingId, embedding, initialState); - - return new EmbeddingProcessor( - embeddingId, - _tenant, - executionContext, - CreateEmbeddingStateUpdater(embeddingId, projectManyEvents), - _streamEventWatcher, - _eventStore, - _embeddingStore, - CreateStateTransitionEventsCalculator(embeddingId, embedding, projectManyEvents), - _loggerFactory.CreateLogger()); - } - - EmbeddingStateUpdater CreateEmbeddingStateUpdater(EmbeddingId embeddingId, IProjectManyEvents projectManyEvents) - => new(embeddingId, _committedEventsFetcher, _embeddingStore, projectManyEvents, _loggerFactory.CreateLogger()); - - StateTransitionEventsCalculator CreateStateTransitionEventsCalculator(EmbeddingId embeddingId, IEmbedding embedding, IProjectManyEvents projectManyEvents) - => new(embeddingId, embedding, projectManyEvents, _stateComparer, _loopDetector, _loggerFactory.CreateLogger()); - - ProjectManyEvents CreateProjectManyEvents(EmbeddingId embeddingId, IEmbedding embedding, ProjectionState initialState) - => new(embeddingId, embedding, initialState, _loggerFactory.CreateLogger()); -} diff --git a/Source/Embeddings.Processing/EmbeddingProcessorNotStarted.cs b/Source/Embeddings.Processing/EmbeddingProcessorNotStarted.cs deleted file mode 100644 index c51fe6e29..000000000 --- a/Source/Embeddings.Processing/EmbeddingProcessorNotStarted.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Embeddings.Store; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Exception that gets thrown when performing operations on an that is not started. -/// -public class EmbeddingProcessorNotStarted : Exception -{ - /// - /// Initializes a new instance of the class. - /// - /// The - public EmbeddingProcessorNotStarted(EmbeddingId embedding) - : base($"EmbeddingProcessor for embedding {embedding.Value} is not started") - { - } -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/EmbeddingProcessors.cs b/Source/Embeddings.Processing/EmbeddingProcessors.cs deleted file mode 100644 index 19bb36616..000000000 --- a/Source/Embeddings.Processing/EmbeddingProcessors.cs +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.DependencyInversion.Lifecycle; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Embeddings.Store; -using Dolittle.Runtime.Rudimentary; -using Dolittle.Runtime.Tenancy; -using Microsoft.Extensions.Logging; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents an implementation of . -/// -[Singleton] -public class EmbeddingProcessors : IEmbeddingProcessors -{ - readonly ConcurrentDictionary> _processors = new(); - readonly ITenants _tenants; - readonly ILogger _logger; - - /// - /// Initializes a new instance of the class. - /// - /// The to use to get all configured tenants. - /// The to use. - public EmbeddingProcessors(ITenants tenants, ILogger logger) - { - _tenants = tenants; - _logger = logger; - } - - /// - public async Task TryStartEmbeddingProcessorForAllTenants(EmbeddingId embedding, CreateEmbeddingProcessorForTenant factory, CancellationToken cancellationToken) - { - _logger.StartingEmbeddiingProcessorForAllTenants(embedding); - if (!TryRegisterAndCreateProcessors(embedding, factory, out var processors, out var error)) - { - _logger.FailedRegisteringEmbeddingProcessor(embedding, error); - return error; - } - - var tryStartProcessors = await TryStartAndWaitForAllProcessorsToFinish( - embedding, - processors.Select(_ => _.Value), - cancellationToken).ConfigureAwait(false); - _processors.TryRemove(embedding, out var _); - return tryStartProcessors; - } - - /// - public bool HasEmbeddingProcessors(EmbeddingId embedding) => _processors.ContainsKey(embedding); - - /// - public bool TryGetEmbeddingProcessorFor(TenantId tenant, EmbeddingId embedding, out IEmbeddingProcessor processor) - { - if (_processors.TryGetValue(embedding, out var processorsByTenant)) - { - return processorsByTenant.TryGetValue(tenant, out processor); - } - - processor = null; - return false; - } - - bool TryRegisterAndCreateProcessors(EmbeddingId embedding, CreateEmbeddingProcessorForTenant createProcessor, out Dictionary processors, out Exception error) - { - try - { - error = null; - processors = new Dictionary(); - if (!_processors.TryAdd(embedding, processors)) - { - processors = null; - error = new EmbeddingProcessorsAlreadyRegistered(embedding); - return false; - } - foreach (var tenant in _tenants.All) - { - processors.Add(tenant, createProcessor(tenant)); - } - return true; - } - catch (Exception ex) - { - processors = null; - error = ex; - return false; - } - } - - async Task TryStartAndWaitForAllProcessorsToFinish(EmbeddingId embedding, IEnumerable processors, CancellationToken cancellationToken) - { - using var tokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - try - { - var tasks = processors.Select(_ => _.Start(tokenSource.Token)).ToList(); - _logger.EmbeddingProcessorsStarted(embedding); - var finishedTask = await Task.WhenAny(tasks).ConfigureAwait(false); - _logger.StoppingAllEmbeddingProcessors(embedding); - tokenSource.Cancel(); - await Task.WhenAll(tasks).ConfigureAwait(false); - _logger.AllEmbeddingProcessorsSuccessfullyStopped(embedding); - return await finishedTask.ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.AnErrorOccurredWhileStartingOrStoppingEmbedding(embedding, ex); - return ex; - } - finally - { - if (!tokenSource.IsCancellationRequested) - { - tokenSource.Cancel(); - } - } - } -} diff --git a/Source/Embeddings.Processing/EmbeddingProcessorsAlreadyRegistered.cs b/Source/Embeddings.Processing/EmbeddingProcessorsAlreadyRegistered.cs deleted file mode 100644 index d02ae1316..000000000 --- a/Source/Embeddings.Processing/EmbeddingProcessorsAlreadyRegistered.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Embeddings.Store; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Exception that gets thrown when trying to register an embedding more than once. -/// -public class EmbeddingProcessorsAlreadyRegistered : Exception -{ - /// - /// Initializes a new instance of the class. - /// - /// The - public EmbeddingProcessorsAlreadyRegistered(EmbeddingId embedding) - : base($"EmbeddingProcessor for embedding {embedding.Value} is already registered") - { - } -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/EmbeddingRegistrationArguments.cs b/Source/Embeddings.Processing/EmbeddingRegistrationArguments.cs deleted file mode 100644 index c7b345cc1..000000000 --- a/Source/Embeddings.Processing/EmbeddingRegistrationArguments.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Embeddings.Store.Definition; -using Dolittle.Runtime.Execution; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents the runtime representation of the embedding registration arguments. -/// -/// The execution context. -/// The embedding definition. -public record EmbeddingRegistrationArguments(ExecutionContext ExecutionContext, EmbeddingDefinition Definition); \ No newline at end of file diff --git a/Source/Embeddings.Processing/EmbeddingRemoteCompareCallFailed.cs b/Source/Embeddings.Processing/EmbeddingRemoteCompareCallFailed.cs deleted file mode 100644 index 39b239f1e..000000000 --- a/Source/Embeddings.Processing/EmbeddingRemoteCompareCallFailed.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Embeddings.Store; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Exception that gets thrown when a failure occurs in the head while handling a compare embedding call. -/// -public class EmbeddingRemoteCompareCallFailed : Exception -{ - /// - /// Initializes a new instance of the class. - /// - /// The - public EmbeddingRemoteCompareCallFailed(EmbeddingId embedding, string reason) - : base($"A failure occurred during the remote Compare call for embedding {embedding.Value}. {reason}") - { - } -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/EmbeddingRemoteDeleteCallFailed.cs b/Source/Embeddings.Processing/EmbeddingRemoteDeleteCallFailed.cs deleted file mode 100644 index 67aa4aebb..000000000 --- a/Source/Embeddings.Processing/EmbeddingRemoteDeleteCallFailed.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Embeddings.Store; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Exception that gets thrown when a failure occurs in the head while handling a delete embedding call. -/// -public class EmbeddingRemoteDeleteCallFailed : Exception -{ - /// - /// Initializes a new instance of the class. - /// - /// The - public EmbeddingRemoteDeleteCallFailed(EmbeddingId embedding, string reason) - : base($"A failure occurred during the remote Delete call for embedding {embedding.Value}. {reason}") - { - } -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/EmbeddingRequestFactory.cs b/Source/Embeddings.Processing/EmbeddingRequestFactory.cs deleted file mode 100644 index b66dc4245..000000000 --- a/Source/Embeddings.Processing/EmbeddingRequestFactory.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Embeddings.Contracts; -using Dolittle.Runtime.Embeddings.Store; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Processing.Projections; -using Dolittle.Runtime.Protobuf; -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents an implementation of . -/// -public class EmbeddingRequestFactory : IEmbeddingRequestFactory -{ - /// - public EmbeddingRequest Create(ProjectionCurrentState current, UncommittedEvent @event) - => new() - { - Projection = new EmbeddingProjectRequest - { - CurrentState = current.ToProtobuf(), - Event = new Events.Contracts.UncommittedEvent - { - EventType = @event.Type.ToProtobuf(), - Content = @event.Content, - EventSourceId = @event.EventSource.Value, - Public = @event.Public, - } - } - }; - - /// - public EmbeddingRequest Create(EmbeddingCurrentState current, ProjectionState desiredState) - => new() - { - Compare = new EmbeddingCompareRequest - { - ProjectionState = current.ToProtobuf(), - EntityState = desiredState - } - }; - - /// - public EmbeddingRequest Create(EmbeddingCurrentState current) - => new() - { - Delete = new EmbeddingDeleteRequest - { - ProjectionState = current.ToProtobuf() - } - }; - - /// - public Try TryCreate(ProjectionCurrentState current, UncommittedEvent @event) - => Try.Do(() => Create(current, @event)); - - /// - public Try TryCreate(EmbeddingCurrentState current, ProjectionState desiredState) - => Try.Do(() => Create(current, desiredState)); - - /// - public Try TryCreate(EmbeddingCurrentState current) - => Try.Do(() => Create(current)); -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/EmbeddingRequestWorkScheduledForWrongTenant.cs b/Source/Embeddings.Processing/EmbeddingRequestWorkScheduledForWrongTenant.cs deleted file mode 100644 index 53f7b39c5..000000000 --- a/Source/Embeddings.Processing/EmbeddingRequestWorkScheduledForWrongTenant.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Domain.Tenancy; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Exception that gets thrown when the processing of an embedding request is scheduled on the of the wrong tenant. -/// -public class EmbeddingRequestWorkScheduledForWrongTenant : Exception -{ - /// - /// Initializes a new instance of the class. - /// - /// The tenant that the request was for. - /// The tenant that the embedding processor is running for. - public EmbeddingRequestWorkScheduledForWrongTenant(TenantId requestTenant, TenantId loopTenant) - : base($"The processing of an embedding request for tenant {requestTenant} was scheduled on the embedding processor for tenant {loopTenant}") - { - } -} diff --git a/Source/Embeddings.Processing/EmbeddingStateUpdater.cs b/Source/Embeddings.Processing/EmbeddingStateUpdater.cs deleted file mode 100644 index 8991d8363..000000000 --- a/Source/Embeddings.Processing/EmbeddingStateUpdater.cs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Aggregates; -using Dolittle.Runtime.DependencyInversion; -using Dolittle.Runtime.Embeddings.Store; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Rudimentary; -using Dolittle.Runtime.Projections.Store; -using Microsoft.Extensions.Logging; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents an implementation of . -/// -[DisableAutoRegistration] -public class EmbeddingStateUpdater : IUpdateEmbeddingStates -{ - readonly EmbeddingId _embedding; - readonly IFetchCommittedEvents _committedEvents; - readonly IEmbeddingStore _embeddingStore; - readonly IProjectManyEvents _projectManyEvents; - readonly ILogger _logger; - - /// - /// Initializes a new instance of the class. - /// - /// The that identifies the embedding. - /// The that is used to fetch aggregate events. - /// The that is used to persist the states. - /// The . - public EmbeddingStateUpdater( - EmbeddingId embedding, - IFetchCommittedEvents committedEvents, - IEmbeddingStore embeddingStore, - IProjectManyEvents projectManyEvents, - ILogger logger) - { - _embedding = embedding; - _committedEvents = committedEvents; - _embeddingStore = embeddingStore; - _projectManyEvents = projectManyEvents; - _logger = logger; - } - - /// - public async Task TryUpdateAll(ExecutionContext executionContext, CancellationToken cancellationToken) - { - _logger.UpdatingAllEmbeddingStates(_embedding); - var keys = await _embeddingStore.TryGetKeys(_embedding, cancellationToken).ConfigureAwait(false); - if (!keys.Success) - { - return keys; - } - - var result = Try.Succeeded(); - foreach (var key in keys.Result) - { - _logger.UpdatingEmbeddingStateFor(_embedding, key); - var updateResult = await TryUpdateEmbedding(key, executionContext, cancellationToken).ConfigureAwait(false); - if (!updateResult.Success) - { - _logger.FailedUpdatingEmbeddingStateFor(_embedding, key, updateResult.Exception); - result = result.Success ? updateResult : result; - } - } - - return result; - } - - async Task TryUpdateEmbedding(ProjectionKey key, ExecutionContext executionContext, CancellationToken cancellationToken) - { - var currentState = await _embeddingStore.TryGet(_embedding, key, cancellationToken).ConfigureAwait(false); - if (!currentState.Success) - { - return currentState; - } - var unprocessedEvents = await TryGetUnprocessedEvents(key, currentState.Result.Version, cancellationToken).ConfigureAwait(false); - if (!unprocessedEvents.Success) - { - return Try.Failed(unprocessedEvents.Exception); - } - if (!unprocessedEvents.Result.Any()) - { - return Try.Succeeded(); - } - - var projectedState = await _projectManyEvents.TryProject(currentState, unprocessedEvents, executionContext, cancellationToken).ConfigureAwait(false); - if (projectedState.Success || projectedState.IsPartialResult) - { - var updateState = await TryUpdateOrDeleteState(projectedState.Result, cancellationToken).ConfigureAwait(false); - if (updateState.Success && projectedState.IsPartialResult) - { - return projectedState.Exception; - } - - return updateState; - } - - return Try.Failed(projectedState.Exception); - } - - Task TryUpdateOrDeleteState(EmbeddingCurrentState state, CancellationToken cancellationToken) - => state.Type == EmbeddingCurrentStateType.Deleted - ? _embeddingStore.TryRemove( - _embedding, - state.Key, - state.Version, - cancellationToken) - : _embeddingStore.TryReplace( - _embedding, - state.Key, - state.Version, - state.State, - cancellationToken); - - async Task> TryGetUnprocessedEvents(ProjectionKey key, AggregateRootVersion aggregateRootVersion, CancellationToken cancellationToken) - { - try - { - return await _committedEvents.FetchForAggregateAfter( - key.Value, - _embedding.Value, - aggregateRootVersion, - cancellationToken).ConfigureAwait(false); - } - catch (Exception ex) - { - return ex; - } - } -} diff --git a/Source/Embeddings.Processing/Embeddings.Processing.csproj b/Source/Embeddings.Processing/Embeddings.Processing.csproj deleted file mode 100644 index 6c30d8ecc..000000000 --- a/Source/Embeddings.Processing/Embeddings.Processing.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - - Dolittle.Runtime.Embeddings.Processing - Dolittle.Runtime.Embeddings.Processing - - - - - - - - - - - - - - - diff --git a/Source/Embeddings.Processing/EmbeddingsProtocol.cs b/Source/Embeddings.Processing/EmbeddingsProtocol.cs deleted file mode 100644 index 48586e1dd..000000000 --- a/Source/Embeddings.Processing/EmbeddingsProtocol.cs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Embeddings.Contracts; -using Dolittle.Runtime.Protobuf; -using Dolittle.Services.Contracts; -using Dolittle.Runtime.Services; -using Dolittle.Runtime.Embeddings.Store.Definition; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents the . -/// -public class EmbeddingsProtocol : IEmbeddingsProtocol -{ - /// - public EmbeddingRegistrationArguments ConvertConnectArguments(EmbeddingRegistrationRequest arguments) - => new( - arguments.CallContext.ExecutionContext.ToExecutionContext(), - new EmbeddingDefinition( - arguments.EmbeddingId.ToGuid(), - arguments.Events.Select(_ => _.ToArtifact()), - arguments.InitialState)); - - /// - public EmbeddingRegistrationResponse CreateFailedConnectResponse(FailureReason failureMessage) - => new() { Failure = new Dolittle.Protobuf.Contracts.Failure { Id = EmbeddingFailures.FailedToRegisterEmbedding.Value.ToProtobuf(), Reason = failureMessage } }; - - /// - public ReverseCallArgumentsContext GetArgumentsContext(EmbeddingRegistrationRequest message) - => message.CallContext; - - /// - public EmbeddingRegistrationRequest GetConnectArguments(EmbeddingClientToRuntimeMessage message) - => message.RegistrationRequest; - - /// - public Pong GetPong(EmbeddingClientToRuntimeMessage message) - => message.Pong; - - /// - public EmbeddingResponse GetResponse(EmbeddingClientToRuntimeMessage message) - => message.HandleResult; - - /// - public ReverseCallResponseContext GetResponseContext(EmbeddingResponse message) - => message.CallContext; - - /// - public void SetConnectResponse(EmbeddingRegistrationResponse arguments, EmbeddingRuntimeToClientMessage message) - => message.RegistrationResponse = arguments; - - /// - public void SetPing(EmbeddingRuntimeToClientMessage message, Ping ping) - => message.Ping = ping; - - /// - public void SetRequest(EmbeddingRequest request, EmbeddingRuntimeToClientMessage message) - => message.HandleRequest = request; - - /// - public void SetRequestContext(ReverseCallRequestContext context, EmbeddingRequest request) - => request.CallContext = context; - - /// - public ConnectArgumentsValidationResult ValidateConnectArguments(EmbeddingRegistrationArguments arguments) - { - foreach (var eventTypeGroup in arguments.Definition.Events.GroupBy(_ => _.Id)) - { - if (eventTypeGroup.Count() > 1) - { - return ConnectArgumentsValidationResult.Failed($"Event {eventTypeGroup.Key.Value} was specified more than once"); - } - } - return ConnectArgumentsValidationResult.Ok; - } -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/EmbeddingsService.cs b/Source/Embeddings.Processing/EmbeddingsService.cs deleted file mode 100644 index 8fc4d76ca..000000000 --- a/Source/Embeddings.Processing/EmbeddingsService.cs +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Threading.Tasks; -using Dolittle.Runtime.Execution; -using Microsoft.Extensions.Logging; -using Dolittle.Runtime.Services; -using Grpc.Core; -using Microsoft.Extensions.Hosting; -using Dolittle.Runtime.Embeddings.Contracts; -using Dolittle.Runtime.Protobuf; -using System.Threading; -using Dolittle.Runtime.Rudimentary; -using Dolittle.Runtime.Embeddings.Store; -using Dolittle.Runtime.Embeddings.Store.Definition; -using System.Linq; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Services.Hosting; -using static Dolittle.Runtime.Embeddings.Contracts.Embeddings; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents the implementation of . -/// -[PrivateService] -public class EmbeddingsService : EmbeddingsBase -{ - readonly IInitiateReverseCallServices _reverseCallServices; - readonly IEmbeddingsProtocol _protocol; - readonly Func _getEmbeddingProcessorFactoryFor; - readonly IEmbeddingProcessors _embeddingProcessors; - readonly ICompareEmbeddingDefinitionsForAllTenants _embeddingDefinitionComparer; - readonly IPersistEmbeddingDefinitionForAllTenants _embeddingDefinitionPersister; - readonly IEmbeddingRequestFactory _embeddingRequestFactory; - readonly ILoggerFactory _loggerFactory; - readonly ILogger _logger; - readonly IHostApplicationLifetime _hostApplicationLifetime; - readonly ICreateExecutionContexts _executionContextCreator; - - /// - /// Initializes an instance of the class. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public EmbeddingsService( - IHostApplicationLifetime hostApplicationLifetime, - ICreateExecutionContexts executionContextCreator, - IInitiateReverseCallServices reverseCallServices, - IEmbeddingsProtocol protocol, - Func getEmbeddingProcessorFactoryFor, - IEmbeddingProcessors embeddingProcessors, - ICompareEmbeddingDefinitionsForAllTenants embeddingDefinitionComparer, - IPersistEmbeddingDefinitionForAllTenants embeddingDefinitionPersister, - IEmbeddingRequestFactory embeddingRequestFactory, - ILoggerFactory loggerFactory) - { - _hostApplicationLifetime = hostApplicationLifetime; - _executionContextCreator = executionContextCreator; - _reverseCallServices = reverseCallServices; - _protocol = protocol; - _getEmbeddingProcessorFactoryFor = getEmbeddingProcessorFactoryFor; - _embeddingProcessors = embeddingProcessors; - _embeddingDefinitionComparer = embeddingDefinitionComparer; - _embeddingDefinitionPersister = embeddingDefinitionPersister; - _embeddingRequestFactory = embeddingRequestFactory; - _loggerFactory = loggerFactory; - _logger = loggerFactory.CreateLogger(); - } - - /// - public override async Task Connect( - IAsyncStreamReader runtimeStream, - IServerStreamWriter clientStream, - ServerCallContext context) - { - // TODO: It seems like things are not properly unregistered on exceptions? - // TODO: I tested this out and while making the DI container work, it kept failing and telling me that the projection was already registered on the second attempt. - - Log.ConnectingEmbeddings(_logger); - using var cts = CancellationTokenSource.CreateLinkedTokenSource(_hostApplicationLifetime.ApplicationStopping, context.CancellationToken); - var connection = await _reverseCallServices.Connect(runtimeStream, clientStream, context, _protocol, context.CancellationToken).ConfigureAwait(false); - if (!connection.Success) - { - return; - } - using var dispatcher = connection.Result.dispatcher; - var arguments = connection.Result.arguments; - - var tryCreateExecutionContext = _executionContextCreator.TryCreateUsing(arguments.ExecutionContext); - if (!tryCreateExecutionContext.Success) - { - await dispatcher.Reject( - _protocol.CreateFailedConnectResponse($"Failed to register embedding because the execution context is invalid: ${tryCreateExecutionContext.Exception.Message}"), - cts.Token).ConfigureAwait(false); - return; - } - - var executionContext = tryCreateExecutionContext.Result; // TODO: Use this - - if (_embeddingProcessors.HasEmbeddingProcessors(arguments.Definition.Embedding)) - { - await dispatcher.Reject( - _protocol.CreateFailedConnectResponse($"Failed to register Embedding: {arguments.Definition.Embedding.Value}. Embedding already registered with the same id"), - cts.Token).ConfigureAwait(false); - return; - } - - if (await RejectIfInvalidDefinition(arguments.Definition, dispatcher, cts.Token).ConfigureAwait(false)) - { - return; - } - var persistDefinition = await _embeddingDefinitionPersister.TryPersist(arguments.Definition, cts.Token).ConfigureAwait(false); - if (!persistDefinition.Success) - { - await dispatcher.Reject( - _protocol.CreateFailedConnectResponse($"Failed to register Embedding: {arguments.Definition.Embedding.Value}. Failed to persist embedding definition. {persistDefinition.Exception.Message}"), - cts.Token).ConfigureAwait(false); - return; - } - - var dispatcherTask = dispatcher.Accept(new EmbeddingRegistrationResponse(), cts.Token); - var processorTask = _embeddingProcessors.TryStartEmbeddingProcessorForAllTenants( - arguments.Definition.Embedding, - tenant => _getEmbeddingProcessorFactoryFor(tenant) - .Create( - arguments.Definition.Embedding, - new Embedding( - arguments.Definition.Embedding, - dispatcher, - _embeddingRequestFactory, - _loggerFactory.CreateLogger()), - arguments.Definition.InititalState, - executionContext), - cts.Token); - - - var tasks = new TaskGroup(dispatcherTask, processorTask); - await tasks.WaitForAllCancellingOnFirst(cts).ConfigureAwait(false); - } - - /// - public override async Task Update(UpdateRequest request, ServerCallContext context) - { - using var cts = CancellationTokenSource.CreateLinkedTokenSource(_hostApplicationLifetime.ApplicationStopping, context.CancellationToken); - - var tryCreateExecutionContext = _executionContextCreator.TryCreateUsing(request.CallContext.ExecutionContext); - if (!tryCreateExecutionContext.Success) - { - return new UpdateResponse - { - Failure = new Dolittle.Protobuf.Contracts.Failure - { - Id = EmbeddingFailures.FailedToUpdateEmbedding.ToProtobuf(), - Reason = $"Failed to update embedding {request.EmbeddingId.ToGuid()} because the execution context was invalid: {tryCreateExecutionContext.Exception.Message}" - } - }; - } - - var executionContext = tryCreateExecutionContext.Result; - if (!TryGetRegisteredEmbeddingProcessorForTenant(executionContext.Tenant, request.EmbeddingId.ToGuid(), out var processor, out var failure)) - { - return new UpdateResponse - { - Failure = failure - }; - } - var newState = await processor.Update(request.Key, request.State, executionContext, cts.Token).ConfigureAwait(false); - if (!newState.Success) - { - return new UpdateResponse - { - Failure = new Dolittle.Protobuf.Contracts.Failure - { - Id = EmbeddingFailures.FailedToUpdateEmbedding.ToProtobuf(), - Reason = $"Failed to update embedding {request.EmbeddingId.ToGuid()} for tenant {executionContext.Tenant} with key {request.Key}. {newState.Exception.Message}" - } - }; - } - return new UpdateResponse - { - State = new Projections.Contracts.ProjectionCurrentState - { - Type = Projections.Contracts.ProjectionCurrentStateType.Persisted, - Key = request.Key, - State = newState.Result - } - }; - } - - public override async Task Delete(DeleteRequest request, ServerCallContext context) - { - using var cts = CancellationTokenSource.CreateLinkedTokenSource(_hostApplicationLifetime.ApplicationStopping, context.CancellationToken); - - var tryCreateExecutionContext = _executionContextCreator.TryCreateUsing(request.CallContext.ExecutionContext); - if (!tryCreateExecutionContext.Success) - { - return new DeleteResponse - { - Failure = new Dolittle.Protobuf.Contracts.Failure - { - Id = EmbeddingFailures.FailedToUpdateEmbedding.ToProtobuf(), - Reason = $"Failed to delete embedding {request.EmbeddingId.ToGuid()} because the execution context was invalid: {tryCreateExecutionContext.Exception.Message}" - } - }; - } - - var executionContext = tryCreateExecutionContext.Result; - if (!TryGetRegisteredEmbeddingProcessorForTenant(executionContext.Tenant, request.EmbeddingId.ToGuid(), out var processor, out var failure)) - { - return new DeleteResponse - { - Failure = failure - }; - } - var deleteEmbedding = await processor.Delete(request.Key, executionContext, cts.Token).ConfigureAwait(false); - if (!deleteEmbedding.Success) - { - return new DeleteResponse - { - Failure = new Dolittle.Protobuf.Contracts.Failure - { - Id = EmbeddingFailures.FailedToDeleteEmbedding.ToProtobuf(), - Reason = $"Failed to delete embedding {request.EmbeddingId.ToGuid()} for tenant {executionContext.Tenant}. {deleteEmbedding.Exception.Message}" - } - }; - } - - return new DeleteResponse(); - } - - bool TryGetRegisteredEmbeddingProcessorForTenant(TenantId tenant, EmbeddingId embedding, out IEmbeddingProcessor processor, out Failure failure) - { - failure = default; - if (!_embeddingProcessors.TryGetEmbeddingProcessorFor(tenant, embedding, out processor)) - { - failure = new Dolittle.Protobuf.Contracts.Failure - { - Id = EmbeddingFailures.NoEmbeddingRegisteredForTenant.ToProtobuf(), - Reason = $"No embedding with id {embedding.Value} registered for tenant {tenant.Value}" - }; - return false; - } - return true; - } - - async Task RejectIfInvalidDefinition( - EmbeddingDefinition definition, - IReverseCallDispatcher dispatcher, - CancellationToken cancellationToken) - { - _logger.ComparingEmbeddingDefinition(definition); - var tenantsAndComparisonResult = await _embeddingDefinitionComparer.DiffersFromPersisted( - new EmbeddingDefinition( - definition.Embedding, - definition.Events, - definition.InititalState), - cancellationToken).ConfigureAwait(false); - - if (tenantsAndComparisonResult.Values.All(_ => _.Succeeded)) - { - return false; - } - - var unsuccessfulComparisons = tenantsAndComparisonResult - .Where(_ => !_.Value.Succeeded) - .Select(_ => (_.Key, _.Value)); - - _logger.InvalidEmbeddingDefinition(definition, unsuccessfulComparisons); - - await dispatcher.Reject(CreateInvalidValidationResponse( - unsuccessfulComparisons, - definition.Embedding), - cancellationToken).ConfigureAwait(false); - - - return true; - } - EmbeddingRegistrationResponse CreateInvalidValidationResponse( - System.Collections.Generic.IEnumerable<(TenantId Key, EmbeddingDefinitionComparisonResult Value)> unsuccessfulComparisons, - EmbeddingId embedding) - { - var (_, result) = unsuccessfulComparisons.First(); - return _protocol.CreateFailedConnectResponse($"Failed to register Embedding: {embedding.Value} for tenant. {result.FailureReason.Value}"); - } -} diff --git a/Source/Embeddings.Processing/FailedEmbeddingDefinitionComparisonReason.cs b/Source/Embeddings.Processing/FailedEmbeddingDefinitionComparisonReason.cs deleted file mode 100644 index 4defcb1da..000000000 --- a/Source/Embeddings.Processing/FailedEmbeddingDefinitionComparisonReason.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents the reason for why the comparison of a failed. -/// -public record FailedEmbeddingDefinitionComparisonReason(string Value) : ConceptAs(Value) -{ - /// - /// Implicitly converts to . - /// - /// The value. - public static implicit operator FailedEmbeddingDefinitionComparisonReason(string reason) => new(reason); -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/FailedPersistingEmbeddingDefinition.cs b/Source/Embeddings.Processing/FailedPersistingEmbeddingDefinition.cs deleted file mode 100644 index 7f7eb1747..000000000 --- a/Source/Embeddings.Processing/FailedPersistingEmbeddingDefinition.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Embeddings.Store; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Exception that gets thrown when embedding defintion persisting failed. -/// -public class FailedPersistingEmbeddingDefinition : Exception -{ - /// - /// Initializes a new instance of the class. - /// - /// The - public FailedPersistingEmbeddingDefinition(EmbeddingId embedding) - : base($"A failure occurred while persisting definition for embedding {embedding.Value}") - { - } -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/FailedProjectingEvents.cs b/Source/Embeddings.Processing/FailedProjectingEvents.cs deleted file mode 100644 index c765193b7..000000000 --- a/Source/Embeddings.Processing/FailedProjectingEvents.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Embeddings.Store; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Exception that gets thrown when no events could be projected. -/// -public class FailedProjectingEvents : Exception -{ - /// - /// Initializes a new instance of the class. - /// - /// The - /// The inner - public FailedProjectingEvents(EmbeddingId embedding, Exception inner) - : base($"A failure occurred while projecting events for embedding {embedding.Value}", inner) - { - } -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/FailedToCommitEmbeddingEvents.cs b/Source/Embeddings.Processing/FailedToCommitEmbeddingEvents.cs deleted file mode 100644 index 0e6796eb8..000000000 --- a/Source/Embeddings.Processing/FailedToCommitEmbeddingEvents.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Protobuf; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Exception that gets thrown when embedding events failed to be committed. -/// -public class FailedToCommitEmbeddingEvents : Exception -{ - /// - /// Initializes a new instance of the class. - /// - /// The . - public FailedToCommitEmbeddingEvents(Failure failure) - : base($"Failed to commit embedding events because {failure}") - {} -} diff --git a/Source/Embeddings.Processing/ICalculateStateTransitionEvents.cs b/Source/Embeddings.Processing/ICalculateStateTransitionEvents.cs deleted file mode 100644 index 228136bca..000000000 --- a/Source/Embeddings.Processing/ICalculateStateTransitionEvents.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Embeddings.Store; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Rudimentary; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Defines a system that can calculate the events that needs to be committed in order to do a state transition from a current to a desired . -/// -public interface ICalculateStateTransitionEvents -{ - /// - /// Try to calculate the events necessary to transition from the current state to a desired state. - /// - /// The to transition from. - /// The to transition to. - /// The execution context to execute the update operation in. - /// The . - /// A that, when resolved, returns of . - Task> TryConverge(EmbeddingCurrentState current, ProjectionState desired, ExecutionContext executionContext, CancellationToken cancellationToken); - - /// - /// Try to calculate the events necessary to delete the current state. - /// - /// The to delete. - /// The execution context to execute the delete operation in. - /// The . - /// A that, when resolved, returns of . - Task> TryDelete(EmbeddingCurrentState current, ExecutionContext executionContext, CancellationToken cancellationToken); -} diff --git a/Source/Embeddings.Processing/ICompareEmbeddingDefinitionsForAllTenants.cs b/Source/Embeddings.Processing/ICompareEmbeddingDefinitionsForAllTenants.cs deleted file mode 100644 index 2d4a40428..000000000 --- a/Source/Embeddings.Processing/ICompareEmbeddingDefinitionsForAllTenants.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Embeddings.Store.Definition; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Defines a system that can compare a embedding definition from an embedding registration with the persisted definition. -/// -public interface ICompareEmbeddingDefinitionsForAllTenants -{ - /// - /// Checks whether the given differs from the persisted definition. - /// - /// The to compare. - /// The . - /// A that, when resolved, returns a value indicating whether the differs from the persisted definition. - Task> DiffersFromPersisted(EmbeddingDefinition definition, CancellationToken token); -} diff --git a/Source/Embeddings.Processing/ICompareStates.cs b/Source/Embeddings.Processing/ICompareStates.cs deleted file mode 100644 index 1a0c2dfa0..000000000 --- a/Source/Embeddings.Processing/ICompareStates.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Defines a system that can compare instances . -/// -public interface ICompareStates -{ - /// - /// Tries to compare two projection states to determine equality. Doesn't care about the ordering of - /// properties or dictionary keys, but will fail on differently ordered arrays. - /// - /// The first to compare. - /// The second to compare. - /// A of true if they are equal, false if not. - Try TryCheckEquality(ProjectionState left, ProjectionState right); -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/IDetectEmbeddingLoops.cs b/Source/Embeddings.Processing/IDetectEmbeddingLoops.cs deleted file mode 100644 index 9e60f74b8..000000000 --- a/Source/Embeddings.Processing/IDetectEmbeddingLoops.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Defines a system that can detect loops in the logic of an . -/// -public interface IDetectEmbeddingLoops -{ - /// - /// Try to check if a projection's state is equal to one of it's previous states. - /// - /// The current . - /// An of the previous states. - /// A that indicates whether the operation was successful or not. - Try TryCheckForProjectionStateLoop(ProjectionState currentState, IEnumerable previousStates); -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/IEmbedding.cs b/Source/Embeddings.Processing/IEmbedding.cs deleted file mode 100644 index 8caf6306b..000000000 --- a/Source/Embeddings.Processing/IEmbedding.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Embeddings.Store; -using Dolittle.Runtime.Events.Processing.Projections; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Rudimentary; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Defines an embedding. -/// -public interface IEmbedding -{ - /// - /// Tries to get that will get the current state closer to the desired state. - /// - /// The current state. - /// The desired state. - /// The execution context to execute the update operation in. - /// The . - /// A that, when resolved, returns of . - Task> TryCompare(EmbeddingCurrentState currentState, ProjectionState desiredState, ExecutionContext executionContext, CancellationToken cancellationToken); - - /// - /// Tries to get that will get the current state closer to be deleted. - /// - /// The . - /// The execution context to execute the delete operation in. - /// The . - /// A that, when resolved, returns of . - Task> TryDelete(EmbeddingCurrentState currentState, ExecutionContext executionContext, CancellationToken cancellationToken); - - /// - /// Projects a from onto a to calculate the new . - /// - /// The to update. - /// The to use to update the state. - /// The execution context to execute the projection operation in. - /// The . - /// A that, when resolved, returns an . - Task Project(ProjectionCurrentState state, UncommittedEvent @event, ExecutionContext executionContext, CancellationToken cancellationToken); -} diff --git a/Source/Embeddings.Processing/IEmbeddingProcessor.cs b/Source/Embeddings.Processing/IEmbeddingProcessor.cs deleted file mode 100644 index 08e0d66a0..000000000 --- a/Source/Embeddings.Processing/IEmbeddingProcessor.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Projections.Store; -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Rudimentary; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; - -namespace Dolittle.Runtime.Embeddings.Processing; - -public interface IEmbeddingProcessor -{ - /// - /// Starts the embedding processing. - /// - /// The used to signal the started processor to stop. - /// A that, when resolved, returns a that indicates whether the processor completes or fails. - Task Start(CancellationToken cancellationToken); - - /// - /// Tries to update embedding to match the projected state with the given state for a key. - /// - /// The that should be updated. - /// The desired to reach. - /// The execution context to execute the update operation in. - /// The used to cancel the operation. - /// A that is resolved to a when the operation completes. - Task> Update(ProjectionKey key, ProjectionState state, ExecutionContext executionContext, CancellationToken cancellationToken); - - /// - /// Tries to delete the embedding state for a key. - /// - /// The that should be deleted. - /// The execution context to execute the delete operation in. - /// The used to cancel the operation. - /// A that is resolved to a result. - Task Delete(ProjectionKey key, ExecutionContext executionContext, CancellationToken cancellationToken); -} diff --git a/Source/Embeddings.Processing/IEmbeddingProcessorFactory.cs b/Source/Embeddings.Processing/IEmbeddingProcessorFactory.cs deleted file mode 100644 index f8571aa7c..000000000 --- a/Source/Embeddings.Processing/IEmbeddingProcessorFactory.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Embeddings.Store; -using Dolittle.Runtime.Execution; -using Dolittle.Runtime.Projections.Store.State; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Defines a factory that can create . -/// -public interface IEmbeddingProcessorFactory -{ - /// - /// Creates an . - /// - /// The embedding identifier. - /// The embedding. - /// The initial state of the embedding. - /// The execution context to run the processor in. - /// The created . - IEmbeddingProcessor Create(EmbeddingId embeddingId, IEmbedding embedding, ProjectionState initialState, ExecutionContext executionContext); -} diff --git a/Source/Embeddings.Processing/IEmbeddingProcessors.cs b/Source/Embeddings.Processing/IEmbeddingProcessors.cs deleted file mode 100644 index 5341bdf26..000000000 --- a/Source/Embeddings.Processing/IEmbeddingProcessors.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Embeddings.Store; -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Defines a system that manages all instances of . -/// -public interface IEmbeddingProcessors -{ - /// - /// Starts an instance of an for all tenants for a given embedding. - /// - /// The to start processors for. - /// A to use for creating instances of for each tenant. - /// The used to signal the started processors to stop. - /// A that is resolved when one or all of the started complete or fail. - Task TryStartEmbeddingProcessorForAllTenants(EmbeddingId embedding, CreateEmbeddingProcessorForTenant factory, CancellationToken cancellationToken); - - /// - /// Checks if there are any instances of running for the given embedding. - /// - /// The to check for. - /// true if there are processors running, false if not. - bool HasEmbeddingProcessors(EmbeddingId embedding); - - /// - /// Get a specific for a given tenant and embedding. - /// - /// The to get the processor for. - /// The to get the processor for. - /// The running if it exists, null if not. - /// true if the processors was found, false if not. - bool TryGetEmbeddingProcessorFor(TenantId tenant, EmbeddingId embedding, out IEmbeddingProcessor processor); -} diff --git a/Source/Embeddings.Processing/IEmbeddingRequestFactory.cs b/Source/Embeddings.Processing/IEmbeddingRequestFactory.cs deleted file mode 100644 index 977f45741..000000000 --- a/Source/Embeddings.Processing/IEmbeddingRequestFactory.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Embeddings.Contracts; -using Dolittle.Runtime.Embeddings.Store; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Defines a factory that creates embedding requests. -/// -public interface IEmbeddingRequestFactory -{ - /// - /// Creates an for projections. - /// - /// The . - /// The . - /// The projection . - EmbeddingRequest Create(ProjectionCurrentState current, UncommittedEvent @event); - - /// - /// Creates an for projections. - /// - /// The . - /// The . - /// A projection . - Try TryCreate(ProjectionCurrentState current, UncommittedEvent @event); - - /// - /// Creates an for comparisons. - /// - /// The . - /// The desired . - /// The compare . - EmbeddingRequest Create(EmbeddingCurrentState current, ProjectionState desiredState); - - /// - /// Creates an for comparisons. - /// - /// The . - /// The desired . - /// A compare . - Try TryCreate(EmbeddingCurrentState current, ProjectionState desiredState); - - /// - /// Creates an for deleting. - /// - /// The . - /// A delete . - EmbeddingRequest Create(EmbeddingCurrentState current); - - /// - /// Creates an for deleting. - /// - /// The . - /// A delete . - Try TryCreate(EmbeddingCurrentState current); -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/IEmbeddingsProtocol.cs b/Source/Embeddings.Processing/IEmbeddingsProtocol.cs deleted file mode 100644 index 5954c8ce7..000000000 --- a/Source/Embeddings.Processing/IEmbeddingsProtocol.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Embeddings.Contracts; -using Dolittle.Runtime.Services; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Defines the protocol for embeddings. -/// -public interface IEmbeddingsProtocol : IReverseCallServiceProtocol -{ -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/IPersistEmbeddingDefinitionForAllTenants.cs b/Source/Embeddings.Processing/IPersistEmbeddingDefinitionForAllTenants.cs deleted file mode 100644 index 189a3c073..000000000 --- a/Source/Embeddings.Processing/IPersistEmbeddingDefinitionForAllTenants.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Embeddings.Store.Definition; -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Defines a system that can persist an embedding definition for all registered tenants. -/// -public interface IPersistEmbeddingDefinitionForAllTenants -{ - /// - /// Persist the given for all tenants. - /// - /// The to persist. - /// The . - /// A that, when resolved, returns a value indicating whether the has been persisted for all tenants. - Task TryPersist(EmbeddingDefinition definition, CancellationToken token); -} \ No newline at end of file diff --git a/Source/Embeddings.Processing/IProjectManyEvents.cs b/Source/Embeddings.Processing/IProjectManyEvents.cs deleted file mode 100644 index f9f7cd98d..000000000 --- a/Source/Embeddings.Processing/IProjectManyEvents.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Embeddings.Store; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Rudimentary; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Defines a system that can project many events. -/// -public interface IProjectManyEvents -{ - /// - /// Tries to project all the . - /// - /// The . - /// The . - /// The . - /// The . - /// - Task> TryProject(EmbeddingCurrentState currentState, CommittedAggregateEvents events, ExecutionContext executionContext, CancellationToken cancellationToken); - - /// - /// Tries to project all the . - /// - /// The . - /// The . - /// The . - /// The . - /// - Task> TryProject(EmbeddingCurrentState currentState, UncommittedEvents events, ExecutionContext executionContext, CancellationToken cancellationToken); -} diff --git a/Source/Embeddings.Processing/IUpdateEmbeddingStates.cs b/Source/Embeddings.Processing/IUpdateEmbeddingStates.cs deleted file mode 100644 index e6087e6ff..000000000 --- a/Source/Embeddings.Processing/IUpdateEmbeddingStates.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Rudimentary; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Defines a system that can update all embedding states. -/// -public interface IUpdateEmbeddingStates -{ - /// - /// Try to update all the embedding states by projecting all aggregate root events. - /// - /// The . - /// The . - /// A that, when resolved, returns a that indicates whether the operation was successful or not. - Task TryUpdateAll(ExecutionContext executionContext, CancellationToken cancellationToken); -} diff --git a/Source/Embeddings.Processing/Log.cs b/Source/Embeddings.Processing/Log.cs deleted file mode 100644 index e648c43a7..000000000 --- a/Source/Embeddings.Processing/Log.cs +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using Dolittle.Runtime.Aggregates; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Embeddings.Store; -using Dolittle.Runtime.Embeddings.Store.Definition; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Projections.Store; -using Dolittle.Runtime.Projections.Store.State; -using Microsoft.Extensions.Logging; -using UncommittedAggregateEvents = Dolittle.Runtime.Events.Store.UncommittedAggregateEvents; - -namespace Dolittle.Runtime.Embeddings.Processing; - -static partial class Log -{ - - [LoggerMessage(0, LogLevel.Debug, "Connecting Embeddings")] - internal static partial void ConnectingEmbeddings(ILogger logger); - - #region EmbeddingsService - - static readonly Action _comparingEmbeddingDefinition = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(208111084, nameof(ComparingEmbeddingDefinition)), - "Comparing embedding definition for embedding {Embedding}"); - - internal static void ComparingEmbeddingDefinition(this ILogger logger, EmbeddingDefinition arguments) - => _comparingEmbeddingDefinition(logger, arguments.Embedding, null); - - static readonly Action _invalidEmbeddingDefinition = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(1752597594, nameof(InvalidEmbeddingDefinition)), - "Embedding definition for embedding {Embedding} failed validation. {Reason}"); - - internal static void InvalidEmbeddingDefinition(this ILogger logger, EmbeddingDefinition defintion, IEnumerable<(TenantId, EmbeddingDefinitionComparisonResult)> failedComparisons) - => _invalidEmbeddingDefinition( - logger, - defintion.Embedding, - failedComparisons.First().Item2.FailureReason, - null); - - static readonly Action _persistingDefinition = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(220634741, nameof(PersistingDefinition)), - "Persisting definition for Embedding {Embedding}"); - - internal static void PersistingDefinition(this ILogger logger, EmbeddingId embedding) - => _persistingDefinition( - logger, - embedding, - null); - #endregion - - #region StateTransitionEventsCalculator - static readonly Action _calculatingStateTransitionEvents = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(1563454567, nameof(CalculatingStateTransitionEvents)), - "Calculating state transition events for embedding {Embedding} with key {Key} at aggregate root version {Version}"); - - internal static void CalculatingStateTransitionEvents(this ILogger logger, EmbeddingId embedding, ProjectionKey key, AggregateRootVersion version) - => _calculatingStateTransitionEvents(logger, embedding, key, version, null); - - static readonly Action _calculatingStateTransitionEventsCancelled = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(412978046, nameof(CalculatingStateTransitionEventsCancelled)), - "Calculating state transition events was cancellled for embedding {Embedding} with key {Key} at aggregate root version {Version}"); - - internal static void CalculatingStateTransitionEventsCancelled(this ILogger logger, EmbeddingId embedding, ProjectionKey key, AggregateRootVersion version) - => _calculatingStateTransitionEventsCancelled(logger, embedding, key, version, null); - - static readonly Action _calculatingStateTransitionEventsFailedCheckingIfDesiredState = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(327860911, nameof(CalculatingStateTransitionEventsFailedCheckingIfDesiredState)), - "Calculating state transition events failed while checking if the current state is the desired state for embedding {Embedding} with key {Key} at aggregate root version {Version}"); - - internal static void CalculatingStateTransitionEventsFailedCheckingIfDesiredState( - this ILogger logger, - EmbeddingId embedding, - ProjectionKey key, - AggregateRootVersion version, - Exception exception) - => _calculatingStateTransitionEventsFailedCheckingIfDesiredState(logger, embedding, key, version, exception); - - static readonly Action _calculatingStateTransitionEventsFailedGettingNextTransitionEvents = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(226703386, nameof(CalculatingStateTransitionEventsFailedGettingNextTransitionEvents)), - "Calculating state transition events failed getting the next transition events for embedding {Embedding} with key {Key} at aggregate root version {Version}"); - - internal static void CalculatingStateTransitionEventsFailedGettingNextTransitionEvents( - this ILogger logger, - EmbeddingId embedding, - ProjectionKey key, - AggregateRootVersion version, - Exception exception) - => _calculatingStateTransitionEventsFailedGettingNextTransitionEvents(logger, embedding, key, version, exception); - - static readonly Action _calculatingStateTransitionEventsFailedProjectingNewState = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(81456606, nameof(CalculatingStateTransitionEventsFailedProjectingNewState)), - "Calculating state transition events failed projecting the new state from the transition events for embedding {Embedding} with key {Key} at aggregate root version {Version}"); - - internal static void CalculatingStateTransitionEventsFailedProjectingNewState( - this ILogger logger, - EmbeddingId embedding, - ProjectionKey key, - AggregateRootVersion version, - Exception exception) - => _calculatingStateTransitionEventsFailedProjectingNewState(logger, embedding, key, version, exception); - - #endregion - #region EmbeddingStateUpdater - static readonly Action _updatingAllEmbeddingStates = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(157937906, nameof(UpdatingAllEmbeddingStates)), - "Updating all embeddings states for embedding {Embedding}"); - - internal static void UpdatingAllEmbeddingStates(this ILogger logger, EmbeddingId embedding) - => _updatingAllEmbeddingStates(logger, embedding, null); - - static readonly Action _updatingEmbeddingStateFor = LoggerMessage - .Define( - LogLevel.Trace, - new EventId(401955945, nameof(UpdatingEmbeddingStateFor)), - "Updating embedding state for embedding {Embedding} and key {Key}"); - - internal static void UpdatingEmbeddingStateFor(this ILogger logger, EmbeddingId embedding, ProjectionKey key) - => _updatingEmbeddingStateFor(logger, embedding, key, null); - - static readonly Action _failedUpdatingEmbeddingStateFor = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(30417, nameof(FailedUpdatingEmbeddingStateFor)), - "Failed updating embedding state for embedding {Embedding} and key {Key}"); - - internal static void FailedUpdatingEmbeddingStateFor(this ILogger logger, EmbeddingId embedding, ProjectionKey key, Exception exception) - => _failedUpdatingEmbeddingStateFor(logger, embedding, key, exception); - - #endregion - #region EmbeddingProcessor - static readonly Action _failedEnsuringAllStatesAreFresh = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(291050328, nameof(FailedEnsuringAllStatesAreFresh)), - "Failed to ensure all embedding states are fresh for embedding {Embedding}"); - - internal static void FailedEnsuringAllStatesAreFresh(this ILogger logger, EmbeddingId embedding, Exception exception) - => _failedEnsuringAllStatesAreFresh(logger, embedding, exception); - - static readonly Action _eventProcessorWorkWasCancelled = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(43544717, nameof(EventProcessorWorkWasCancelled)), - "Cancelled embedding processor with id {Embedding} while deleting or updating embedding state with key {Key}"); - - internal static void EventProcessorWorkWasCancelled(this ILogger logger, EmbeddingId embedding, ProjectionKey key) - => _eventProcessorWorkWasCancelled(logger, embedding, key, null); - - static readonly Action _eventProcessorWorkFailed = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(78426396, nameof(EventProcessorWorkFailed)), - "An error ocurred while updating or deleting embedding {Embedding} with key {Key}"); - - internal static void EventProcessorWorkFailed(this ILogger logger, EmbeddingId embedding, ProjectionKey key, Exception exception) - => _eventProcessorWorkFailed(logger, embedding, key, exception); - - static readonly Action _committingTransitionEvents = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(319, nameof(CommittingTransitionEvents)), - "Embedding processor with id {Embedding} is committing {NumberOfEvents} transition events for state with key {Key}"); - - internal static void CommittingTransitionEvents(this ILogger logger, EmbeddingId embedding, ProjectionKey key, UncommittedAggregateEvents uncommittedEvents) - => _committingTransitionEvents(logger, embedding, uncommittedEvents.Count, key, null); - - #endregion - #region EmbeddingProcessors - static readonly Action _startingEmbeddiingProcessorForAllTenants = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(371525267, nameof(StartingEmbeddiingProcessorForAllTenants)), - "Trying to start embedding processor with id {Embedding} for all tenants"); - - internal static void StartingEmbeddiingProcessorForAllTenants(this ILogger logger, EmbeddingId embedding) - => _startingEmbeddiingProcessorForAllTenants(logger, embedding, null); - - static readonly Action _failedRegisteringEmbeddingProcessor = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(380586739, nameof(FailedRegisteringEmbeddingProcessor)), - "Failed to registering embedding processor with id {Embedding}"); - - internal static void FailedRegisteringEmbeddingProcessor(this ILogger logger, EmbeddingId embedding, Exception exception) - => _failedRegisteringEmbeddingProcessor(logger, embedding, exception); - - static readonly Action _embeddingProcessorsStarted = LoggerMessage - .Define( - LogLevel.Trace, - new EventId(112400393, nameof(EmbeddingProcessorsStarted)), - "All embedding processors with id {Embedding} has started"); - - internal static void EmbeddingProcessorsStarted(this ILogger logger, EmbeddingId embedding) - => _embeddingProcessorsStarted(logger, embedding, null); - - static readonly Action _stoppingAllEmbeddingProcessors = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(289216221, nameof(StoppingAllEmbeddingProcessors)), - "Stopping all embedding processors with id {Embedding}"); - - internal static void StoppingAllEmbeddingProcessors(this ILogger logger, EmbeddingId embedding) - => _stoppingAllEmbeddingProcessors(logger, embedding, null); - - static readonly Action _allEmbeddingProcessorsSuccessfullyStopped = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(396379390, nameof(AllEmbeddingProcessorsSuccessfullyStopped)), - "All embedding processors with id {Embedding} has successfully been stopped"); - - internal static void AllEmbeddingProcessorsSuccessfullyStopped(this ILogger logger, EmbeddingId embedding) - => _allEmbeddingProcessorsSuccessfullyStopped(logger, embedding, null); - - static readonly Action _anErrorOccurredWhileStartingOrStoppingEmbedding = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(3037276, nameof(AnErrorOccurredWhileStartingOrStoppingEmbedding)), - "An error ocurred while starting or stopping embedding processors with id {Embedding}"); - - internal static void AnErrorOccurredWhileStartingOrStoppingEmbedding(this ILogger logger, EmbeddingId embedding, Exception exception) - => _anErrorOccurredWhileStartingOrStoppingEmbedding(logger, embedding, exception); - - #endregion - #region ProjectManyEvents - static readonly Action _projectingEventsOnEmbedding = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(11584329, nameof(ProjectingEventsOnEmbedding)), - "Projecting {NumEvents} events on embedding {Embedding} and key {Key}"); - - internal static void ProjectingEventsOnEmbedding(this ILogger logger, EmbeddingId embedding, ProjectionKey key, UncommittedEvents events) - => _projectingEventsOnEmbedding(logger, events.Count, embedding, key, null); - - #endregion - #region Embedding - static readonly Action _projectEventThroughDispatcher = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(33587349, nameof(ProjectEventThroughDispatcher)), - "Projecting an event on embedding {Embedding} and key {Key} with current state of type {Type}"); - - internal static void ProjectEventThroughDispatcher(this ILogger logger, EmbeddingId embedding, ProjectionCurrentState state) - => _projectEventThroughDispatcher(logger, embedding, state.Key, Enum.GetName(state.Type), null); - - static readonly Action _compareStatesForEmbedding = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(268001296, nameof(CompareStatesForEmbedding)), - "Comparing states for embedding {Embedding} and key {Key} with current state of type {Type}. Current state is {CurrentState} and desired state is {DesiredState}"); - - internal static void CompareStatesForEmbedding(this ILogger logger, EmbeddingId embedding, EmbeddingCurrentState currentState, ProjectionState desiredState) - => _compareStatesForEmbedding(logger, embedding, currentState.Key, Enum.GetName(currentState.Type), currentState.State, desiredState, null); - - static readonly Action _deletingStateForEmbedding = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(22170214, nameof(DeletingStateForEmbedding)), - "Deleting state for embedding {Embedding} and key {Key} with current state of type {Type}"); - - internal static void DeletingStateForEmbedding(this ILogger logger, EmbeddingId embedding, EmbeddingCurrentState currentState) - => _deletingStateForEmbedding(logger, embedding, currentState.Key, Enum.GetName(currentState.Type), null); - #endregion -} diff --git a/Source/Embeddings.Processing/PersistEmbeddingDefinitionForAllTenants.cs b/Source/Embeddings.Processing/PersistEmbeddingDefinitionForAllTenants.cs deleted file mode 100644 index 2a3320c56..000000000 --- a/Source/Embeddings.Processing/PersistEmbeddingDefinitionForAllTenants.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.DependencyInversion.Lifecycle; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Embeddings.Store.Definition; -using Dolittle.Runtime.Rudimentary; -using Dolittle.Runtime.Tenancy; -using Microsoft.Extensions.Logging; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents an implementation of . -/// -[Singleton] -public class PersistEmbeddingDefinitionForAllTenants : IPersistEmbeddingDefinitionForAllTenants -{ - readonly IPerformActionsForAllTenants _forAllTenants; - readonly Func _getDefinitionsFor; - readonly ILogger _logger; - - /// - /// Initializes an instance of the class. - /// - /// The system that can perform an action on all tenants. - /// The factory for getting embedding definitions scoped to the right execution context. - /// The logger for logging messages. - public PersistEmbeddingDefinitionForAllTenants( - IPerformActionsForAllTenants forAllTenants, - Func getDefinitionsFor, - ILogger logger) - { - _forAllTenants = forAllTenants; - _getDefinitionsFor = getDefinitionsFor; - _logger = logger; - } - - /// - public async Task TryPersist(EmbeddingDefinition definition, CancellationToken token) - { - _logger.PersistingDefinition(definition.Embedding); - var results = new Dictionary>(); - await _forAllTenants.PerformAsync(async (tenant, _) => - { - var result = await _getDefinitionsFor(tenant).TryPersist(definition, token).ConfigureAwait(false); - results.Add(tenant, result); - }).ConfigureAwait(false); - - if (results.Any(_ => !_.Value.Success)) - { - return results.First(_ => !_.Value.Success).Value.Exception; - } - - if (results.Any(_ => !_.Value.Result)) - { - return new FailedPersistingEmbeddingDefinition(definition.Embedding); - } - - return Try.Succeeded(); - } - -} diff --git a/Source/Embeddings.Processing/ProjectManyEvents.cs b/Source/Embeddings.Processing/ProjectManyEvents.cs deleted file mode 100644 index fdc333b81..000000000 --- a/Source/Embeddings.Processing/ProjectManyEvents.cs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.DependencyInversion; -using Dolittle.Runtime.Embeddings.Store; -using Dolittle.Runtime.Events.Processing.Projections; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Rudimentary; -using Microsoft.Extensions.Logging; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents an implementation of . -/// -[DisableAutoRegistration] -public class ProjectManyEvents : IProjectManyEvents -{ - readonly EmbeddingId _identifier; - readonly IEmbedding _embedding; - readonly ProjectionState _initialState; - readonly ILogger _logger; - - /// - /// Initializes an instance of the class. - /// - /// The that identifies the embedding. - /// The that is used to update the state. - /// The that is used to initialize newly created states. - /// The . - public ProjectManyEvents( - EmbeddingId identifier, - IEmbedding embedding, - ProjectionState initialState, - ILogger logger) - { - _identifier = identifier; - _embedding = embedding; - _initialState = initialState; - _logger = logger; - } - - /// - public Task> TryProject(EmbeddingCurrentState currentState, CommittedAggregateEvents events, ExecutionContext executionContext, CancellationToken cancellationToken) - => TryProject( - currentState, - new UncommittedEvents(events.Select(_ => new UncommittedEvent(_.EventSource, _.Type, _.Public, _.Content)).ToList()), - executionContext, - cancellationToken); - - /// - public async Task> TryProject(EmbeddingCurrentState currentState, UncommittedEvents events, ExecutionContext executionContext, CancellationToken cancellationToken) - { - _logger.ProjectingEventsOnEmbedding(_identifier, currentState.Key, events); - for (var i = 0; i < events.Count; i++) - { - var tryProject = await TryProjectOne(currentState, events[i], executionContext, cancellationToken).ConfigureAwait(false); - if (!tryProject.Success) - { - return i == 0 - ? tryProject.Exception - : Partial.PartialSuccess(currentState, tryProject.Exception); - } - currentState = tryProject.Result; - } - return currentState; - } - - async Task> TryProjectOne(EmbeddingCurrentState currentState, UncommittedEvent @event, ExecutionContext executionContext, CancellationToken cancellationToken) - { - try - { - var result = await _embedding.Project(currentState, @event, executionContext, cancellationToken).ConfigureAwait(false); - var nextAggregateRootVersion = currentState.Version.Value + 1; - return result switch - { - ProjectionFailedResult failedResult => failedResult.Exception, - ProjectionReplaceResult replaceResult => new EmbeddingCurrentState(nextAggregateRootVersion, EmbeddingCurrentStateType.Persisted, replaceResult.State, currentState.Key), - ProjectionDeleteResult => new EmbeddingCurrentState(nextAggregateRootVersion, EmbeddingCurrentStateType.Deleted, _initialState, currentState.Key), - _ => new UnknownProjectionResultType(result) - }; - } - catch (Exception ex) - { - return ex; - } - } -} diff --git a/Source/Embeddings.Processing/StateTransitionEventsCalculator.cs b/Source/Embeddings.Processing/StateTransitionEventsCalculator.cs deleted file mode 100644 index 8e0a6b11b..000000000 --- a/Source/Embeddings.Processing/StateTransitionEventsCalculator.cs +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Artifacts; -using Dolittle.Runtime.DependencyInversion; -using Dolittle.Runtime.Embeddings.Store; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Rudimentary; -using Microsoft.Extensions.Logging; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Represents an implementation of . -/// -[DisableAutoRegistration] -public class StateTransitionEventsCalculator : ICalculateStateTransitionEvents -{ - readonly EmbeddingId _embeddingId; - readonly IEmbedding _embedding; - readonly IProjectManyEvents _projector; - readonly ICompareStates _stateComparer; - readonly IDetectEmbeddingLoops _loopDetector; - readonly ILogger _logger; - - /// - /// Initializes an instance of the class. - /// - /// The . - /// The . - /// The . - /// The . - /// The . - /// The . - public StateTransitionEventsCalculator( - EmbeddingId identifier, - IEmbedding embedding, - IProjectManyEvents projector, - ICompareStates stateComparer, - IDetectEmbeddingLoops loopDetector, - ILogger logger) - { - _embeddingId = identifier; - _embedding = embedding; - _projector = projector; - _stateComparer = stateComparer; - _loopDetector = loopDetector; - _logger = logger; - } - - /// - public Task> TryConverge(EmbeddingCurrentState current, ProjectionState desired, ExecutionContext executionContext, CancellationToken cancellationToken) - => DoWork( - current, - newCurrent => _stateComparer.TryCheckEquality(newCurrent.State, desired), - (newCurrent, token) => _embedding.TryCompare(newCurrent, desired, executionContext, token), - executionContext, - cancellationToken); - - /// - public Task> TryDelete(EmbeddingCurrentState current, ExecutionContext executionContext, CancellationToken cancellationToken) - => DoWork( - current, - newCurrent => Try.Do(() => newCurrent.Type is EmbeddingCurrentStateType.Deleted), - (newCurrent, token) => _embedding.TryDelete(newCurrent, executionContext, token), - executionContext, - cancellationToken); - - async Task> DoWork( - EmbeddingCurrentState current, - Func> isDesiredState, - Func>> getTransitionEvents, - ExecutionContext executionContext, - CancellationToken cancellationToken) - { - try - { - _logger.CalculatingStateTransitionEvents(_embeddingId, current.Key, current.Version); - var allTransitionEvents = new List(); - var previousStates = new List - { - current.State - }; - - while (true) - { - if (cancellationToken.IsCancellationRequested) - { - _logger.CalculatingStateTransitionEventsCancelled(_embeddingId, current.Key, current.Version); - return new CalculateStateTransitionEventsCancelled(_embeddingId); - } - var getEventsToCommit = TryCheckIfDesiredState(current, allTransitionEvents, isDesiredState, out var eventsToCommit); - if (!getEventsToCommit.Success || getEventsToCommit.Result) - { - if (getEventsToCommit.Exception != default) - { - _logger.CalculatingStateTransitionEventsFailedCheckingIfDesiredState( - _embeddingId, - current.Key, - current.Version, - getEventsToCommit.Exception); - return getEventsToCommit.Exception; - } - return eventsToCommit; - } - var addNewTransitionEvents = await TryGetAndAddNewTransitionEventsInto( - allTransitionEvents, - current, - getTransitionEvents, - cancellationToken).ConfigureAwait(false); - if (!addNewTransitionEvents.Success) - { - _logger.CalculatingStateTransitionEventsFailedGettingNextTransitionEvents( - _embeddingId, - current.Key, - current.Version, - addNewTransitionEvents.Exception); - return addNewTransitionEvents.Exception; - } - - var projectIntermediateState = await TryProjectNewState(current, addNewTransitionEvents, previousStates, executionContext, cancellationToken).ConfigureAwait(false); - if (!projectIntermediateState.Success) - { - _logger.CalculatingStateTransitionEventsFailedProjectingNewState( - _embeddingId, - current.Key, - current.Version, - addNewTransitionEvents.Exception); - return projectIntermediateState.Exception; - } - - previousStates.Add(projectIntermediateState.Result.State); - current = projectIntermediateState; - } - } - catch (Exception ex) - { - return ex; - } - } - - Try TryCheckIfDesiredState( - EmbeddingCurrentState current, - IEnumerable allTransitionEvents, - Func> isDesiredState, - out UncommittedAggregateEvents eventsToCommit) - { - eventsToCommit = null; - var isDesired = isDesiredState(current); - if (!isDesired.Success) - { - return isDesired.Exception; - } - if (!isDesired.Result) - { - return false; - } - var flattenedTransitionEvents = from uncommittedEvents in allTransitionEvents - from @event in uncommittedEvents - select @event; - - eventsToCommit = CreateUncommittedAggregateEvents(new UncommittedEvents(flattenedTransitionEvents.ToArray()), current); - return true; - } - - async Task> TryGetAndAddNewTransitionEventsInto( - IList allTransitionEvents, - EmbeddingCurrentState current, - Func>> getTransitionEvents, - CancellationToken cancellationToken) - { - var newTransitionEvents = await getTransitionEvents(current, cancellationToken).ConfigureAwait(false); - if (!newTransitionEvents.Success) - { - return newTransitionEvents.Exception; - } - allTransitionEvents.Add(newTransitionEvents.Result); - return newTransitionEvents; - } - - async Task> TryProjectNewState( - EmbeddingCurrentState current, - Try newTransitionEvents, - IEnumerable previousStates, - ExecutionContext executionContext, - CancellationToken cancellationToken) - { - var intermediateState = await _projector.TryProject(current, newTransitionEvents.Result, executionContext, cancellationToken).ConfigureAwait(false); - if (!intermediateState.Success) - { - return intermediateState.IsPartialResult - ? new CouldNotProjectAllEvents(_embeddingId, intermediateState.Exception) - : new FailedProjectingEvents(_embeddingId, intermediateState.Exception); - } - - var loopDetected = _loopDetector.TryCheckForProjectionStateLoop(intermediateState.Result.State, previousStates); - - return loopDetected switch - { - { Success: false } => loopDetected.Exception, - { Result: true } => new EmbeddingLoopDetected(_embeddingId), - _ => intermediateState - }; - } - - UncommittedAggregateEvents CreateUncommittedAggregateEvents(UncommittedEvents events, EmbeddingCurrentState currentState) - => new( - currentState.Key.Value, - new Artifact(_embeddingId.Value, ArtifactGeneration.First), - currentState.Version.Value - (ulong)events.Count, - events); -} diff --git a/Source/Embeddings.Processing/UnexpectedEmbeddingResponse.cs b/Source/Embeddings.Processing/UnexpectedEmbeddingResponse.cs deleted file mode 100644 index 30c511430..000000000 --- a/Source/Embeddings.Processing/UnexpectedEmbeddingResponse.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Embeddings.Contracts; -using Dolittle.Runtime.Embeddings.Store; - -namespace Dolittle.Runtime.Embeddings.Processing; - -/// -/// Exception that gets thrown when an unexpected embedding response is received. -/// -public class UnexpectedEmbeddingResponse : Exception -{ - /// - /// Initializes a new instance of the class. - /// - /// The - /// The - public UnexpectedEmbeddingResponse(EmbeddingId embedding, EmbeddingResponse.ResponseOneofCase responseCase) - : base($"Embedding {embedding.Value} returned an unexpected response case {responseCase}") - { - } -} \ No newline at end of file diff --git a/Source/Embeddings.Store.MongoDB/DatabaseConnection.cs b/Source/Embeddings.Store.MongoDB/DatabaseConnection.cs deleted file mode 100644 index 19bfc4344..000000000 --- a/Source/Embeddings.Store.MongoDB/DatabaseConnection.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.DependencyInversion.Lifecycle; -using Dolittle.Runtime.DependencyInversion.Scoping; -using Dolittle.Runtime.MongoDB; -using Microsoft.Extensions.Options; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace Dolittle.Runtime.Embeddings.Store.MongoDB; - -/// -/// Represents an implementation of . -/// -[Singleton, PerTenant] -public class DatabaseConnection : IDatabaseConnection -{ - - /// - /// Initializes a new instance of the class. - /// - /// A with database connection parameters. - public DatabaseConnection(IOptions configuration) - { - var config = configuration.Value; - var settings = new MongoClientSettings - { - Servers = config.Servers.Select(_ => MongoServerAddress.Parse(_)), - GuidRepresentation = GuidRepresentation.Standard, - MaxConnectionPoolSize = config.MaxConnectionPoolSize, - ClusterConfigurator = cb => cb.AddTelemetry() - }; - - MongoClient = new MongoClient(settings.Freeze()); - Database = MongoClient.GetDatabase(config.Database); - } - - /// - public IMongoClient MongoClient { get; } - - /// - public IMongoDatabase Database { get; } -} diff --git a/Source/Embeddings.Store.MongoDB/Definition/ConvertEmbeddingDefinition.cs b/Source/Embeddings.Store.MongoDB/Definition/ConvertEmbeddingDefinition.cs deleted file mode 100644 index b62127a3c..000000000 --- a/Source/Embeddings.Store.MongoDB/Definition/ConvertEmbeddingDefinition.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Dolittle.Runtime.Artifacts; -using Dolittle.Runtime.DependencyInversion.Lifecycle; - - -namespace Dolittle.Runtime.Embeddings.Store.MongoDB.Definition; - -/// -/// Represents an implementation of . -/// -[Singleton] -public class ConvertEmbeddingDefinition : IConvertEmbeddingDefinition -{ - /// - public Store.Definition.EmbeddingDefinition ToRuntime(EmbeddingDefinition definition) - => new( - definition.Embedding, - definition.Events.Select(_ => new Artifact(_, ArtifactGeneration.First)), - definition.InitialState); - - /// - public EmbeddingDefinition ToStored(Store.Definition.EmbeddingDefinition definition) - => new() - { - Embedding = definition.Embedding, - InitialState = definition.InititalState, - Events = definition.Events.Select(_ => _.Id.Value).ToArray() - }; -} diff --git a/Source/Embeddings.Store.MongoDB/Definition/EmbeddingDefinition.cs b/Source/Embeddings.Store.MongoDB/Definition/EmbeddingDefinition.cs deleted file mode 100644 index aff67b839..000000000 --- a/Source/Embeddings.Store.MongoDB/Definition/EmbeddingDefinition.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using MongoDB.Bson.Serialization.Attributes; - - -namespace Dolittle.Runtime.Embeddings.Store.MongoDB.Definition; - -/// -/// Represents the persisted definition of an embedding. -/// -public class EmbeddingDefinition -{ - /// - /// Gets or sets the embedding id. - /// - [BsonId] - public Guid Embedding { get; set; } - - /// - /// Gets or sets the initial state. - /// - public string InitialState { get; set; } - - /// - /// Gets or sets the embedding event types. - /// - public Guid[] Events { get; set; } -} \ No newline at end of file diff --git a/Source/Embeddings.Store.MongoDB/Definition/EmbeddingDefinitions.cs b/Source/Embeddings.Store.MongoDB/Definition/EmbeddingDefinitions.cs deleted file mode 100644 index 677346fff..000000000 --- a/Source/Embeddings.Store.MongoDB/Definition/EmbeddingDefinitions.cs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.DependencyInversion.Lifecycle; -using Dolittle.Runtime.DependencyInversion.Scoping; -using Dolittle.Runtime.Embeddings.Store.Definition; - -using Dolittle.Runtime.Rudimentary; -using MongoDB.Driver; - -namespace Dolittle.Runtime.Embeddings.Store.MongoDB.Definition; - -/// -/// Represents an implementation of . -/// -[Singleton, PerTenant] -public class EmbeddingDefinitions : IEmbeddingDefinitions -{ - readonly IEmbeddings _embeddings; - readonly IConvertEmbeddingDefinition _definitionConverter; - - /// - /// Initializes an instance of the class. - /// - /// The embeddings. - /// The embedding definition converter. - public EmbeddingDefinitions(IEmbeddings embeddings, IConvertEmbeddingDefinition definitionConverter) - { - _embeddings = embeddings; - _definitionConverter = definitionConverter; - } - - /// - public async Task> TryGet(EmbeddingId embedding, CancellationToken token) - { - try - { - return await OnDefinitions>( - async collection => - { - var definition = await collection - .Find(CreateIdFilter(embedding)) - .SingleOrDefaultAsync(token) - .ConfigureAwait(false); - return definition == null - ? Try.Failed(new EmbeddingDefinitionDoesNotExist(embedding)) - : _definitionConverter.ToRuntime(definition); - }, - token).ConfigureAwait(false); - } - catch (Exception ex) - { - return ex; - } - } - - /// - public async Task> TryPersist(Store.Definition.EmbeddingDefinition definition, CancellationToken token) - { - try - { - return await OnDefinitions( - async collection => - { - var updateResult = await collection - .ReplaceOneAsync( - CreateIdFilter(definition.Embedding), - _definitionConverter.ToStored(definition), - new ReplaceOptions { IsUpsert = true }, - token) - .ConfigureAwait(false); - return updateResult.IsAcknowledged; - }, - token).ConfigureAwait(false); - } - catch (Exception ex) - { - return ex; - } - } - - async Task OnDefinitions( - Func, Task> callback, - CancellationToken token) - => await callback(await _embeddings.GetDefinitions(token).ConfigureAwait(false)) - .ConfigureAwait(false); - - FilterDefinition CreateIdFilter(EmbeddingId embedding) - => Builders.Filter.Eq(_ => _.Embedding, embedding.Value); -} diff --git a/Source/Embeddings.Store.MongoDB/Definition/IConvertEmbeddingDefinition.cs b/Source/Embeddings.Store.MongoDB/Definition/IConvertEmbeddingDefinition.cs deleted file mode 100644 index d2994dc29..000000000 --- a/Source/Embeddings.Store.MongoDB/Definition/IConvertEmbeddingDefinition.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Dolittle.Runtime.Embeddings.Store.MongoDB.Definition; - -/// -/// Defines a system that can convert to an from persisted and runtime representation of a embedding definition. -/// -public interface IConvertEmbeddingDefinition -{ - /// - /// Converts a runtime representation of an embedding definition to a the persisted mongodb representation. - /// - /// The runtime representation of the embedding definition. - /// The persisted mongodb representation of the embedding definition. - EmbeddingDefinition ToStored(Store.Definition.EmbeddingDefinition definition); - - /// - /// Converts a persisted mongodb representation of an embedding definition to the runtime representation. - /// - /// The persisted mongodb representation of the embedding definition. - /// The runtime representation of the embedding definition. - Store.Definition.EmbeddingDefinition ToRuntime(EmbeddingDefinition definition); -} \ No newline at end of file diff --git a/Source/Embeddings.Store.MongoDB/Embeddings.Store.MongoDB.csproj b/Source/Embeddings.Store.MongoDB/Embeddings.Store.MongoDB.csproj deleted file mode 100644 index 783678299..000000000 --- a/Source/Embeddings.Store.MongoDB/Embeddings.Store.MongoDB.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - - Dolittle.Runtime.Embeddings.Store.MongoDB - Dolittle.Runtime.Embeddings.Store.MongoDB - - - - - - - - - - - - - - - diff --git a/Source/Embeddings.Store.MongoDB/Embeddings.cs b/Source/Embeddings.Store.MongoDB/Embeddings.cs deleted file mode 100644 index ab23aa8a7..000000000 --- a/Source/Embeddings.Store.MongoDB/Embeddings.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.DependencyInversion.Lifecycle; -using Dolittle.Runtime.DependencyInversion.Scoping; -using MongoDB.Driver; - -namespace Dolittle.Runtime.Embeddings.Store.MongoDB; - -/// -/// Represents an implementation of . -/// -[Singleton, PerTenant] -public class Embeddings : EmbeddingsConnection, IEmbeddings -{ - const string EmbeddingDefinitionCollectionName = "embedding-definitions"; - readonly IMongoCollection _embeddingDefinitions; - static string CollectionNameForEmbedding(EmbeddingId embeddingId) => $"embedding-{embeddingId.Value}"; - - /// - /// Initializes a new instance of the class. - /// - /// The . - public Embeddings(IDatabaseConnection connection) - : base(connection) - { - _embeddingDefinitions = Database.GetCollection(EmbeddingDefinitionCollectionName); - } - - /// - public Task> GetDefinitions(CancellationToken token) - => Task.FromResult(_embeddingDefinitions); - - /// - public Task> GetStates(EmbeddingId embeddingId, CancellationToken token) - => Task.FromResult(Database.GetCollection(CollectionNameForEmbedding(embeddingId))); -} diff --git a/Source/Embeddings.Store.MongoDB/EmbeddingsConfiguration.cs b/Source/Embeddings.Store.MongoDB/EmbeddingsConfiguration.cs deleted file mode 100644 index f245aeb9a..000000000 --- a/Source/Embeddings.Store.MongoDB/EmbeddingsConfiguration.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using Dolittle.Runtime.Configuration; -using MongoDB.Driver; - -namespace Dolittle.Runtime.Embeddings.Store.MongoDB; - -/// -/// Represents a resource configuration for a MongoDB Embedding implementation. -/// -[TenantConfiguration("resources:embeddings")] -public class EmbeddingsConfiguration -{ - /// - /// Gets or sets the MongoDB servers. - /// - public IEnumerable Servers { get; set; } - - /// - /// Gets or sets the database name. - /// - public string Database { get; set; } - - /// - /// Gets or sets the maximum connection pool size for the MongoDB client. - /// - public int MaxConnectionPoolSize { get; set; } = MongoDefaults.MaxConnectionPoolSize; -} diff --git a/Source/Embeddings.Store.MongoDB/EmbeddingsConnection.cs b/Source/Embeddings.Store.MongoDB/EmbeddingsConnection.cs deleted file mode 100644 index a0fa4826f..000000000 --- a/Source/Embeddings.Store.MongoDB/EmbeddingsConnection.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.DependencyInversion; -using MongoDB.Driver; - -namespace Dolittle.Runtime.Embeddings.Store.MongoDB; - -/// -/// Represents a connection to the MongoDB Embeddings database. -/// -[DisableAutoRegistration] -public class EmbeddingsConnection : IEmbeddingsConnection -{ - /// - /// Initializes a new instance of the class with default collections. - /// - /// A connection to the MongoDB database. - protected EmbeddingsConnection(IDatabaseConnection connection) - { - MongoClient = connection.MongoClient; - Database = connection.Database; - } - - /// - /// Gets the configured for the MongoDB database. - /// - protected IMongoClient MongoClient { get; } - - /// - /// Gets the . - /// - protected IMongoDatabase Database { get; } - - /// - /// Starts a client session. - /// - /// The . - /// The . - /// The . - public IClientSessionHandle StartSession(ClientSessionOptions options = default, CancellationToken cancellationToken = default) => MongoClient.StartSession(options, cancellationToken); - - /// - /// Starts a client session. - /// - /// The . - /// The . - /// A that, when resolved, returns the . - public Task StartSessionAsync(ClientSessionOptions options = default, CancellationToken cancellationToken = default) => MongoClient.StartSessionAsync(options, cancellationToken); -} diff --git a/Source/Embeddings.Store.MongoDB/IDatabaseConnection.cs b/Source/Embeddings.Store.MongoDB/IDatabaseConnection.cs deleted file mode 100644 index dd2c2d968..000000000 --- a/Source/Embeddings.Store.MongoDB/IDatabaseConnection.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using MongoDB.Driver; - -namespace Dolittle.Runtime.Embeddings.Store.MongoDB; - -/// -/// Defines a connection to the MongoDB database. -/// -public interface IDatabaseConnection -{ - /// - /// Gets the configured for the MongoDB database. - /// - public IMongoClient MongoClient { get; } - - /// - /// Gets the configured for the MongoDB database. - /// - public IMongoDatabase Database { get; } -} diff --git a/Source/Embeddings.Store.MongoDB/IEmbeddings.cs b/Source/Embeddings.Store.MongoDB/IEmbeddings.cs deleted file mode 100644 index 3d1b0a8f4..000000000 --- a/Source/Embeddings.Store.MongoDB/IEmbeddings.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Projections.Store; -using MongoDB.Driver; - -namespace Dolittle.Runtime.Embeddings.Store.MongoDB; - -/// -/// Defines a system that knows about embeddings. -/// -public interface IEmbeddings : IEmbeddingsConnection -{ - /// - /// Gets the projection states collection for an embedding. - /// - /// The . - /// The . - /// A that, when resolved, returns a with . - Task> GetStates(EmbeddingId embeddingId, CancellationToken token); - - /// - /// Gets the embedding definitions collection for an embedding. - /// - /// The . - /// A that, when resolved, returns a with . - Task> GetDefinitions(CancellationToken token); -} \ No newline at end of file diff --git a/Source/Embeddings.Store.MongoDB/IEmbeddingsConnection.cs b/Source/Embeddings.Store.MongoDB/IEmbeddingsConnection.cs deleted file mode 100644 index a2af7fb1d..000000000 --- a/Source/Embeddings.Store.MongoDB/IEmbeddingsConnection.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using MongoDB.Driver; - -namespace Dolittle.Runtime.Embeddings.Store.MongoDB; - -/// -/// Defines a connection to the Embeddings. -/// -public interface IEmbeddingsConnection -{ - /// - /// Starts a client session. - /// - /// The . - /// The . - /// The . - IClientSessionHandle StartSession(ClientSessionOptions options = default, CancellationToken cancellationToken = default); - - /// - /// Starts a client session. - /// - /// The . - /// The . - /// A that, when resolved, returns the . - Task StartSessionAsync(ClientSessionOptions options = default, CancellationToken cancellationToken = default); -} \ No newline at end of file diff --git a/Source/Embeddings.Store.MongoDB/State/Embedding.cs b/Source/Embeddings.Store.MongoDB/State/Embedding.cs deleted file mode 100644 index 80fb11fef..000000000 --- a/Source/Embeddings.Store.MongoDB/State/Embedding.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using MongoDB.Bson.Serialization.Attributes; - -namespace Dolittle.Runtime.Embeddings.Store.MongoDB.State; - -/// -/// Represents the mongodb embedding store representation of an embedding. -/// -public class Embedding -{ - /// - /// Gets or sets the projection key of the embedding. - /// - [BsonId] - public string Key { get; set; } - - /// - /// Gets or sets the embedding content. - /// - public string Content { get; set; } - - /// - /// Gets or sets a value indicating whether the embedding currently is deleted. - /// - public bool IsRemoved { get; set; } - - /// - /// Gets or sets the aggregate root version. - /// - public ulong Version { get; set; } -} \ No newline at end of file diff --git a/Source/Embeddings.Store.MongoDB/State/EmbeddingStates.cs b/Source/Embeddings.Store.MongoDB/State/EmbeddingStates.cs deleted file mode 100644 index 92d545b6c..000000000 --- a/Source/Embeddings.Store.MongoDB/State/EmbeddingStates.cs +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Aggregates; -using Dolittle.Runtime.DependencyInversion.Lifecycle; -using Dolittle.Runtime.DependencyInversion.Scoping; -using Dolittle.Runtime.Embeddings.Store.State; -using Dolittle.Runtime.Projections.Store; -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Rudimentary; -using MongoDB.Driver; - -namespace Dolittle.Runtime.Embeddings.Store.MongoDB.State; - -/// -/// Represents an implementation of . -/// -[Singleton, PerTenant] -public class EmbeddingStates : IEmbeddingStates -{ - readonly IEmbeddings _embeddings; - - /// - /// Initializes an instance of the class. - /// - /// The embeddings repository. - public EmbeddingStates(IEmbeddings embeddings) - { - _embeddings = embeddings; - } - - /// - public async Task> TryGet( - EmbeddingId embeddingId, - ProjectionKey key, - CancellationToken token) - { - try - { - var embedding = await OnEmbedding( - embeddingId, - async collection => await collection - .Find(CreateKeyFilter(key)) - .SingleOrDefaultAsync(token) - .ConfigureAwait(false), - token).ConfigureAwait(false); - - return embedding == default - ? Try.Failed(new EmbeddingStateDoesNotExist(embeddingId, key)) - : new EmbeddingState(embedding.Content, embedding.Version, embedding.IsRemoved); - } - catch (Exception ex) - { - return ex; - } - } - - /// - /// - /// Returns all of the stored embedding states, even ones that have been marked as removed. - /// - public async Task>> TryGetAll( - EmbeddingId embedding, - CancellationToken token) - { - try - { - var states = await OnEmbedding( - embedding, - async collection => await collection - .Find(Builders.Filter.Empty) - .Project(_ => Tuple.Create( - new EmbeddingState(_.Content, _.Version, _.IsRemoved), _.Key)) - .ToListAsync(token) - .ConfigureAwait(false), - token).ConfigureAwait(false); - var result = states.Select(_ => - { - return (_.Item1, _.Item2); - }); - - return Try>.Succeeded(result); - } - catch (Exception ex) - { - return ex; - } - } - - /// - public async Task> TryMarkAsRemove( - EmbeddingId embedding, - ProjectionKey key, - AggregateRootVersion version, - CancellationToken token) - { - try - { - return await OnEmbedding( - embedding, - async collection => - { - var markDefinition = Builders - .Update - .Set(_ => _.IsRemoved, true) - .Set(_ => _.Version, version.Value); - var markResult = await collection - .UpdateOneAsync( - CreateKeyFilter(key), - markDefinition, - new UpdateOptions { IsUpsert = true }, - token) - .ConfigureAwait(false); - return markResult.IsAcknowledged; - }, - token).ConfigureAwait(false); - } - catch (MongoWaitQueueFullException) - { - return false; - } - catch (Exception ex) - { - return ex; - } - } - - /// - public async Task> TryReplace( - EmbeddingId embedding, - ProjectionKey key, - EmbeddingState state, - CancellationToken token) - { - try - { - return await OnEmbedding( - embedding, - async collection => - { - var updateDefinition = Builders - .Update - .Set(_ => _.Content, state.State.Value) - .Set(_ => _.Version, state.Version.Value) - .Set(_ => _.IsRemoved, state.IsRemoved); - var updateResult = await collection - .UpdateOneAsync( - CreateKeyFilter(key), - updateDefinition, - new UpdateOptions { IsUpsert = true }, - token) - .ConfigureAwait(false); - return updateResult.IsAcknowledged; - }, - token).ConfigureAwait(false); - } - catch (MongoWaitQueueFullException) - { - return false; - } - catch (Exception ex) - { - return ex; - } - } - - /// - public async Task TryDrop(EmbeddingId embedding, CancellationToken token) - { - try - { - await OnEmbedding( - embedding, - async collection => - { - var deleteResult = await collection - .DeleteManyAsync(Builders.Filter.Empty, token) - .ConfigureAwait(false); - return deleteResult.IsAcknowledged; - }, - token).ConfigureAwait(false); - return Try.Succeeded(); - } - catch (Exception ex) - { - return ex; - } - } - - async Task OnEmbedding( - EmbeddingId embedding, - Func, Task> callback, - CancellationToken token) - => await callback(await _embeddings.GetStates(embedding, token).ConfigureAwait(false)) - .ConfigureAwait(false); - - FilterDefinition CreateKeyFilter(ProjectionKey key) => - Builders.Filter.Eq(_ => _.Key, key.Value); -} diff --git a/Source/Embeddings.Store.Services.Grpc/EmbeddingStoreGrpcService.cs b/Source/Embeddings.Store.Services.Grpc/EmbeddingStoreGrpcService.cs deleted file mode 100644 index e7e9d0034..000000000 --- a/Source/Embeddings.Store.Services.Grpc/EmbeddingStoreGrpcService.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading.Tasks; -using Dolittle.Runtime.Protobuf; -using Dolittle.Runtime.Embeddings.Processing; -using Grpc.Core; -using static Dolittle.Runtime.Embeddings.Contracts.EmbeddingStore; -using System.Linq; -using Dolittle.Runtime.Rudimentary; -using System; -using System.Collections.Generic; -using Dolittle.Runtime.Projections.Store; -using Dolittle.Runtime.Services.Hosting; - -namespace Dolittle.Runtime.Embeddings.Store.Services.Grpc; - -/// -/// Represents the implementation of the grpc service. -/// -[PrivateService] -public class EmbeddingStoreGrpcService : EmbeddingStoreBase -{ - readonly IEmbeddingsService _embeddingsService; - - /// - /// Initializes a new instance of the class. - /// - /// . - public EmbeddingStoreGrpcService(IEmbeddingsService embeddingService) - { - _embeddingsService = embeddingService; - } - - /// - public override async Task GetOne(Contracts.GetOneRequest request, ServerCallContext context) - => CreateResponse( - await _embeddingsService.TryGetOne( - request.EmbeddingId.ToGuid(), - request.Key, - request.CallContext.ExecutionContext.ToExecutionContext(), - context.CancellationToken).ConfigureAwait(false), - (result, response) => response.State = result.ToProtobuf(), - (failure, response) => response.Failure = failure); - - /// - public override async Task GetAll(Contracts.GetAllRequest request, ServerCallContext context) - => CreateResponse>( - await _embeddingsService.TryGetAll( - request.EmbeddingId.ToGuid(), - request.CallContext.ExecutionContext.ToExecutionContext(), - context.CancellationToken).ConfigureAwait(false), - (result, response) => response.States.AddRange(result.ToProtobuf()), - (failure, response) => response.Failure = failure); - - /// - public override async Task GetKeys(Contracts.GetKeysRequest request, ServerCallContext context) - => CreateResponse>( - await _embeddingsService.TryGetKeys( - request.EmbeddingId.ToGuid(), - request.CallContext.ExecutionContext.ToExecutionContext(), - context.CancellationToken).ConfigureAwait(false), - (result, response) => response.Keys.AddRange(result.Select(_ => _.Value)), - (failure, response) => response.Failure = failure); - - TResponse CreateResponse( - Try maybeResult, - Action onSuccess, - Action onFailure) - where TResponse : new() - { - var response = new TResponse(); - if (maybeResult.Success) - { - onSuccess(maybeResult, response); - } - else - { - onFailure(maybeResult.Exception.ToFailure(), response); - } - return response; - } -} diff --git a/Source/Embeddings.Store.Services.Grpc/Embeddings.Store.Services.Grpc.csproj b/Source/Embeddings.Store.Services.Grpc/Embeddings.Store.Services.Grpc.csproj deleted file mode 100644 index 82554c586..000000000 --- a/Source/Embeddings.Store.Services.Grpc/Embeddings.Store.Services.Grpc.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - - Dolittle.Runtime.Embeddings.Store.Services.Grpc - Dolittle.Runtime.Embeddings.Store.Services.Grpc - - - - - - - - - - - - - - - diff --git a/Source/Embeddings.Store.Services/Embeddings.Store.Services.csproj b/Source/Embeddings.Store.Services/Embeddings.Store.Services.csproj deleted file mode 100644 index 06ce39c78..000000000 --- a/Source/Embeddings.Store.Services/Embeddings.Store.Services.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - - Dolittle.Runtime.Embeddings.Store.Services - Dolittle.Runtime.Embeddings.Store.Services - - - - - - - - - - - - - - - - - diff --git a/Source/Embeddings.Store.Services/EmbeddingsService.cs b/Source/Embeddings.Store.Services/EmbeddingsService.cs deleted file mode 100644 index 5b6a4ea4c..000000000 --- a/Source/Embeddings.Store.Services/EmbeddingsService.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.DependencyInversion.Lifecycle; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Execution; -using Dolittle.Runtime.Projections.Store; -using Dolittle.Runtime.Rudimentary; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; - -namespace Dolittle.Runtime.Embeddings.Store.Services; - -/// -/// Represents the implementation of . -/// -[Singleton] -public class EmbeddingsService : IEmbeddingsService -{ - readonly ICreateExecutionContexts _executionContextCreator; - readonly Func _getEmbeddingStoreFor; - - /// - /// Initializes a new instance of the class. - /// - /// The execution context creator to use to validate execution contexts. - /// The factory to use to create embedding stores per tenant. - public EmbeddingsService( - ICreateExecutionContexts executionContextCreator, - Func getEmbeddingStoreFor) - { - _executionContextCreator = executionContextCreator; - _getEmbeddingStoreFor = getEmbeddingStoreFor; - } - - /// - public Task> TryGetOne(EmbeddingId embedding, ProjectionKey key, ExecutionContext context, CancellationToken token) - => _executionContextCreator - .TryCreateUsing(context) - .Then(_ => _getEmbeddingStoreFor(_.Tenant)) - .Then(_ => _.TryGet(embedding, key, token)); - - /// - public Task>> TryGetAll(EmbeddingId embedding, ExecutionContext context, CancellationToken token) - => _executionContextCreator - .TryCreateUsing(context) - .Then(_ => _getEmbeddingStoreFor(_.Tenant)) - .Then(_ => _.TryGetAll(embedding, token)); - - /// - public Task>> TryGetKeys(EmbeddingId embedding, ExecutionContext context, CancellationToken token) - => _executionContextCreator - .TryCreateUsing(context) - .Then(_ => _getEmbeddingStoreFor(_.Tenant)) - .Then(_ => _.TryGetKeys(embedding, token)); -} diff --git a/Source/Embeddings.Store.Services/ExceptionExtensions.cs b/Source/Embeddings.Store.Services/ExceptionExtensions.cs deleted file mode 100644 index 3bcf5c4e3..000000000 --- a/Source/Embeddings.Store.Services/ExceptionExtensions.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Protobuf; - -namespace Dolittle.Runtime.Embeddings.Store.Services; - -/// -/// Extension methods for . -/// -public static class ExceptionExtensions -{ - /// - /// Converts the to a . - /// - /// The to convert from. - /// The converted . - public static Failure ToFailure(this Exception exception) - => exception switch - { - EmbeddingDefinitionDoesNotExist e => new Failure(Failures.FailedToGetEmbeddingDefinition, e.Message), - _ => new Failure(FailureId.Other, $"Error message: {exception.Message}\nStack Trace: {exception.StackTrace}") - }; -} \ No newline at end of file diff --git a/Source/Embeddings.Store.Services/Failures.cs b/Source/Embeddings.Store.Services/Failures.cs deleted file mode 100644 index 2197034c8..000000000 --- a/Source/Embeddings.Store.Services/Failures.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Protobuf; - -namespace Dolittle.Runtime.Embeddings.Store.Services; - -/// -/// Holds the unique failure ids unique to the Embeddings. -/// -public static class Failures -{ - /// - /// Gets the that represents the 'FailedToGetEmbeddingDefinition' failure type. - /// - public static readonly FailureId FailedToGetEmbeddingDefinition = FailureId.Create("c76b3806-8b74-47b0-b169-5e3ff1f5265b"); -} \ No newline at end of file diff --git a/Source/Embeddings.Store.Services/IEmbeddingsService.cs b/Source/Embeddings.Store.Services/IEmbeddingsService.cs deleted file mode 100644 index 7aa091963..000000000 --- a/Source/Embeddings.Store.Services/IEmbeddingsService.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Projections.Store; -using Dolittle.Runtime.Rudimentary; -using RuntimeExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; - -namespace Dolittle.Runtime.Embeddings.Store.Services; - -/// -/// Defines the service that retrieves Embeddings. -/// -public interface IEmbeddingsService -{ - /// - /// Try to get an embedding state. - /// - /// to get state from. - /// of the state to get. - /// the embedding should be gotten in. - /// for cancelling the task. - /// A that, when resolved, returns of the . - Task> TryGetOne(EmbeddingId embedding, ProjectionKey key, RuntimeExecutionContext context, CancellationToken token); - - /// - /// Try to get all the embedding states. - /// - /// to get state from. - /// the embeddings should be gotten in. - /// for cancelling the task. - /// A that, when resolved, returns of the of . - Task>> TryGetAll(EmbeddingId embedding, RuntimeExecutionContext context, CancellationToken token); - - /// - /// Try to get all the keys of an embedding. - /// - /// to get state from. - /// the embedding keys should be gotten in. - /// for cancelling the task. - /// A that, when resolved, returns of the of . - Task>> TryGetKeys(EmbeddingId embedding, RuntimeExecutionContext context, CancellationToken token); -} \ No newline at end of file diff --git a/Source/Embeddings.Store/Definition/EmbeddingDefinition.cs b/Source/Embeddings.Store/Definition/EmbeddingDefinition.cs deleted file mode 100644 index 1303c08a3..000000000 --- a/Source/Embeddings.Store/Definition/EmbeddingDefinition.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using Dolittle.Runtime.Artifacts; -using Dolittle.Runtime.Projections.Store.State; - -namespace Dolittle.Runtime.Embeddings.Store.Definition; - -/// -/// Represents the definition of an embedding. -/// -/// The embedding id. -/// The list of the embeddings event selectors. -/// The initital embedding state. -public record EmbeddingDefinition(EmbeddingId Embedding, IEnumerable Events, ProjectionState InititalState); \ No newline at end of file diff --git a/Source/Embeddings.Store/Definition/IEmbeddingDefinitions.cs b/Source/Embeddings.Store/Definition/IEmbeddingDefinitions.cs deleted file mode 100644 index b79b2c7c5..000000000 --- a/Source/Embeddings.Store/Definition/IEmbeddingDefinitions.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Embeddings.Store.Definition; - -/// -/// Defines a repository for projection definitions. -/// -public interface IEmbeddingDefinitions -{ - /// - /// Try to get a for a projection. - /// - /// The . - /// The . - /// A that, when resolved, returns a of . - Task> TryGet(EmbeddingId projection, CancellationToken token); - - /// - /// Try to persist a . - /// - /// The . - /// The . - /// A that, when resolved, returns a value indicating whether the new state was persisted. - Task> TryPersist(EmbeddingDefinition definition, CancellationToken token); -} \ No newline at end of file diff --git a/Source/Embeddings.Store/EmbeddingCurrentState.cs b/Source/Embeddings.Store/EmbeddingCurrentState.cs deleted file mode 100644 index 577df6adb..000000000 --- a/Source/Embeddings.Store/EmbeddingCurrentState.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Aggregates; -using Dolittle.Runtime.Projections.Store; -using Dolittle.Runtime.Projections.Store.State; - -namespace Dolittle.Runtime.Embeddings.Store; - -/// -/// Represents the current state of an embedding tied to an aggregate root version. -/// -/// The aggregate root version the state was calculated from. -/// The type of the state. -/// The state. -/// The key of the projection. -public record EmbeddingCurrentState(AggregateRootVersion Version, EmbeddingCurrentStateType Type, ProjectionState State, ProjectionKey Key) -{ - /// - /// Implicitly converts a to . - /// - /// The . - public static implicit operator ProjectionCurrentState(EmbeddingCurrentState current) => new(ProjectionTypeFromEmbeddingType(current.Type), current.State, current.Key); - - static ProjectionCurrentStateType ProjectionTypeFromEmbeddingType(EmbeddingCurrentStateType type) - => type switch - { - EmbeddingCurrentStateType.CreatedFromInitialState => ProjectionCurrentStateType.CreatedFromInitialState, - EmbeddingCurrentStateType.Persisted => ProjectionCurrentStateType.Persisted, - EmbeddingCurrentStateType.Deleted => ProjectionCurrentStateType.CreatedFromInitialState, - _ => throw new UnknownEmbeddingCurrentStateType(type) - }; -}; diff --git a/Source/Embeddings.Store/EmbeddingCurrentStateType.cs b/Source/Embeddings.Store/EmbeddingCurrentStateType.cs deleted file mode 100644 index e61df3ed8..000000000 --- a/Source/Embeddings.Store/EmbeddingCurrentStateType.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Dolittle.Runtime.Embeddings.Store; - -/// -/// Represents the different types of a . -/// -public enum EmbeddingCurrentStateType -{ - CreatedFromInitialState = 0, - Persisted, - Deleted -} \ No newline at end of file diff --git a/Source/Embeddings.Store/EmbeddingDefinitionDoesNotExist.cs b/Source/Embeddings.Store/EmbeddingDefinitionDoesNotExist.cs deleted file mode 100644 index 4d8f061c8..000000000 --- a/Source/Embeddings.Store/EmbeddingDefinitionDoesNotExist.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Embeddings.Store.Definition; - -namespace Dolittle.Runtime.Embeddings.Store; - -/// -/// Exception that gets thrown when a does not exist. -/// -public class EmbeddingDefinitionDoesNotExist : Exception -{ - /// - /// Initializes an instance of the class. - /// - /// The embedding id. - public EmbeddingDefinitionDoesNotExist(EmbeddingId embedding) - : base($"Embedding {embedding.Value} doesn't have a definition") - { - } -} \ No newline at end of file diff --git a/Source/Embeddings.Store/EmbeddingId.cs b/Source/Embeddings.Store/EmbeddingId.cs deleted file mode 100644 index 242c951bb..000000000 --- a/Source/Embeddings.Store/EmbeddingId.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Embeddings.Store; - -/// -/// Represents the unique identifier of an embedding. -/// -/// The identifier of the embedding as a . -public record EmbeddingId(Guid Value) : ConceptAs(Value) -{ - /// - /// Implicitly convert from a to an . - /// - /// EmbeddingId as a . - public static implicit operator EmbeddingId(Guid embeddingId) => new(embeddingId); - - /// - /// Implicitly convert from a to an . - /// - /// EmbeddingId as a . - public static implicit operator EmbeddingId(string embeddingId) => new(Guid.Parse(embeddingId)); - - /// - /// Generates a new . - /// - /// A randomly generated . - public static EmbeddingId New() => Guid.NewGuid(); -} \ No newline at end of file diff --git a/Source/Embeddings.Store/EmbeddingIsRemoved.cs b/Source/Embeddings.Store/EmbeddingIsRemoved.cs deleted file mode 100644 index 4b598fe5d..000000000 --- a/Source/Embeddings.Store/EmbeddingIsRemoved.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Aggregates; -using Dolittle.Runtime.Embeddings.Store.State; -using Dolittle.Runtime.Projections.Store; - -namespace Dolittle.Runtime.Embeddings.Store; - -/// -/// Exception that gets thrown when you try to get an that is removed. -/// -public class EmbeddingIsRemoved : Exception -{ - /// - /// Initializes an instance of the class. - /// - /// The embedding id. - /// The key to the embedding. - /// The of the removed embedding. - public EmbeddingIsRemoved(EmbeddingId embedding, ProjectionKey key, AggregateRootVersion version) - : base($"Can't get embedding {embedding.Value} with key {key.Value}, as it's already removed. Aggregate root version of the removed embedding is {version.Value}") - { - } -} diff --git a/Source/Embeddings.Store/EmbeddingStateDoesNotExist.cs b/Source/Embeddings.Store/EmbeddingStateDoesNotExist.cs deleted file mode 100644 index 44759efe4..000000000 --- a/Source/Embeddings.Store/EmbeddingStateDoesNotExist.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Embeddings.Store.State; -using Dolittle.Runtime.Projections.Store; - -namespace Dolittle.Runtime.Embeddings.Store; - -/// -/// Exception that gets thrown when a does not exist. -/// -public class EmbeddingStateDoesNotExist : Exception -{ - /// - /// Initializes an instance of the class. - /// - /// The embedding id. - /// The key to the embedding. - public EmbeddingStateDoesNotExist(EmbeddingId embedding, ProjectionKey key) - : base($"An embedding state for embedding {embedding.Value} with key {key.Value} does not exist") - { - } -} \ No newline at end of file diff --git a/Source/Embeddings.Store/EmbeddingStore.cs b/Source/Embeddings.Store/EmbeddingStore.cs deleted file mode 100644 index 5d198c70f..000000000 --- a/Source/Embeddings.Store/EmbeddingStore.cs +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Aggregates; -using Dolittle.Runtime.Embeddings.Store.Definition; -using Dolittle.Runtime.Embeddings.Store.State; -using Dolittle.Runtime.Projections.Store; -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Rudimentary; -using Microsoft.Extensions.Logging; - -namespace Dolittle.Runtime.Embeddings.Store; - -/// -/// Represents the implementation of -/// -public class EmbeddingStore : IEmbeddingStore -{ - readonly IEmbeddingStates _embeddingStates; - readonly IEmbeddingDefinitions _embeddingDefinitions; - readonly ILogger _logger; - - /// - /// Initializes an instance of the class. - /// - /// The embedding states. - /// The embedding definitions. - /// The logger for logging messages. - public EmbeddingStore( - IEmbeddingStates embeddingStates, - IEmbeddingDefinitions embeddingDefinitions, - ILogger logger) - { - _embeddingStates = embeddingStates; - _embeddingDefinitions = embeddingDefinitions; - _logger = logger; - } - - /// - public async Task> TryGet(EmbeddingId embedding, ProjectionKey key, CancellationToken token) - { - _logger.GettingOneEmbedding(embedding, key); - - var state = await _embeddingStates.TryGet(embedding, key, token); - var result = state switch - { - { Success: true, Result: { IsRemoved: true } } => await TryGetInitialState( - embedding, - key, - state.Result.Version, - token).ConfigureAwait(false), - { Success: true } => Try.Succeeded(new EmbeddingCurrentState( - state.Result.Version, - EmbeddingCurrentStateType.Persisted, - state.Result.State, - key)), - { Success: false, Exception: EmbeddingStateDoesNotExist } => - await TryGetInitialState(embedding, key, token).ConfigureAwait(false), - _ => Try.Failed(state.Exception) - }; - if (result.Exception != default) - { - _logger.ErrorGettingOneEmbedding(embedding, key, result.Exception); - } - return result; - } - - /// - public Task>> TryGetAll(EmbeddingId embedding, CancellationToken token) - => TryGetAll(embedding, false, token); - - /// - public async Task>> TryGetAll(EmbeddingId embedding, bool includeRemoved, CancellationToken token) - { - _logger.GettingAllEmbeddings(embedding); - - var tryGetStateTuples = await _embeddingStates.TryGetAll(embedding, token).ConfigureAwait(false); - if (!tryGetStateTuples.Success) - { - _logger.ErrorGettingAllEmbeddings(embedding, tryGetStateTuples.Exception); - return tryGetStateTuples.Exception; - } - return tryGetStateTuples - .Select(_ => - _.Where(resultTuple => includeRemoved || !resultTuple.State.IsRemoved) - .Select(resultTuple => - new EmbeddingCurrentState( - resultTuple.State.Version, - resultTuple.State.IsRemoved ? EmbeddingCurrentStateType.Deleted : EmbeddingCurrentStateType.Persisted, - resultTuple.State.State, - resultTuple.Key))); - } - - /// - public Task>> TryGetKeys(EmbeddingId embedding, CancellationToken token) - => TryGetKeys(embedding, false, token); - - - /// - public async Task>> TryGetKeys(EmbeddingId embedding, bool includeRemoved, CancellationToken token) - { - _logger.GettingEmbeddingKeys(embedding); - - var tryGetStateTuples = await _embeddingStates.TryGetAll(embedding, token).ConfigureAwait(false); - if (!tryGetStateTuples.Success) - { - _logger.ErrorGettingEmbeddingKeys(embedding, tryGetStateTuples.Exception); - return tryGetStateTuples.Exception; - } - return tryGetStateTuples - .Select(_ => - _.Where(resultTuple => includeRemoved || !resultTuple.State.IsRemoved) - .Select(resultTuple => resultTuple.Key)); - } - - - /// - public async Task TryRemove(EmbeddingId embedding, ProjectionKey key, AggregateRootVersion version, CancellationToken token) - { - _logger.RemovingEmbedding(embedding, key, version); - var tryMarkAsRemoved = await _embeddingStates.TryMarkAsRemove(embedding, key, version, token).ConfigureAwait(false); - if (tryMarkAsRemoved.Exception != default) - { - _logger.ErrorRemovingEmbedding(embedding, key, version, tryMarkAsRemoved.Exception); - } - return tryMarkAsRemoved.Success ? Try.Succeeded() : tryMarkAsRemoved.Exception; - - } - - /// - public async Task TryReplace( - EmbeddingId embedding, - ProjectionKey key, - AggregateRootVersion version, - ProjectionState state, - CancellationToken token) - { - _logger.ReplacingEmbedding(embedding, key, version, state); - var embeddingState = new EmbeddingState(state, version, false); - - var tryReplace = await _embeddingStates.TryReplace(embedding, key, embeddingState, token).ConfigureAwait(false); - if (tryReplace.Exception != default) - { - _logger.ErrorReplacingEmbedding(embedding, key, version, state, tryReplace.Exception); - } - return tryReplace.Success ? Try.Succeeded() : tryReplace.Exception; - } - - Task> TryGetInitialState( - EmbeddingId embedding, - ProjectionKey key, - CancellationToken token) - => TryGetInitialState(embedding, key, AggregateRootVersion.Initial, token); - - async Task> TryGetInitialState( - EmbeddingId embedding, - ProjectionKey key, - AggregateRootVersion version, - CancellationToken token) - { - var definition = await _embeddingDefinitions.TryGet(embedding, token).ConfigureAwait(false); - if (!definition.Success) - { - return definition.Exception; - } - return new EmbeddingCurrentState( - version, - EmbeddingCurrentStateType.CreatedFromInitialState, - definition.Result.InititalState, - key); - } -} diff --git a/Source/Embeddings.Store/Embeddings.Store.csproj b/Source/Embeddings.Store/Embeddings.Store.csproj deleted file mode 100644 index a4cd972ef..000000000 --- a/Source/Embeddings.Store/Embeddings.Store.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Dolittle.Runtime.Embeddings.Store - Dolittle.Runtime.Embeddings.Store - - - - - - - - - - - - - diff --git a/Source/Embeddings.Store/FailedToGetEmbeddingKeys.cs b/Source/Embeddings.Store/FailedToGetEmbeddingKeys.cs deleted file mode 100644 index 407385e46..000000000 --- a/Source/Embeddings.Store/FailedToGetEmbeddingKeys.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; - -namespace Dolittle.Runtime.Embeddings.Store; - -/// -/// Exception that gets thrown when the embedding store failed to get the persisted embedding keys for an embedding. -/// -public class FailedToGetEmbeddingKeys : Exception -{ - /// - /// Initializes an instance of the class. - /// - /// The embedding identifier. - public FailedToGetEmbeddingKeys(EmbeddingId embedding) - : base($"Failed to get embedding's keys, EmbeddingId: {embedding.Value}") - { - } -} \ No newline at end of file diff --git a/Source/Embeddings.Store/FailedToGetEmbeddingState.cs b/Source/Embeddings.Store/FailedToGetEmbeddingState.cs deleted file mode 100644 index 5b75cb427..000000000 --- a/Source/Embeddings.Store/FailedToGetEmbeddingState.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Projections.Store; - -namespace Dolittle.Runtime.Embeddings.Store; - -/// -/// Exception that gets thrown when the embedding store failed to get the state of an embedding. -/// -public class FailedToGetEmbeddingState : Exception -{ - /// - /// Initializes an instance of the class. - /// - /// The embedding identifier. - /// The projection key. - public FailedToGetEmbeddingState(EmbeddingId embedding, ProjectionKey key) - : base($"Failed to get embedding's state: Id: {embedding.Value} Key: {key.Value}") - { - } - - /// - /// Initializes an instance of the class. - /// - /// The embedding identifier. - public FailedToGetEmbeddingState(EmbeddingId embedding) - : base($"Failed to get embedding's state: Id: {embedding.Value}") - { - } -} \ No newline at end of file diff --git a/Source/Embeddings.Store/FailedToRemoveEmbedding.cs b/Source/Embeddings.Store/FailedToRemoveEmbedding.cs deleted file mode 100644 index 8181a6d39..000000000 --- a/Source/Embeddings.Store/FailedToRemoveEmbedding.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Aggregates; -using Dolittle.Runtime.Projections.Store; - -namespace Dolittle.Runtime.Embeddings.Store; - -/// -/// Exception that gets thrown when the embedding store failed to remove an embedding. -/// -public class FailedToRemoveEmbedding : Exception -{ - - /// - /// Initializes an instance of the class. - /// - /// The embedding identifier. - /// The projection key - /// The aggregate root version. - public FailedToRemoveEmbedding(EmbeddingId embedding, ProjectionKey key, AggregateRootVersion version) - : base($"Failed to remove embedding with id {embedding.Value}, key {key.Value} and aggregate root version {version.Value}") - { - } -} diff --git a/Source/Embeddings.Store/FailedToReplaceEmbedding.cs b/Source/Embeddings.Store/FailedToReplaceEmbedding.cs deleted file mode 100644 index 59886c441..000000000 --- a/Source/Embeddings.Store/FailedToReplaceEmbedding.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Aggregates; -using Dolittle.Runtime.Projections.Store; -using Dolittle.Runtime.Projections.Store.State; - -namespace Dolittle.Runtime.Embeddings.Store; - -/// -/// Exception that gets thrown when the embedding store failed to replace an embedding. -/// -public class FailedToReplaceEmbedding : Exception -{ - /// - /// Initializes an instance of the class. - /// - /// The embedding identifier. - /// The projection key - /// The aggregate root version. - /// The new projection state. - public FailedToReplaceEmbedding(EmbeddingId embedding, ProjectionKey key, AggregateRootVersion version, ProjectionState state) - : base($"Failed to replace embedding with id {embedding.Value}, key {key.Value} and aggregate root version {version.Value} with state {state.Value}") - { - } -} diff --git a/Source/Embeddings.Store/IEmbeddingStore.cs b/Source/Embeddings.Store/IEmbeddingStore.cs deleted file mode 100644 index 70fdc368b..000000000 --- a/Source/Embeddings.Store/IEmbeddingStore.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Dolittle.Runtime.Embeddings.Store; - -/// -/// Defines a system that can knows about persisted embeddings in the embedding store. -/// -public interface IEmbeddingStore : IFetchEmbeddingKeys, IFetchEmbeddingStates, IWriteEmbeddingStates -{ -} \ No newline at end of file diff --git a/Source/Embeddings.Store/IFetchEmbeddingKeys.cs b/Source/Embeddings.Store/IFetchEmbeddingKeys.cs deleted file mode 100644 index f8038727f..000000000 --- a/Source/Embeddings.Store/IFetchEmbeddingKeys.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Projections.Store; -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Embeddings.Store; - -/// -/// Defines a system that can fetch embedding keys from the embedding store. -/// -public interface IFetchEmbeddingKeys -{ - /// - /// Try to get all keys for an embedding. - /// - /// The embedding id. - /// The . - /// A that, when resolved, returns of of . - Task>> TryGetKeys(EmbeddingId embedding, CancellationToken cancellationToken); - - /// - /// Try to get all keys for an embedding. - /// - /// The embedding id. - /// Whether to get removed embedding too. - /// The . - /// A that, when resolved, returns of of . - Task>> TryGetKeys(EmbeddingId embedding, bool includeRemoved, CancellationToken cancellationToken); -} \ No newline at end of file diff --git a/Source/Embeddings.Store/IFetchEmbeddingStates.cs b/Source/Embeddings.Store/IFetchEmbeddingStates.cs deleted file mode 100644 index 992751b05..000000000 --- a/Source/Embeddings.Store/IFetchEmbeddingStates.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Projections.Store; -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Embeddings.Store; - -/// -/// Defines a system that can fetch embedding states from the embedding store. -/// -public interface IFetchEmbeddingStates -{ - /// - /// Try to get the state of an embedding by id and key. - /// - /// The embedding id. - /// The projection key. - /// The . - /// A that, when resolved, returns of . If the found embedding is marked as removed, returns the inital state. - Task> TryGet(EmbeddingId embedding, ProjectionKey key, CancellationToken cancellationToken); - - /// - /// Try to get all the states of an embedding by id. - /// - /// The embedding id. - /// The . - /// A that, when resolved, returns of . - Task>> TryGetAll(EmbeddingId embedding, CancellationToken cancellationToken); - - /// - /// Try to get all the states of an embedding by id. - /// - /// The embedding id. - /// Whether to include removed embeddings in the result too. - /// The . - /// A that, when resolved, returns of . - Task>> TryGetAll(EmbeddingId embedding, bool includeRemoved, CancellationToken cancellationToken); -} \ No newline at end of file diff --git a/Source/Embeddings.Store/IWriteEmbeddingStates.cs b/Source/Embeddings.Store/IWriteEmbeddingStates.cs deleted file mode 100644 index 1496ba889..000000000 --- a/Source/Embeddings.Store/IWriteEmbeddingStates.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Aggregates; -using Dolittle.Runtime.Projections.Store; -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Embeddings.Store; - -/// -/// Defines a system that can write embedding states to the embedding store. -/// -public interface IWriteEmbeddingStates -{ - /// - /// Try to replace a specific embedding state by key. - /// - /// The embedding id. - /// The projection key. - /// The corresponding to this state. - /// The new projection state. - /// The . - /// A that, when resolved, returns value indicating whether the state was successfully replaced. - Task TryReplace(EmbeddingId embedding, ProjectionKey key, AggregateRootVersion version, ProjectionState state, CancellationToken cancellationToken); - - /// - /// Try to remove a specific embedding state by key. - /// - /// The embedding id. - /// The projection key. - /// The corresponding to the deletion. - /// The . - /// A that, when resolved, returns value indicating whether the state was successfully removed. - Task TryRemove(EmbeddingId embedding, ProjectionKey key, AggregateRootVersion version, CancellationToken cancellationToken); -} diff --git a/Source/Embeddings.Store/LoggerExtensions.cs b/Source/Embeddings.Store/LoggerExtensions.cs deleted file mode 100644 index 0ab9180b1..000000000 --- a/Source/Embeddings.Store/LoggerExtensions.cs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Aggregates; -using Dolittle.Runtime.Projections.Store; -using Dolittle.Runtime.Projections.Store.State; -using Microsoft.Extensions.Logging; - -namespace Dolittle.Runtime.Embeddings.Store; - -static class LoggerExtensions -{ - static readonly Action _gettingOneEmbedding = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(2006779877, nameof(GettingOneEmbedding)), - "Getting state for embedding {Embedding} with key {Key}"); - - internal static void GettingOneEmbedding(this ILogger logger, EmbeddingId embedding, ProjectionKey key) - => _gettingOneEmbedding(logger, embedding, key, null); - - static readonly Action _errorGettingOneEmbedding = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(235391867, nameof(ErrorGettingOneEmbedding)), - "Error getting state for embedding {Embedding} with key {Key}"); - - internal static void ErrorGettingOneEmbedding(this ILogger logger, EmbeddingId embedding, ProjectionKey key, Exception exception) - => _errorGettingOneEmbedding(logger, embedding, key, exception); - - static readonly Action _gettingAllEmbeddings = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(340579607, nameof(GettingAllEmbeddings)), - "Getting all states for embedding {Embedding}"); - - internal static void GettingAllEmbeddings(this ILogger logger, EmbeddingId embedding) - => _gettingAllEmbeddings(logger, embedding, null); - - static readonly Action _errorGettingAllEmbeddings = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(1901764417, nameof(ErrorGettingAllEmbeddings)), - "Error getting all states for embedding {Embedding}"); - - internal static void ErrorGettingAllEmbeddings(this ILogger logger, EmbeddingId embedding, Exception exception) - => _errorGettingAllEmbeddings(logger, embedding, exception); - - static readonly Action _gettingEmbeddingKeys = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(403575857, nameof(GettingEmbeddingKeys)), - "Getting keys for embedding {Embedding}"); - - internal static void GettingEmbeddingKeys(this ILogger logger, EmbeddingId embedding) - => _gettingEmbeddingKeys(logger, embedding, null); - - static readonly Action _errorGettingEmbeddingKeys = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(298297742, nameof(ErrorGettingEmbeddingKeys)), - "Error getting keys for embedding {Embedding}"); - - internal static void ErrorGettingEmbeddingKeys(this ILogger logger, EmbeddingId embedding, Exception exception) - => _errorGettingEmbeddingKeys(logger, embedding, exception); - - static readonly Action _removingEmbedding = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(293285248, nameof(RemovingEmbedding)), - "Removing embedding with id {Embedding}, key {Key} and version {Version}"); - - internal static void RemovingEmbedding(this ILogger logger, EmbeddingId embedding, ProjectionKey key, AggregateRootVersion version) - => _removingEmbedding(logger, embedding, key, version, null); - - static readonly Action _errorRemovingEmbedding = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(87120798, nameof(ErrorRemovingEmbedding)), - "Error removing embedding with id {Embedding}, key {Key} and version {Version}"); - - internal static void ErrorRemovingEmbedding(this ILogger logger, EmbeddingId embedding, ProjectionKey key, AggregateRootVersion version, Exception exception) - => _errorRemovingEmbedding(logger, embedding, key, version, exception); - - static readonly Action _replacingEmbedding = LoggerMessage - .Define( - LogLevel.Debug, - new EventId(646882857, nameof(ReplacingEmbedding)), - "Replacing embedding with id {Embedding}, key {Key} and version {Version} with state {State}"); - - internal static void ReplacingEmbedding(this ILogger logger, EmbeddingId embedding, ProjectionKey key, AggregateRootVersion version, ProjectionState state) - => _replacingEmbedding(logger, embedding, key, version, state, null); - - static readonly Action _errorReplacingEmbedding = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(221665652, nameof(ErrorReplacingEmbedding)), - "Error replacing embedding with id {Embedding}, key {Key} and version {Version} with state {State}"); - - internal static void ErrorReplacingEmbedding(this ILogger logger, EmbeddingId embedding, ProjectionKey key, AggregateRootVersion version, ProjectionState state, Exception exception) - => _errorReplacingEmbedding(logger, embedding, key, version, state, exception); -} diff --git a/Source/Embeddings.Store/State/EmbeddingState.cs b/Source/Embeddings.Store/State/EmbeddingState.cs deleted file mode 100644 index c341866c6..000000000 --- a/Source/Embeddings.Store/State/EmbeddingState.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Aggregates; -using Dolittle.Runtime.Projections.Store.State; - -namespace Dolittle.Runtime.Embeddings.Store.State; - -/// -/// Represents the state of an embedding tied to an aggregate root version. -/// -/// The state. -/// The aggregate root version the state was calculated from. -public record EmbeddingState(ProjectionState State, AggregateRootVersion Version, bool IsRemoved); diff --git a/Source/Embeddings.Store/State/IEmbeddingStates.cs b/Source/Embeddings.Store/State/IEmbeddingStates.cs deleted file mode 100644 index da4b4ad03..000000000 --- a/Source/Embeddings.Store/State/IEmbeddingStates.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Aggregates; -using Dolittle.Runtime.Projections.Store; -using Dolittle.Runtime.Projections.Store.State; -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Embeddings.Store.State; - -/// -/// Defines the repository for the embeddings . -/// -public interface IEmbeddingStates -{ - /// - /// Try to get a specific . - /// - /// The embedding id. - /// The embedding key. - /// The . - /// A that, when resolved, returns of . - Task> TryGet(EmbeddingId embedding, ProjectionKey key, CancellationToken token); - - /// - /// Try to get all . - /// - /// The embedding id. - /// The . - /// A that, when resolved, returns of . - Task>> TryGetAll(EmbeddingId embedding, CancellationToken token); - - /// - /// Try to replace a specific . - /// - /// The embedding id. - /// The embedding key. - /// The new embedding state. - /// The . - /// A that, when resolved, returns indicating whether the state was successfully replaced. - Task> TryReplace(EmbeddingId embedding, ProjectionKey key, EmbeddingState state, CancellationToken token); - - /// - /// Try to mark a specific as removed. - /// - /// The embedding id. - /// The embedding key. - /// The . - /// The . - /// A that, when resolved, returns value indicating whether the state was successfully removed. - Task> TryMarkAsRemove(EmbeddingId embedding, ProjectionKey key, AggregateRootVersion version, CancellationToken token); - - /// - /// Try to drop the whole collection. - /// - /// The embedding id. - /// The . - /// A that, when resolved, returns value indicating whether the embedding collection was successfully dropped. - Task TryDrop(EmbeddingId embedding, CancellationToken token); -} diff --git a/Source/Embeddings.Store/UnknownProjectionCurrentStateType.cs b/Source/Embeddings.Store/UnknownProjectionCurrentStateType.cs deleted file mode 100644 index b7c47c8b3..000000000 --- a/Source/Embeddings.Store/UnknownProjectionCurrentStateType.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; - -namespace Dolittle.Runtime.Embeddings.Store; - -/// -/// Exception that gets thrown when attempting to convert a that is not known. -/// -public class UnknownEmbeddingCurrentStateType : Exception -{ - /// - /// Initializes an instance of the class. - /// - /// The current state type that is not known. - public UnknownEmbeddingCurrentStateType(EmbeddingCurrentStateType type) - : base($"{nameof(EmbeddingCurrentStateType)} {type} is not known") - { - } -} \ No newline at end of file diff --git a/Source/EventHorizon/Consumer/Connections/EventHorizonConnection.cs b/Source/EventHorizon/Consumer/Connections/EventHorizonConnection.cs index d33f60f5e..a44c1a045 100644 --- a/Source/EventHorizon/Consumer/Connections/EventHorizonConnection.cs +++ b/Source/EventHorizon/Consumer/Connections/EventHorizonConnection.cs @@ -149,4 +149,9 @@ static ConsumerSubscriptionRequest CreateRequest(SubscriptionId subscription, St static ConsumerResponse CreateSuccessfulResponse() => new(); static ConsumerResponse CreateFailureResponse(Failure failure) => new() { Failure = failure }; + + public void Dispose() + { + _reverseCallClient?.Dispose(); + } } diff --git a/Source/EventHorizon/Consumer/Connections/IEventHorizonConnection.cs b/Source/EventHorizon/Consumer/Connections/IEventHorizonConnection.cs index 13b0a5905..238a4d2ee 100644 --- a/Source/EventHorizon/Consumer/Connections/IEventHorizonConnection.cs +++ b/Source/EventHorizon/Consumer/Connections/IEventHorizonConnection.cs @@ -1,6 +1,7 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using System.Threading; using System.Threading.Tasks; using Dolittle.Runtime.Events.Store.Streams; @@ -11,7 +12,7 @@ namespace Dolittle.Runtime.EventHorizon.Consumer.Connections; /// /// Defines an event horizon connection to a producer microservice Runtime. /// -public interface IEventHorizonConnection +public interface IEventHorizonConnection : IDisposable { /// /// Connects to the producer Runtime, and returns the response. diff --git a/Source/EventHorizon/Consumer/Processing/EventProcessor.cs b/Source/EventHorizon/Consumer/Processing/EventProcessor.cs index 8c2899081..75def3269 100644 --- a/Source/EventHorizon/Consumer/Processing/EventProcessor.cs +++ b/Source/EventHorizon/Consumer/Processing/EventProcessor.cs @@ -77,6 +77,6 @@ async Task Process(CommittedEvent @event, CancellationToken c _logger.LogWarning(e, "Failed to commit external event"); _metrics.IncrementTotalEventHorizonEventWritesFailed(); } - return new SuccessfulProcessing(); + return SuccessfulProcessing.Instance; } } diff --git a/Source/EventHorizon/Consumer/Processing/EventProcessorPolicies.cs b/Source/EventHorizon/Consumer/Processing/EventProcessorPolicies.cs index cb919ab6f..33afddb93 100644 --- a/Source/EventHorizon/Consumer/Processing/EventProcessorPolicies.cs +++ b/Source/EventHorizon/Consumer/Processing/EventProcessorPolicies.cs @@ -3,7 +3,6 @@ using System; using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; using Microsoft.Extensions.Logging; using Polly; diff --git a/Source/EventHorizon/Consumer/Processing/EventsFromEventHorizonFetcher.cs b/Source/EventHorizon/Consumer/Processing/EventsFromEventHorizonFetcher.cs index 3c91c8ec5..197485abf 100644 --- a/Source/EventHorizon/Consumer/Processing/EventsFromEventHorizonFetcher.cs +++ b/Source/EventHorizon/Consumer/Processing/EventsFromEventHorizonFetcher.cs @@ -32,14 +32,14 @@ public EventsFromEventHorizonFetcher(AsyncProducerConsumerQueue eve } /// - public async Task>> Fetch(StreamPosition streamPosition, CancellationToken cancellationToken) + public async Task>> Fetch(StreamPosition position, CancellationToken cancellationToken) { try { //TODO: This can be improved by taking as many as possible instead of just the first var @event = await _events.DequeueAsync(cancellationToken).ConfigureAwait(false); _metrics.IncrementTotalEventsFetched(); - return new [] { @event }; + return new[] { @event }; } catch (Exception ex) { @@ -47,6 +47,14 @@ public async Task>> Fetch(StreamPosition streamPosi } } + /// Unused + public Task> FetchSingle(StreamPosition _, CancellationToken cancellationToken) => + throw new NotImplementedException("unused for eventhorizon"); + + /// Unused + public Task> FetchLast(CancellationToken cancellationToken) => + throw new NotImplementedException("unused for eventhorizon"); + /// public async Task> GetNextStreamPosition(CancellationToken cancellationToken) => new NotImplementedException("GetNextStreamPosition should never be used on this specific fetcher"); @@ -65,7 +73,8 @@ public void NotifyForEvent(StreamId stream, StreamPosition position) public Task WaitForEvent(ScopeId scope, StreamId stream, StreamPosition position, CancellationToken token) => Task.Delay(60 * 1000, token); /// - public Task WaitForEvent(ScopeId scope, StreamId stream, StreamPosition position, TimeSpan timeout, CancellationToken token) => Task.Delay(60 * 1000, token); + public Task WaitForEvent(ScopeId scope, StreamId stream, StreamPosition position, TimeSpan timeout, CancellationToken token) => + Task.Delay(60 * 1000, token); /// public Task WaitForEvent(ScopeId scope, StreamId stream, TimeSpan timeout, CancellationToken token) => Task.Delay(60 * 1000, token); diff --git a/Source/EventHorizon/Consumer/Processing/GetNextEventToReceiveForSubscription.cs b/Source/EventHorizon/Consumer/Processing/GetNextEventToReceiveForSubscription.cs index 727155818..c5a699d8d 100644 --- a/Source/EventHorizon/Consumer/Processing/GetNextEventToReceiveForSubscription.cs +++ b/Source/EventHorizon/Consumer/Processing/GetNextEventToReceiveForSubscription.cs @@ -12,13 +12,13 @@ namespace Dolittle.Runtime.EventHorizon.Consumer.Processing; /// public class GetNextEventToReceiveForSubscription : IGetNextEventToReceiveForSubscription { - readonly IStreamProcessorStateRepository _repository; + readonly IStreamProcessorStates _repository; /// /// Initializes a new instance of the class. /// /// The stream processor state repository to use for getting subscription states. - public GetNextEventToReceiveForSubscription(IStreamProcessorStateRepository repository) + public GetNextEventToReceiveForSubscription(IStreamProcessorStates repository) { _repository = repository; } @@ -28,7 +28,7 @@ public async Task GetNextEventToReceiveFor(SubscriptionId subscr { var tryGetState = await _repository.TryGetFor(subscriptionId, cancellationToken).ConfigureAwait(false); return tryGetState.Success - ? tryGetState.Result.Position + ? tryGetState.Result.Position.StreamPosition : StreamPosition.Start; } -} \ No newline at end of file +} diff --git a/Source/EventHorizon/Consumer/Processing/StreamProcessor.cs b/Source/EventHorizon/Consumer/Processing/StreamProcessor.cs index bf6554acb..1c66616b9 100644 --- a/Source/EventHorizon/Consumer/Processing/StreamProcessor.cs +++ b/Source/EventHorizon/Consumer/Processing/StreamProcessor.cs @@ -20,7 +20,7 @@ public class StreamProcessor : IStreamProcessor readonly SubscriptionId _identifier; readonly ExecutionContext _executionContext; readonly IEventProcessor _eventProcessor; - readonly IResilientStreamProcessorStateRepository _streamProcessorStates; + readonly IStreamProcessorStates _streamProcessorStates; readonly EventsFromEventHorizonFetcher _eventsFetcher; readonly IEventFetcherPolicies _eventsFetcherPolicy; readonly IMetricsCollector _metrics; @@ -44,7 +44,7 @@ public StreamProcessor( ExecutionContext executionContext, IEventProcessor eventProcessor, EventsFromEventHorizonFetcher eventsFetcher, - IResilientStreamProcessorStateRepository streamProcessorStates, + IStreamProcessorStates streamProcessorStates, IEventFetcherPolicies eventsFetcherPolicy, IMetricsCollector metrics, ILoggerFactory loggerFactory) @@ -78,6 +78,8 @@ public async Task StartAndWait(CancellationToken cancellationToken) _started = true; var tryGetStreamProcessorState = await _streamProcessorStates.TryGetFor(_identifier, cancellationToken).ConfigureAwait(false); + + if (!tryGetStreamProcessorState.Success) { Log.StreamProcessorPersistingNewState(_logger, _identifier); @@ -86,7 +88,7 @@ public async Task StartAndWait(CancellationToken cancellationToken) } else { - Log.StreamProcessorFetchedState(_logger, _identifier, tryGetStreamProcessorState.Result.Position); + Log.StreamProcessorFetchedState(_logger, _identifier, tryGetStreamProcessorState.Result.Position.StreamPosition); } _metrics.IncrementTotalStreamProcessorStarted(); @@ -101,7 +103,6 @@ public async Task StartAndWait(CancellationToken cancellationToken) _executionContext, _eventsFetcherPolicy, _eventsFetcher, - new TimeToRetryForUnpartitionedStreamProcessor(), _loggerFactory.CreateLogger()).Start(cancellationToken).ConfigureAwait(false); } } diff --git a/Source/EventHorizon/Consumer/Processing/StreamProcessorFactory.cs b/Source/EventHorizon/Consumer/Processing/StreamProcessorFactory.cs index e495f0b2c..153f99058 100644 --- a/Source/EventHorizon/Consumer/Processing/StreamProcessorFactory.cs +++ b/Source/EventHorizon/Consumer/Processing/StreamProcessorFactory.cs @@ -18,7 +18,7 @@ namespace Dolittle.Runtime.EventHorizon.Consumer.Processing; [Singleton, PerTenant] public class StreamProcessorFactory : IStreamProcessorFactory { - readonly IResilientStreamProcessorStateRepository _streamProcessorStates; + readonly IStreamProcessorStates _streamProcessorStates; readonly ICommitExternalEvents _externalEventsCommitter; readonly IEventFetcherPolicies _eventsFetcherPolicy; readonly IMetricsCollector _metrics; @@ -27,13 +27,13 @@ public class StreamProcessorFactory : IStreamProcessorFactory /// /// Initializes an instance of the class. /// - /// The . + /// The . /// The /// The . /// The system for collecting metrics. /// The . public StreamProcessorFactory( - IResilientStreamProcessorStateRepository streamProcessorStates, + IStreamProcessorStates streamProcessorStates, ICommitExternalEvents externalEventsCommitter, IEventFetcherPolicies eventsFetcherPolicy, IMetricsCollector metrics, diff --git a/Source/EventHorizon/Consumer/Subscription.cs b/Source/EventHorizon/Consumer/Subscription.cs index a5f63942e..93df81415 100644 --- a/Source/EventHorizon/Consumer/Subscription.cs +++ b/Source/EventHorizon/Consumer/Subscription.cs @@ -135,7 +135,9 @@ async Task SubscribeLoop(CancellationToken cancellationToken) try { - var (connection, response) = await ConnectToEventHorizon(cancellationToken).ConfigureAwait(false); + var connectionAndResponse = await ConnectToEventHorizon(cancellationToken).ConfigureAwait(false); + var response = connectionAndResponse.Item2; + using var connection = connectionAndResponse.Item1; if (response.Success) { _metrics.IncrementCurrentConnectedSubscriptions(); diff --git a/Source/EventHorizon/Consumer/SubscriptionId.cs b/Source/EventHorizon/Consumer/SubscriptionId.cs deleted file mode 100644 index 7b9ac15ed..000000000 --- a/Source/EventHorizon/Consumer/SubscriptionId.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Domain.Platform; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; - -namespace Dolittle.Runtime.EventHorizon.Consumer; - -/// -/// Represents an the unique identifier of an Event Horizon Subscription. -/// -public record SubscriptionId( - TenantId ConsumerTenantId, - MicroserviceId ProducerMicroserviceId, - TenantId ProducerTenantId, - ScopeId ScopeId, - StreamId StreamId, - PartitionId PartitionId) : IStreamProcessorId -{ - /// - public override string ToString() => $"Consumer Tenant: {ConsumerTenantId.Value} Producer Microservice: {ProducerMicroserviceId.Value} Producer Tenant: {ProducerTenantId.Value} Scope: {ScopeId.Value} Stream: {StreamId.Value} Partition: {PartitionId.Value}'"; -} diff --git a/Source/EventHorizon/EventHorizon.csproj b/Source/EventHorizon/EventHorizon.csproj index de59a2b1b..41f32c06e 100644 --- a/Source/EventHorizon/EventHorizon.csproj +++ b/Source/EventHorizon/EventHorizon.csproj @@ -16,10 +16,9 @@ - - + diff --git a/Source/EventHorizon/Producer/ConsumerProtocol.cs b/Source/EventHorizon/Producer/ConsumerProtocol.cs index a173d0251..bb3d920ae 100644 --- a/Source/EventHorizon/Producer/ConsumerProtocol.cs +++ b/Source/EventHorizon/Producer/ConsumerProtocol.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; using Dolittle.Runtime.Protobuf; using Dolittle.Services.Contracts; using Dolittle.Runtime.EventHorizon.Contracts; diff --git a/Source/EventHorizon/Producer/ConsumerService.cs b/Source/EventHorizon/Producer/ConsumerService.cs index 72cd461d0..f2f0b1c7b 100644 --- a/Source/EventHorizon/Producer/ConsumerService.cs +++ b/Source/EventHorizon/Producer/ConsumerService.cs @@ -105,11 +105,15 @@ public override async Task Subscribe( _metrics.IncrementTotalRejectedSubscriptions(); await dispatcher.Reject(failureResponse, context.CancellationToken).ConfigureAwait(false); return; - } else { - consent = ConsentId.NoConsent; } - } + if (!_tenants.All.Contains(arguments.ProducerTenant)) + { + await dispatcher.Reject(MissingProducerTenantResponse(arguments), context.CancellationToken).ConfigureAwait(false); + } + + consent = ConsentId.NoConsent; + } _metrics.IncrementTotalAcceptedSubscriptions(); Log.SuccessfullySubscribed( @@ -123,6 +127,16 @@ public override async Task Subscribe( await _eventHorizons.Start(dispatcher, arguments, consent, context.CancellationToken).ConfigureAwait(false); } + static SubscriptionResponse MissingProducerTenantResponse(ConsumerSubscriptionArguments arguments) => + new() + { + Failure = new ProtobufContracts.Failure + { + Id = SubscriptionFailures.MissingProducerTenant.ToProtobuf(), + Reason = $"Producer tenant '{arguments.ProducerTenant}' does not exist" + } + }; + bool TryGetConsent(ConsumerSubscriptionArguments arguments, out ConsentId consent, out SubscriptionResponse failureResponse) { consent = ConsentId.NoConsent; diff --git a/Source/EventHorizon/Producer/EventHorizon.cs b/Source/EventHorizon/Producer/EventHorizon.cs index 9f9fc22e5..db2a7fe1a 100644 --- a/Source/EventHorizon/Producer/EventHorizon.cs +++ b/Source/EventHorizon/Producer/EventHorizon.cs @@ -161,7 +161,7 @@ await eventWaiter.WaitForEvent( _cancellationTokenSource.Token).ConfigureAwait(false); continue; } - + var streamEvents = tryGetStreamEvent.Result; foreach (var streamEvent in streamEvents) { @@ -175,7 +175,7 @@ await eventWaiter.WaitForEvent( Log.ErrorOccurredWhileHandlingRequest(_logger, response.Failure.Id.ToGuid(), response.Failure.Reason); return; } - + CurrentPosition = streamEvent.Position + 1; } } diff --git a/Source/EventHorizon/Producer/EventHorizonAlreadyRegistered.cs b/Source/EventHorizon/Producer/EventHorizonAlreadyRegistered.cs index ade160dae..0efa2688b 100644 --- a/Source/EventHorizon/Producer/EventHorizonAlreadyRegistered.cs +++ b/Source/EventHorizon/Producer/EventHorizonAlreadyRegistered.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Protobuf; namespace Dolittle.Runtime.EventHorizon.Producer; diff --git a/Source/EventHorizon/Producer/SubscriptionFailures.cs b/Source/EventHorizon/Producer/SubscriptionFailures.cs index 53d0453ec..c2ce44ab5 100644 --- a/Source/EventHorizon/Producer/SubscriptionFailures.cs +++ b/Source/EventHorizon/Producer/SubscriptionFailures.cs @@ -14,6 +14,7 @@ public static class SubscriptionFailures /// Gets the that represents the 'MissingConsent' failure type. /// public static FailureId MissingConsent => FailureId.Create("be1ba4e6-81e3-49c4-bec2-6c7e262bfb77"); + public static FailureId MissingProducerTenant => FailureId.Create("733d0c4f-fc25-4b60-acdf-cac5ee661f23"); /// /// Gets the that represents the 'MissingSubscriptionArguments' failure type. diff --git a/Source/Events.Management/Events.Management.csproj b/Source/Events.Management/Events.Management.csproj deleted file mode 100644 index 30032b565..000000000 --- a/Source/Events.Management/Events.Management.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Dolittle.Runtime.Events.Management - Dolittle.Runtime.Events.Management - - - - - - - - - - - - diff --git a/Source/Events.Processing.Management/Events.Processing.Management.csproj b/Source/Events.Processing.Management/Events.Processing.Management.csproj deleted file mode 100644 index 1c2916d29..000000000 --- a/Source/Events.Processing.Management/Events.Processing.Management.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - - Dolittle.Runtime.Events.Processing.Management - Dolittle.Runtime.Events.Processing.Management - - - - - - - - - - diff --git a/Source/Events.Processing/EventHandlers/EventHandler.cs b/Source/Events.Processing/EventHandlers/EventHandler.cs deleted file mode 100644 index 7e10ebccd..000000000 --- a/Source/Events.Processing/EventHandlers/EventHandler.cs +++ /dev/null @@ -1,357 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.ExceptionServices; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Artifacts; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Events.Processing.Filters; -using Dolittle.Runtime.Events.Processing.Streams; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Events.Store.Streams.Filters; -using Dolittle.Runtime.Protobuf; -using Dolittle.Runtime.Rudimentary; -using Microsoft.Extensions.Logging; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; - -namespace Dolittle.Runtime.Events.Processing.EventHandlers; - -/// -/// Represents an event handler in the system. -/// -/// -/// An event handler is a formalized type that consists of a filter and an event processor. -/// The filter filters off of an event log based on the types of events the handler is interested in -/// and puts these into a stream for the filter. From this new stream, the event processor will handle -/// the forwarding to the client for it to handle the event. -/// What sets an event handler apart is that it has a formalization around the stream definition that -/// consists of the events it is interested in, which is defined from the client. -/// -public class EventHandler : IEventHandler -{ - readonly IStreamProcessors _streamProcessors; - readonly IValidateFilterForAllTenants _filterValidator; - readonly IStreamDefinitions _streamDefinitions; - readonly EventHandlerRegistrationArguments _arguments; - readonly Func> _filterProcessorForTenant; - readonly Func _eventProcessorForTenant; - readonly Func _acceptRegistration; - readonly Func _rejectRegistration; - readonly IMetricsCollector _metrics; - readonly ILogger _logger; - readonly ExecutionContext _executionContext; - readonly CancellationTokenSource _cancellationTokenSource; - - bool _disposed; - - /// - /// Initializes a new instance of . - /// - /// The . - /// The for validating the filter definition. - /// The. - /// Connecting arguments. - /// - /// The event processor. - /// Accepts the event handler registration. - /// Rejects the event handler registration. - /// The collector to use for metrics. - /// Logger for logging. - /// The execution context for the event handler. - /// Cancellation token that can cancel the hierarchy. - public EventHandler( - IStreamProcessors streamProcessors, - IValidateFilterForAllTenants filterValidationForAllTenants, - IStreamDefinitions streamDefinitions, - EventHandlerRegistrationArguments arguments, - Func> filterProcessorForTenant, - Func eventProcessorForTenant, - Func acceptRegistration, - Func rejectRegistration, - IMetricsCollector metrics, - ILogger logger, - ExecutionContext executionContext, - CancellationToken cancellationToken) - { - _logger = logger; - _streamProcessors = streamProcessors; - _filterValidator = filterValidationForAllTenants; - _streamDefinitions = streamDefinitions; - _arguments = arguments; - _filterProcessorForTenant = filterProcessorForTenant; - _executionContext = executionContext; - _eventProcessorForTenant = eventProcessorForTenant; - _acceptRegistration = acceptRegistration; - _rejectRegistration = rejectRegistration; - _metrics = metrics; - _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - } - - StreamId TargetStream => _arguments.EventHandler.Value; - - /// - public EventHandlerInfo Info => new( - new EventHandlerId(_arguments.Scope, _arguments.EventHandler), - _arguments.HasAlias, - _arguments.Alias, - _arguments.EventTypes, - _arguments.Partitioned); - - public ScopeId Scope => _arguments.Scope.Value; - - public EventProcessorId EventProcessor => _arguments.EventHandler.Value; - - public IEnumerable EventTypes => _arguments.EventTypes; - - public bool Partitioned => _arguments.Partitioned; - - public StreamDefinition FilteredStreamDefinition => new( - new TypeFilterWithEventSourcePartitionDefinition( - TargetStream, - TargetStream, - EventTypes, - Partitioned)); - - public TypeFilterWithEventSourcePartitionDefinition FilterDefinition => new( - StreamId.EventLog, - TargetStream, - EventTypes, - Partitioned); - - StreamProcessor FilterStreamProcessor { get; set; } - - StreamProcessor EventProcessorStreamProcessor { get; set; } - - /// - public Try> GetEventHandlerCurrentState() - => EventProcessorStreamProcessor != default - ? EventProcessorStreamProcessor.GetCurrentStates() - : new EventHandlerNotRegistered(Info.Id); - - /// - public Task> ReprocessEventsFrom(TenantId tenant, StreamPosition position) - => EventProcessorStreamProcessor.SetToPosition(tenant, position); - - /// - public async Task>>> ReprocessAllEvents() - { - try - { - return Try>>.Succeeded(await EventProcessorStreamProcessor.SetToInitialPositionForAllTenants().ConfigureAwait(false)); - } - catch (Exception ex) - { - return ex; - } - } - - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Dispose managed and unmanaged resources. - /// - /// Whether to dispose managed resources. - protected virtual void Dispose(bool disposing) - { - if (_disposed) - { - return; - } - if (disposing) - { - FilterStreamProcessor?.Dispose(); - EventProcessorStreamProcessor?.Dispose(); - _cancellationTokenSource.Dispose(); - } - - _disposed = true; - } - - /// - public async Task RegisterAndStart() - { - _logger.ConnectingEventHandlerWithId(EventProcessor); - if (await RejectIfNonWriteableStream().ConfigureAwait(false) - || !await RegisterFilterStreamProcessor().ConfigureAwait(false) - || !await RegisterEventProcessorStreamProcessor().ConfigureAwait(false)) - { - return; - } - - await Start().ConfigureAwait(false); - } - - /// - public event EventHandlerRegistrationFailed? OnRegistrationFailed; - - async Task RejectIfNonWriteableStream() - { - if (!TargetStream.IsNonWriteable) - { - return false; - } - _logger.EventHandlerIsInvalid(EventProcessor); - await Fail( - EventHandlersFailures.CannotRegisterEventHandlerOnNonWriteableStream, - $"Cannot register Event Handler: '{EventProcessor.Value}' because it is an invalid Stream Id").ConfigureAwait(false); - - return true; - } - - async Task RegisterFilterStreamProcessor() - { - _logger.RegisteringStreamProcessorForFilter(EventProcessor); - return await RegisterStreamProcessor( - "EventHandler-Filter", - new EventLogStreamDefinition(), - _filterProcessorForTenant, - HandleFailedToRegisterFilter, - (streamProcessor) => FilterStreamProcessor = streamProcessor - ).ConfigureAwait(false); - } - - Failure HandleFailedToRegisterFilter(Exception exception) - { - _logger.ErrorWhileRegisteringStreamProcessorForFilter(exception, EventProcessor); - - if (exception is StreamProcessorAlreadyRegistered) - { - _logger.EventHandlerAlreadyRegistered(EventProcessor); - return new Failure( - EventHandlersFailures.FailedToRegisterEventHandler, - $"Failed to register Event Handler: {EventProcessor.Value}. Filter already registered"); - } - return new Failure( - EventHandlersFailures.FailedToRegisterEventHandler, - $"Failed to register Event Handler: {EventProcessor.Value}. An error occurred. {exception.Message}"); - } - - async Task RegisterEventProcessorStreamProcessor() - { - _logger.RegisteringStreamProcessorForEventProcessor(EventProcessor, TargetStream); - return await RegisterStreamProcessor( - "EventHandler-EventProcessor", - FilteredStreamDefinition, - _eventProcessorForTenant, - HandleFailedToRegisterEventProcessor, - (streamProcessor) => - { - EventProcessorStreamProcessor = streamProcessor; - streamProcessor.OnProcessedEvent += (tenant, @event, time) => - { - _metrics.IncrementEventsProcessedTotal(Info, tenant, @event, time); - }; - streamProcessor.OnFailedToProcessedEvent += (tenant, @event, time) => - { - _metrics.IncrementEventsProcessedTotal(Info, tenant, @event, time); - _metrics.IncrementEventProcessingFailuresTotal(Info, tenant, @event); - }; - }).ConfigureAwait(false); - } - - Failure HandleFailedToRegisterEventProcessor(Exception exception) - { - _logger.ErrorWhileRegisteringStreamProcessorForEventProcessor(exception, EventProcessor); - - if (exception is not StreamProcessorAlreadyRegistered) - { - return new Failure( - EventHandlersFailures.FailedToRegisterEventHandler, - $"Failed to register Event Handler: {EventProcessor.Value}. An error occurred. {exception.Message}"); - } - - _logger.EventHandlerAlreadyRegisteredOnSourceStream(EventProcessor); - return new Failure( - EventHandlersFailures.FailedToRegisterEventHandler, - $"Failed to register Event Handler: {EventProcessor.Value}. Event Processor already registered on Source Stream: '{EventProcessor.Value}'"); - } - - async Task RegisterStreamProcessor( - EventProcessorKind kind, - IStreamDefinition streamDefinition, - Func getProcessor, - Func onException, - Action onStreamProcessor) - { - var streamProcessor = _streamProcessors.TryCreateAndRegister( - Scope, - EventProcessor, - kind, - streamDefinition, - getProcessor, - _executionContext, - _cancellationTokenSource.Token); - - onStreamProcessor(streamProcessor); - - if (!streamProcessor.Success) - { - await Fail(onException(streamProcessor.Exception)).ConfigureAwait(false); - } - - return streamProcessor.Success; - } - - async Task Start() - { - _logger.StartingEventHandler(FilterDefinition.TargetStream); - try - { - var runningDispatcher = _acceptRegistration(_cancellationTokenSource.Token); - await FilterStreamProcessor.Initialize().ConfigureAwait(false); - await EventProcessorStreamProcessor.Initialize().ConfigureAwait(false); - await ValidateFilter().ConfigureAwait(false); - - var tasks = new TaskGroup(FilterStreamProcessor.Start(), EventProcessorStreamProcessor.Start(), runningDispatcher); - - tasks.OnFirstTaskFailure += (_, ex) => _logger.ErrorWhileRunningEventHandler(ex, EventProcessor, Scope); - tasks.OnAllTasksCompleted += () => _logger.EventHandlerDisconnected(EventProcessor, Scope); - - await tasks.WaitForAllCancellingOnFirst(_cancellationTokenSource).ConfigureAwait(false); - } - catch (Exception ex) - { - if (!_cancellationTokenSource.Token.IsCancellationRequested) - { - _logger.ErrorWhileStartingEventHandler(ex, EventProcessor, Scope); - } - ExceptionDispatchInfo.Capture(ex).Throw(); - } - } - - async Task ValidateFilter() - { - _logger.ValidatingFilter(FilterDefinition.TargetStream); - var filterValidationResults = await _filterValidator.Validate(_filterProcessorForTenant, _cancellationTokenSource.Token).ConfigureAwait(false); - - if (filterValidationResults.Any(_ => !_.Value.Success)) - { - var firstFailedValidation = filterValidationResults.First(_ => !_.Value.Success).Value; - _logger.FilterValidationFailed(FilterDefinition.TargetStream, firstFailedValidation.FailureReason); - throw new FilterValidationFailed(FilterDefinition.TargetStream, firstFailedValidation.FailureReason); - } - - var filteredStreamDefinition = new StreamDefinition(FilterDefinition); - _logger.PersistingStreamDefinition(filteredStreamDefinition.StreamId); - await _streamDefinitions.Persist(Scope, filteredStreamDefinition, _cancellationTokenSource.Token).ConfigureAwait(false); - } - - Task Fail(FailureId failureId, string message) - => Fail(new Failure(failureId, message)); - - Task Fail(Failure failure) - { - OnRegistrationFailed?.Invoke(); - return _rejectRegistration(failure, _cancellationTokenSource.Token); - } -} diff --git a/Source/Events.Processing/EventHandlers/EventHandlerFactory.cs b/Source/Events.Processing/EventHandlers/EventHandlerFactory.cs deleted file mode 100644 index 2ba82d470..000000000 --- a/Source/Events.Processing/EventHandlers/EventHandlerFactory.cs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Threading; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Events.Processing.Contracts; -using Dolittle.Runtime.Events.Processing.Filters; -using Dolittle.Runtime.Events.Processing.Streams; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Events.Store.Streams.Filters; -using Dolittle.Runtime.Protobuf; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using ReverseCallDispatcher = Dolittle.Runtime.Services.IReverseCallDispatcher< - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerClientToRuntimeMessage, - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRuntimeToClientMessage, - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRegistrationRequest, - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRegistrationResponse, - Dolittle.Runtime.Events.Processing.Contracts.HandleEventRequest, - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerResponse>; - - -namespace Dolittle.Runtime.Events.Processing.EventHandlers; - -/// -/// Represents an implementation of . -/// -public class EventHandlerFactory : IEventHandlerFactory -{ - readonly IStreamProcessors _streamProcessors; - readonly IFilterStreamProcessors _filterStreamProcessors; - readonly IValidateFilterForAllTenants _filterValidator; - readonly Func _getEventsToStreamsWriter; - readonly IStreamDefinitions _streamDefinitions; - readonly IMetricsCollector _metrics; - readonly ILoggerFactory _loggerFactory; - - /// - /// Initializes a new instance of the class. - /// - /// The . - /// The . - /// The for getting a tenant scoped . - /// The . - /// The collector to use for metrics. - /// The . - /// The . - public EventHandlerFactory( - IStreamProcessors streamProcessors, - IValidateFilterForAllTenants filterValidator, - Func getEventsToStreamsWriter, - IStreamDefinitions streamDefinitions, - IMetricsCollector metrics, - ILoggerFactory loggerFactory, - IFilterStreamProcessors filterStreamProcessors) - { - _streamProcessors = streamProcessors; - _filterValidator = filterValidator; - _getEventsToStreamsWriter = getEventsToStreamsWriter; - _streamDefinitions = streamDefinitions; - _metrics = metrics; - _loggerFactory = loggerFactory; - _filterStreamProcessors = filterStreamProcessors; - } - - /// - public IEventHandler Create(EventHandlerRegistrationArguments arguments, ReverseCallDispatcher dispatcher, CancellationToken cancellationToken) - => new EventHandler( - _streamProcessors, - _filterValidator, - _streamDefinitions, - arguments, - tenant => new TypeFilterWithEventSourcePartition( - arguments.Scope, - new TypeFilterWithEventSourcePartitionDefinition(StreamId.EventLog, arguments.EventHandler.Value, arguments.EventTypes ,arguments.Partitioned), - _getEventsToStreamsWriter(tenant), - _loggerFactory.CreateLogger()), - _ => new EventProcessor(arguments.Scope, arguments.EventHandler, dispatcher, _loggerFactory.CreateLogger()), - cancellation => dispatcher.Accept(new EventHandlerRegistrationResponse(), cancellation), - (failure, cancellation) => dispatcher.Reject(new EventHandlerRegistrationResponse{Failure = failure.ToProtobuf()}, cancellation), - _metrics, - _loggerFactory.CreateLogger(), - arguments.ExecutionContext, - cancellationToken - ); - - /// - public FastEventHandler CreateFast(EventHandlerRegistrationArguments arguments, bool implicitFilter, ReverseCallDispatcher dispatcher, CancellationToken cancellationToken) - => new( - implicitFilter, - _streamProcessors, - _filterStreamProcessors, - _filterValidator, - _streamDefinitions, - arguments, - tenant => new TypeFilterWithEventSourcePartition( - arguments.Scope, - new TypeFilterWithEventSourcePartitionDefinition(StreamId.EventLog, arguments.EventHandler.Value, arguments.EventTypes ,arguments.Partitioned), - _getEventsToStreamsWriter(tenant), - _loggerFactory.CreateLogger()), - _ => new EventProcessor(arguments.Scope, arguments.EventHandler, dispatcher, _loggerFactory.CreateLogger()), - cancellation => dispatcher.Accept(new EventHandlerRegistrationResponse(), cancellation), - (failure, cancellation) => dispatcher.Reject(new EventHandlerRegistrationResponse{Failure = failure.ToProtobuf()}, cancellation), - _metrics, - _loggerFactory.CreateLogger(), - arguments.ExecutionContext, - cancellationToken - ); -} diff --git a/Source/Events.Processing/EventHandlers/Fast/CreateScopedFilterStreamProcessors.cs b/Source/Events.Processing/EventHandlers/Fast/CreateScopedFilterStreamProcessors.cs deleted file mode 100644 index 1e13f0c04..000000000 --- a/Source/Events.Processing/EventHandlers/Fast/CreateScopedFilterStreamProcessors.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.ObjectModel; -using System.Linq; -using System.Threading; -using System.Threading.Channels; -using System.Threading.Tasks; -using Dolittle.Runtime.Artifacts; -using Dolittle.Runtime.DependencyInversion.Lifecycle; -using Dolittle.Runtime.DependencyInversion.Scoping; -using Dolittle.Runtime.Events.Processing.Streams; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Events.Store.Streams.Filters; - -namespace Dolittle.Runtime.Events.Processing.EventHandlers; - -/// -/// Represents an implementation . -/// -[Singleton, PerTenant] -public class CreateScopedFilterStreamProcessors : ICreateScopedFilterStreamProcessors -{ - readonly IResilientStreamProcessorStateRepository _streamProcessorStates; - readonly IStreamEventWatcher _streamWatcher; - readonly IEventLogStream _eventLogStream; - readonly Func, StreamProcessorId, bool, StreamProcessorState, ScopedFilterStreamProcessor> _createFilterStreamProcessor; - - /// - /// Initializes a new instance of the class. - /// - /// The stream processor states repository to use to get or create the current state of the stream processor. - /// The stream watcher to use to notify waiters when the stream processor is created.. - /// The . - /// The factory to use to create instances of unpartitioned stream processors. - public CreateScopedFilterStreamProcessors( - IResilientStreamProcessorStateRepository streamProcessorStates, - IStreamEventWatcher streamWatcher, - IEventLogStream eventLogStream, - Func, StreamProcessorId, bool, StreamProcessorState, ScopedFilterStreamProcessor> createFilterStreamProcessor) - { - _streamProcessorStates = streamProcessorStates; - _streamWatcher = streamWatcher; - _eventLogStream = eventLogStream; - _createFilterStreamProcessor = createFilterStreamProcessor; - } - - /// - public async Task Create( - TypeFilterWithEventSourcePartitionDefinition filterDefinition, - StreamProcessorId streamProcessorId, - CancellationToken cancellationToken) - { - var processorState = await GetOrCreateStreamProcessorState( - streamProcessorId, - StreamProcessorState.New, - cancellationToken) - .ConfigureAwait(false); - - if (processorState is not StreamProcessorState unpartitionedProcessorState) - { - throw new ExpectedUnpartitionedStreamProcessorState(streamProcessorId); - } - // TODO: This is not needed when using the fast event handler. - NotifyStream(streamProcessorId.ScopeId, filterDefinition, processorState.Position); - return _createFilterStreamProcessor( - _eventLogStream.Subscribe( - streamProcessorId.ScopeId, - processorState.Position.Value, - new ReadOnlyCollection(filterDefinition.Types.ToList()), - cancellationToken), - streamProcessorId, - filterDefinition.Partitioned, - unpartitionedProcessorState); - } - - async Task GetOrCreateStreamProcessorState(IStreamProcessorId streamProcessorId, IStreamProcessorState initialState, CancellationToken cancellationToken) - { - var tryGetStreamProcessorState = await _streamProcessorStates.TryGetFor(streamProcessorId, cancellationToken).ConfigureAwait(false); - - if (tryGetStreamProcessorState.Success) - { - return tryGetStreamProcessorState.Result; - } - - await _streamProcessorStates.Persist(streamProcessorId, initialState, cancellationToken).ConfigureAwait(false); - return initialState; - } - - void NotifyStream(ScopeId scopeId, TypeFilterWithEventSourcePartitionDefinition filterDefinition, StreamPosition position) - { - if (position == StreamPosition.Start) - { - return; - } - if (filterDefinition.Public) - { - _streamWatcher.NotifyForEvent(filterDefinition.TargetStream, position - 1); - } - else - { - _streamWatcher.NotifyForEvent(scopeId, filterDefinition.TargetStream, position - 1); - } - } -} diff --git a/Source/Events.Processing/EventHandlers/Fast/FastEventHandler.cs b/Source/Events.Processing/EventHandlers/Fast/FastEventHandler.cs deleted file mode 100644 index 676d95638..000000000 --- a/Source/Events.Processing/EventHandlers/Fast/FastEventHandler.cs +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.ExceptionServices; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Artifacts; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Events.Processing.Filters; -using Dolittle.Runtime.Events.Processing.Streams; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Events.Store.Streams.Filters; -using Dolittle.Runtime.Protobuf; -using Dolittle.Runtime.Rudimentary; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; - -namespace Dolittle.Runtime.Events.Processing.EventHandlers; - -/// -/// Represents an event handler in the system. -/// -/// -/// An event handler is a formalized type that consists of a filter and an event processor. -/// The filter filters off of an event log based on the types of events the handler is interested in -/// and puts these into a stream for the filter. From this new stream, the event processor will handle -/// the forwarding to the client for it to handle the event. -/// What sets an event handler apart is that it has a formalization around the stream definition that -/// consists of the events it is interested in, which is defined from the client. -/// -public class FastEventHandler : IEventHandler -{ - readonly IStreamProcessors _streamProcessors; - readonly IFilterStreamProcessors _filterStreamProcessors; - readonly IValidateFilterForAllTenants _filterValidator; - readonly IStreamDefinitions _streamDefinitions; - readonly EventHandlerRegistrationArguments _arguments; - readonly Func> _filterProcessorForTenant; - readonly Func _eventProcessorForTenant; - readonly Func _acceptRegistration; - readonly Func _rejectRegistration; - readonly IMetricsCollector _metrics; - readonly ExecutionContext _executionContext; - readonly bool _implicitFilter; - readonly ILogger _logger; - readonly CancellationTokenSource _cancellationTokenSource; - - bool _disposed; - - /// - /// Initializes a new instance of . - /// - /// Whether filtering is implicit. - /// The . - /// The . - /// The for validating the filter definition. - /// The. - /// Connecting arguments. - /// - /// The event processor. - /// Accepts the event handler registration. - /// Rejects the event handler registration. - /// The collector to use for metrics. - /// Logger for logging. - /// The execution context for the event handler. - /// Cancellation token that can cancel the hierarchy. - public FastEventHandler( - bool implicitFilter, - IStreamProcessors streamProcessors, - IFilterStreamProcessors filterStreamProcessors, - IValidateFilterForAllTenants filterValidationForAllTenants, - IStreamDefinitions streamDefinitions, - EventHandlerRegistrationArguments arguments, - Func> filterProcessorForTenant, - Func eventProcessorForTenant, - Func acceptRegistration, - Func rejectRegistration, - IMetricsCollector metrics, - ILogger logger, - ExecutionContext executionContext, - CancellationToken cancellationToken) - { - _implicitFilter = implicitFilter; - _logger = logger; - _streamProcessors = streamProcessors; - _filterStreamProcessors = filterStreamProcessors; - _filterValidator = filterValidationForAllTenants; - _streamDefinitions = streamDefinitions; - _arguments = arguments; - _filterProcessorForTenant = filterProcessorForTenant; - _executionContext = executionContext; - _eventProcessorForTenant = eventProcessorForTenant; - _acceptRegistration = acceptRegistration; - _rejectRegistration = rejectRegistration; - _metrics = metrics; - _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - } - - StreamId TargetStream => _arguments.EventHandler.Value; - - /// - public EventHandlerInfo Info => new( - new EventHandlerId(_arguments.Scope, _arguments.EventHandler), - _arguments.HasAlias, - _arguments.Alias, - _arguments.EventTypes, - _arguments.Partitioned); - - ScopeId Scope => _arguments.Scope.Value; - - EventProcessorId EventProcessor => _arguments.EventHandler.Value; - - IEnumerable EventTypes => _arguments.EventTypes; - - bool Partitioned => _arguments.Partitioned; - - StreamDefinition FilteredStreamDefinition => new( - new TypeFilterWithEventSourcePartitionDefinition( - TargetStream, - TargetStream, - EventTypes, - Partitioned)); - - TypeFilterWithEventSourcePartitionDefinition FilterDefinition => new( - StreamId.EventLog, - TargetStream, - EventTypes, - Partitioned); - - FilterStreamProcessor FilterStreamProcessor { get; set; } - - StreamProcessor EventProcessorStreamProcessor { get; set; } - - /// - public Try> GetEventHandlerCurrentState() - => EventProcessorStreamProcessor != default - ? EventProcessorStreamProcessor.GetCurrentStates() - : new EventHandlerNotRegistered(Info.Id); - - /// - public Task> ReprocessEventsFrom(TenantId tenant, StreamPosition position) - => EventProcessorStreamProcessor.SetToPosition(tenant, position); - - /// - public async Task>>> ReprocessAllEvents() - { - try - { - return Try>>.Succeeded(await EventProcessorStreamProcessor.SetToInitialPositionForAllTenants().ConfigureAwait(false)); - } - catch (Exception ex) - { - return ex; - } - } - - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Dispose managed and unmanaged resources. - /// - /// Whether to dispose managed resources. - protected virtual void Dispose(bool disposing) - { - if (_disposed) - { - return; - } - if (disposing) - { - FilterStreamProcessor?.Dispose(); - EventProcessorStreamProcessor?.Dispose(); - _cancellationTokenSource.Dispose(); - } - - _disposed = true; - } - - /// - public async Task RegisterAndStart() - { - _logger.ConnectingEventHandlerWithId(EventProcessor); - if (await RejectIfNonWriteableStream().ConfigureAwait(false) - || !await RegisterFilterStreamProcessor().ConfigureAwait(false) - || !await RegisterEventProcessorStreamProcessor().ConfigureAwait(false)) - { - return; - } - - await Start().ConfigureAwait(false); - } - - /// - public event EventHandlerRegistrationFailed? OnRegistrationFailed; - - async Task RejectIfNonWriteableStream() - { - if (!TargetStream.IsNonWriteable) - { - return false; - } - _logger.EventHandlerIsInvalid(EventProcessor); - await Fail( - EventHandlersFailures.CannotRegisterEventHandlerOnNonWriteableStream, - $"Cannot register Event Handler: '{EventProcessor.Value}' because it is an invalid Stream Id").ConfigureAwait(false); - - return true; - } - - async Task RegisterFilterStreamProcessor() - { - if (_implicitFilter) - { - return true; - } - - _logger.RegisteringStreamProcessorForFilter(EventProcessor); - return await RegisterFilterStreamProcessor( - FilterDefinition, - HandleFailedToRegisterFilter, - streamProcessor => FilterStreamProcessor = streamProcessor - ).ConfigureAwait(false); - } - - Failure HandleFailedToRegisterFilter(Exception exception) - { - _logger.ErrorWhileRegisteringStreamProcessorForFilter(exception, EventProcessor); - - if (exception is not StreamProcessorAlreadyRegistered) - { - return new Failure( - EventHandlersFailures.FailedToRegisterEventHandler, - $"Failed to register Event Handler: {EventProcessor.Value}. An error occurred. {exception.Message}"); - } - _logger.EventHandlerAlreadyRegistered(EventProcessor); - return new Failure( - EventHandlersFailures.FailedToRegisterEventHandler, - $"Failed to register Event Handler: {EventProcessor.Value}. Filter already registered"); - } - async Task RegisterEventProcessorStreamProcessor() - { - _logger.RegisteringStreamProcessorForEventProcessor(EventProcessor, TargetStream); - return await RegisterStreamProcessor( - FilteredStreamDefinition, - _eventProcessorForTenant, - HandleFailedToRegisterEventProcessor, - (streamProcessor) => - { - EventProcessorStreamProcessor = streamProcessor; - streamProcessor.OnProcessedEvent += (tenant, @event, time) => - { - _metrics.IncrementEventsProcessedTotal(Info, tenant, @event, time); - }; - streamProcessor.OnFailedToProcessedEvent += (tenant, @event, time) => - { - _metrics.IncrementEventsProcessedTotal(Info, tenant, @event, time); - _metrics.IncrementEventProcessingFailuresTotal(Info, tenant, @event); - }; - }).ConfigureAwait(false); - } - - Failure HandleFailedToRegisterEventProcessor(Exception exception) - { - _logger.ErrorWhileRegisteringStreamProcessorForEventProcessor(exception, EventProcessor); - - if (exception is not StreamProcessorAlreadyRegistered) - { - return new Failure( - EventHandlersFailures.FailedToRegisterEventHandler, - $"Failed to register Event Handler: {EventProcessor.Value}. An error occurred. {exception.Message}"); - } - - _logger.EventHandlerAlreadyRegisteredOnSourceStream(EventProcessor); - return new Failure( - EventHandlersFailures.FailedToRegisterEventHandler, - $"Failed to register Event Handler: {EventProcessor.Value}. Event Processor already registered on Source Stream: '{EventProcessor.Value}'"); - } - - async Task RegisterFilterStreamProcessor( - TypeFilterWithEventSourcePartitionDefinition filterDefinition, - Func onException, - Action onStreamProcessor) - { - var streamProcessor = _filterStreamProcessors.TryCreateAndRegister( - Scope, - filterDefinition, - _cancellationTokenSource.Token); - - onStreamProcessor(streamProcessor); - - if (!streamProcessor.Success) - { - await Fail(onException(streamProcessor.Exception)).ConfigureAwait(false); - } - - return streamProcessor.Success; - } - - async Task RegisterStreamProcessor( - IStreamDefinition streamDefinition, - Func getProcessor, - Func onException, - Action onStreamProcessor) - { - // TODO: Use fast stream processor for event handler processor - var streamProcessor = _streamProcessors.TryCreateAndRegister( - Scope, - EventProcessor, - "FastEventHandler-EventProcessor", - streamDefinition, - getProcessor, - _executionContext, - _cancellationTokenSource.Token); - - onStreamProcessor(streamProcessor); - - if (!streamProcessor.Success) - { - await Fail(onException(streamProcessor.Exception)).ConfigureAwait(false); - } - - return streamProcessor.Success; - } - - async Task Start() - { - _logger.StartingEventHandler(FilterDefinition.TargetStream); - try - { - var runningDispatcher = _acceptRegistration(_cancellationTokenSource.Token); - if (!_implicitFilter) - { - await FilterStreamProcessor.Initialize().ConfigureAwait(false); - } - await EventProcessorStreamProcessor.Initialize().ConfigureAwait(false); - await ValidateFilter().ConfigureAwait(false); - var tasks = new List - { - EventProcessorStreamProcessor.Start(), - runningDispatcher - }; - if (!_implicitFilter) - { - tasks.Add(FilterStreamProcessor.Start()); - } - var taskGroup = new TaskGroup(tasks); - - taskGroup.OnFirstTaskFailure += (_, ex) => _logger.ErrorWhileRunningEventHandler(ex, EventProcessor, Scope); - taskGroup.OnAllTasksCompleted += () => _logger.EventHandlerDisconnected(EventProcessor, Scope); - - await taskGroup.WaitForAllCancellingOnFirst(_cancellationTokenSource).ConfigureAwait(false); - } - catch (Exception ex) - { - if (!_cancellationTokenSource.Token.IsCancellationRequested) - { - _logger.ErrorWhileStartingEventHandler(ex, EventProcessor, Scope); - } - ExceptionDispatchInfo.Capture(ex).Throw(); - } - } - - async Task ValidateFilter() - { - _logger.ValidatingFilter(FilterDefinition.TargetStream); - var filterValidationResults = await _filterValidator.Validate(_filterProcessorForTenant, _cancellationTokenSource.Token).ConfigureAwait(false); - - if (filterValidationResults.Any(_ => !_.Value.Success)) - { - var firstFailedValidation = filterValidationResults.First(_ => !_.Value.Success).Value; - _logger.FilterValidationFailed(FilterDefinition.TargetStream, firstFailedValidation.FailureReason); - throw new FilterValidationFailed(FilterDefinition.TargetStream, firstFailedValidation.FailureReason); - } - - var filteredStreamDefinition = new StreamDefinition(FilterDefinition); - _logger.PersistingStreamDefinition(filteredStreamDefinition.StreamId); - await _streamDefinitions.Persist(Scope, filteredStreamDefinition, _cancellationTokenSource.Token).ConfigureAwait(false); - } - - Task Fail(FailureId failureId, string message) - => Fail(new Failure(failureId, message)); - - Task Fail(Failure failure) - { - OnRegistrationFailed?.Invoke(); - return _rejectRegistration(failure, _cancellationTokenSource.Token); - } -} diff --git a/Source/Events.Processing/EventHandlers/Fast/FilterStreamProcessor.cs b/Source/Events.Processing/EventHandlers/Fast/FilterStreamProcessor.cs deleted file mode 100644 index 0d2d54e2d..000000000 --- a/Source/Events.Processing/EventHandlers/Fast/FilterStreamProcessor.cs +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Events.Processing.Streams; -using Dolittle.Runtime.Events.Store.Streams.Filters; -using Dolittle.Runtime.Rudimentary; -using Dolittle.Runtime.Tenancy; -using Microsoft.Extensions.Logging; - -namespace Dolittle.Runtime.Events.Processing.EventHandlers; - -/// -/// Represents a fast stream processor meant to be used for the filter of an event handler. -/// TODO: This should be replaced at some point -/// -public class FilterStreamProcessor : IDisposable -{ - readonly TypeFilterWithEventSourcePartitionDefinition _filterDefinition; - readonly Action _unregister; - readonly StreamProcessorId _identifier; - readonly IPerformActionsForAllTenants _forAllTenants; - readonly Func _getCreateScopedStreamProcessors; - readonly ILogger _logger; - readonly CancellationTokenSource _stopAllScopedStreamProcessorsTokenSource; - - readonly Dictionary _streamProcessors = new(); - bool _initialized; - bool _started; - bool _disposed; - - /// - /// Initializes a new instance of the class. - /// - /// The stream processor id. - /// The filter definition. - /// The action to perform unregistering - /// The performer to use to create scoped stream processors for all tenants. - /// The factory to us to get the scoped stream processor creator per tenant. - /// The logger to use for logging. - /// The cancellation token that is cancelled when the stream processor should stop processing. - public FilterStreamProcessor( - StreamProcessorId streamProcessorId, - TypeFilterWithEventSourcePartitionDefinition filterDefinition, - Action unregister, - IPerformActionsForAllTenants forAllTenants, - Func getCreateScopedStreamProcessors, - ILogger logger, - CancellationToken cancellationToken) - { - _identifier = streamProcessorId; - _filterDefinition = filterDefinition; - _unregister = unregister; - _forAllTenants = forAllTenants; - _getCreateScopedStreamProcessors = getCreateScopedStreamProcessors; - _logger = logger; - _stopAllScopedStreamProcessorsTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - } - /// - /// Initializes the stream processor. - /// - /// A that represents the asynchronous operation. - public async Task Initialize() - { - _logger.InitializingFilterStreamProcessor(_identifier); - - _stopAllScopedStreamProcessorsTokenSource.Token.ThrowIfCancellationRequested(); - if (_initialized) - { - throw new StreamProcessorAlreadyInitialized(_identifier); - } - _initialized = true; - - await _forAllTenants.PerformAsync(async (tenant, _) => - { - var scopedStreamProcessor = await _getCreateScopedStreamProcessors(tenant).Create( - _filterDefinition, - _identifier, - _stopAllScopedStreamProcessorsTokenSource.Token).ConfigureAwait(false); - - _streamProcessors.Add(tenant, scopedStreamProcessor); - }).ConfigureAwait(false); - } - - /// - /// Starts the stream processing for all tenants. - /// - /// A representing the asynchronous operation. - public async Task Start() - { - _logger.StartingFilterStreamProcessor(_identifier); - - if (!_initialized) - { - throw new StreamProcessorNotInitialized(_identifier); - } - - if (_started) - { - throw new StreamProcessorAlreadyProcessingStream(_identifier); - } - - _started = true; - try - { - var tasks = new TaskGroup(StartScopedStreamProcessors(_stopAllScopedStreamProcessorsTokenSource.Token)); - - tasks.OnFirstTaskFailure += (_, ex) => _logger.ScopedFilterStreamProcessorFailed(ex, _identifier); - await tasks.WaitForAllCancellingOnFirst(_stopAllScopedStreamProcessorsTokenSource).ConfigureAwait(false); - } - finally - { - _unregister(); - } - } - - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Dispose the object. - /// - /// Whether to dispose managed state. - protected virtual void Dispose(bool disposing) - { - if (_disposed) - { - return; - } - - if (disposing) - { - _stopAllScopedStreamProcessorsTokenSource.Cancel(); - _stopAllScopedStreamProcessorsTokenSource.Dispose(); - - if (!_started) - { - _unregister(); - } - } - - _disposed = true; - } - - IEnumerable StartScopedStreamProcessors(CancellationToken cancellationToken) => _streamProcessors.Select( - _ => Task.Run(async () => - { - var (_, streamProcessor) = _; - await streamProcessor.Start(cancellationToken).ConfigureAwait(false); - }, cancellationToken)).ToList(); - -} diff --git a/Source/Events.Processing/EventHandlers/Fast/FilterStreamProcessors.cs b/Source/Events.Processing/EventHandlers/Fast/FilterStreamProcessors.cs deleted file mode 100644 index 7d9e5b9a4..000000000 --- a/Source/Events.Processing/EventHandlers/Fast/FilterStreamProcessors.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Concurrent; -using System.Threading; -using Dolittle.Runtime.DependencyInversion.Lifecycle; -using Dolittle.Runtime.Events.Processing.Streams; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Events.Store.Streams.Filters; -using Dolittle.Runtime.Rudimentary; -using Microsoft.Extensions.Logging; - -namespace Dolittle.Runtime.Events.Processing.EventHandlers; - -/// -/// Represents an implementation of . -/// -[Singleton] -public class FilterStreamProcessors : IFilterStreamProcessors -{ - readonly Func _createStreamProcessor; - readonly ILogger _logger; - readonly ConcurrentDictionary _streamProcessors = new(); - - /// - /// Initializes a new instance of the class. - /// - public FilterStreamProcessors( - Func createStreamProcessor, - ILogger logger) - { - _createStreamProcessor = createStreamProcessor; - _logger = logger; - } - - /// - public Try TryCreateAndRegister( - ScopeId scopeId, - TypeFilterWithEventSourcePartitionDefinition filterDefinition, - CancellationToken cancellationToken) - { - try - { - - var streamProcessorId = new StreamProcessorId(scopeId, filterDefinition.TargetStream.Value, StreamId.EventLog); - if (_streamProcessors.ContainsKey(streamProcessorId)) - { - _logger.FilterStreamProcessorAlreadyRegistered(streamProcessorId); - return new StreamProcessorAlreadyRegistered(streamProcessorId); - } - - var streamProcessor = _createStreamProcessor( - streamProcessorId, - filterDefinition, - () => Unregister(streamProcessorId), - cancellationToken); - - if (!_streamProcessors.TryAdd(streamProcessorId, streamProcessor)) - { - _logger.FilterStreamProcessorAlreadyRegistered(streamProcessorId); - return new StreamProcessorAlreadyRegistered(streamProcessorId); - } - - _logger.FilterStreamProcessorSuccessfullyRegistered(streamProcessorId); - return streamProcessor; - } - catch (Exception ex) - { - return ex; - } - } - - void Unregister(StreamProcessorId id) - { - FilterStreamProcessor existing; - do - { - _streamProcessors.TryRemove(id, out existing); - } - while (existing != default); - _logger.FilterStreamProcessorUnregistered(id); - } -} diff --git a/Source/Events.Processing/EventHandlers/Fast/ICreateScopedFilterStreamProcessors.cs b/Source/Events.Processing/EventHandlers/Fast/ICreateScopedFilterStreamProcessors.cs deleted file mode 100644 index b37bd540e..000000000 --- a/Source/Events.Processing/EventHandlers/Fast/ICreateScopedFilterStreamProcessors.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Events.Processing.Streams; -using Dolittle.Runtime.Events.Store.Streams.Filters; - -namespace Dolittle.Runtime.Events.Processing.EventHandlers; - -public interface ICreateScopedFilterStreamProcessors -{ - - Task Create( - TypeFilterWithEventSourcePartitionDefinition filterDefinition, - StreamProcessorId streamProcessorId, - CancellationToken cancellationToken); -} diff --git a/Source/Events.Processing/EventHandlers/Fast/IFilterStreamProcessors.cs b/Source/Events.Processing/EventHandlers/Fast/IFilterStreamProcessors.cs deleted file mode 100644 index 108b41979..000000000 --- a/Source/Events.Processing/EventHandlers/Fast/IFilterStreamProcessors.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams.Filters; -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Events.Processing.EventHandlers; - -public interface IFilterStreamProcessors -{ - - Try TryCreateAndRegister( - ScopeId scopeId, - TypeFilterWithEventSourcePartitionDefinition filterDefinition, - CancellationToken cancellationToken); -} diff --git a/Source/Events.Processing/EventHandlers/Fast/ScopedFilterStreamProcessor.cs b/Source/Events.Processing/EventHandlers/Fast/ScopedFilterStreamProcessor.cs deleted file mode 100644 index 64ee6212e..000000000 --- a/Source/Events.Processing/EventHandlers/Fast/ScopedFilterStreamProcessor.cs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Channels; -using System.Threading.Tasks; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Events.Processing.Streams; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Microsoft.Extensions.Logging; - -namespace Dolittle.Runtime.Events.Processing.EventHandlers; - -/// -/// Represents a fast scoped filter stream processor -/// -public class ScopedFilterStreamProcessor -{ - readonly ChannelReader _eventLogStream; - readonly StreamId _streamId; - readonly IWriteEventsToStreams _eventsWriter; - readonly IResilientStreamProcessorStateRepository _stateProcessorStates; - readonly TenantId _tenantId; - readonly bool _partitioned; - readonly ILogger _logger; - - StreamProcessorState _currentState; - bool _started; - - public ScopedFilterStreamProcessor( - ChannelReader eventLogStream, - StreamProcessorId streamProcessorId, - IWriteEventsToStreams eventsWriter, - IResilientStreamProcessorStateRepository stateProcessorStates, - TenantId tenantId, - bool partitioned, - StreamProcessorState currentState, - ILogger logger) - { - _eventLogStream = eventLogStream; - _streamId = streamProcessorId.EventProcessorId.Value; - _eventsWriter = eventsWriter; - _stateProcessorStates = stateProcessorStates; - _tenantId = tenantId; - _partitioned = partitioned; - _logger = logger; - _currentState = currentState; - Identifier = streamProcessorId; - } - - /// - /// Gets the identifier for the . - /// - public IStreamProcessorId Identifier { get; } - - /// - /// Starts the filter stream processing. - /// - /// The . - /// A representing the asynchronous operation. - public Task Start(CancellationToken cancellationToken) - { - if (_started) - { - throw new StreamProcessorAlreadyProcessingStream(Identifier); - } - _started = true; - return BeginProcessing(cancellationToken); - } - - - async Task BeginProcessing(CancellationToken cancellationToken) - { - try - { - await foreach (var batch in _eventLogStream.ReadAllAsync(cancellationToken)) - { - if (batch.MatchedEvents.Any()) - { - var eventsAndPartitions = ConvertToEventsAndPartitions(batch.MatchedEvents); - await _eventsWriter.Write(eventsAndPartitions, Identifier.ScopeId, _streamId, cancellationToken).ConfigureAwait(false); - } - - var newState = new StreamProcessorState(batch.To + 1, DateTimeOffset.UtcNow); - await _stateProcessorStates.Persist(Identifier, newState, CancellationToken.None).ConfigureAwait(false); - _currentState = newState; - } - } - catch (Exception ex) - { - if (!cancellationToken.IsCancellationRequested) - { - _logger.FilterStreamProcessingForTenantFailed(ex, Identifier, _tenantId); - } - } - } - - IEnumerable<(CommittedEvent, PartitionId)> ConvertToEventsAndPartitions(IEnumerable events) - => events - .Select(_ => _.ToCommittedEvent()) - .Select(@event => (@event, _partitioned ? new PartitionId(@event.EventSource) : PartitionId.None)); -} diff --git a/Source/Events.Processing/EventHandlers/Services.cs b/Source/Events.Processing/EventHandlers/Services.cs deleted file mode 100644 index 1cda1cb06..000000000 --- a/Source/Events.Processing/EventHandlers/Services.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.DependencyInversion; -using Dolittle.Runtime.Domain.Tenancy; -using Microsoft.Extensions.DependencyInjection; - -namespace Dolittle.Runtime.Events.Processing.EventHandlers; - -// TODO: Is bindings maybe a better word for these things? -public class Services : ICanAddServices -{ - public void AddTo(IServiceCollection services) - { - // TODO: Maybe we want to make an interface for these? - services.AddTransient(); - services.AddTransient(); - } -} diff --git a/Source/Events.Processing/Events.Processing.csproj b/Source/Events.Processing/Events.Processing.csproj deleted file mode 100644 index 654249443..000000000 --- a/Source/Events.Processing/Events.Processing.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - - Dolittle.Runtime.Events.Processing - Dolittle.Runtime.Events.Processing - - - - - - - - - - - - - - - - - - - - diff --git a/Source/Events.Processing/Filters/ValidateFilterByComparingStreams.cs b/Source/Events.Processing/Filters/ValidateFilterByComparingStreams.cs deleted file mode 100644 index 56d10b30a..000000000 --- a/Source/Events.Processing/Filters/ValidateFilterByComparingStreams.cs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.DependencyInversion.Lifecycle; -using Dolittle.Runtime.DependencyInversion.Scoping; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Events.Store.Streams.Filters; -using Dolittle.Runtime.Events.Store.Streams.Filters.EventHorizon; - - -namespace Dolittle.Runtime.Events.Processing.Filters; - -/// -/// Represents an implementation of for filters defined with or . -/// -[Singleton, PerTenant] -public class ValidateFilterByComparingStreams : ICanValidateFilterFor, ICanValidateFilterFor -{ - readonly IEventFetchers _eventFetchers; - - /// - /// Initializes a new instance of the class. - /// - /// The . - public ValidateFilterByComparingStreams(IEventFetchers eventFetchers) - { - _eventFetchers = eventFetchers; - } - - /// - public Task Validate(FilterDefinition persistedDefinition, IFilterProcessor filter, StreamPosition lastUnprocessedEvent, CancellationToken cancellationToken) - => PerformValidation(filter, lastUnprocessedEvent, cancellationToken); - - /// - public Task Validate(PublicFilterDefinition persistedDefinition, IFilterProcessor filter, StreamPosition lastUnprocessedEvent, CancellationToken cancellationToken) - => PerformValidation(filter, lastUnprocessedEvent, cancellationToken); - - async Task PerformValidation(IFilterProcessor filter, StreamPosition lastUnprocessedEvent, CancellationToken cancellationToken) - { - try - { - var streamDefinition = new StreamDefinition(filter.Definition); - var oldStreamEventsFetcher = await _eventFetchers.GetRangeFetcherFor( - filter.Scope, - streamDefinition, - cancellationToken).ConfigureAwait(false); - var eventLogFetcher = await _eventFetchers.GetRangeFetcherFor( - filter.Scope, - new EventLogStreamDefinition(), - cancellationToken).ConfigureAwait(false); - - var oldStream = oldStreamEventsFetcher.FetchRange( - new StreamPositionRange(StreamPosition.Start, ulong.MaxValue), - cancellationToken); - var eventLogStream = eventLogFetcher.FetchRange(new StreamPositionRange(StreamPosition.Start, lastUnprocessedEvent), cancellationToken); - await using var oldStreamEnumerator = oldStream.GetAsyncEnumerator(cancellationToken); - var newStreamPosition = 0; - await foreach (var eventFromEventLog in eventLogStream.WithCancellation(cancellationToken)) - { - var filteringResult = await filter.Filter(eventFromEventLog.Event, PartitionId.None, filter.Identifier, eventFromEventLog.Event.ExecutionContext, cancellationToken).ConfigureAwait(false); - if (filteringResult is FailedFiltering failedResult) - { - return FilterValidationResult.Failed(failedResult.FailureReason); - } - - if (!filteringResult.IsIncluded) - { - continue; - } - - if (!await oldStreamEnumerator.MoveNextAsync()) - { - return FilterValidationResult.Failed("The number of events included in the new stream generated from the filter does not match the old stream."); - } - var oldStreamEvent = oldStreamEnumerator.Current; - var filteredEvent = new StreamEvent( - eventFromEventLog.Event, - new StreamPosition((ulong) newStreamPosition++), - filter.Definition.TargetStream, - filteringResult.Partition, - streamDefinition.Partitioned); - if (EventsAreNotEqual(filter.Definition, filteredEvent, oldStreamEvent, out var failedValidation)) - { - return failedValidation; - } - } - - if (await oldStreamEnumerator.MoveNextAsync()) - { - return FilterValidationResult.Failed($"The number of events included in the new stream generated from the filter does not match the old stream."); - } - - return FilterValidationResult.Succeeded(); - } - catch (Exception exception) - { - return FilterValidationResult.Failed(exception.Message); - } - } - - static bool EventsAreNotEqual(IFilterDefinition filterDefinition, StreamEvent newEvent, StreamEvent oldEvent, out FilterValidationResult failedResult) - { - failedResult = default; - if (newEvent.Event.EventLogSequenceNumber != oldEvent.Event.EventLogSequenceNumber) - { - failedResult = FilterValidationResult.Failed($"Event in new stream at position {newEvent.Position} is event {newEvent.Event.EventLogSequenceNumber} while the event in the old stream is event {oldEvent.Event.EventLogSequenceNumber}"); - return true; - } - - if (filterDefinition.Partitioned && newEvent.Partition != oldEvent.Partition) - { - failedResult = FilterValidationResult.Failed($"Event in new stream at position {newEvent.Position} has is in partition {newEvent.Partition} while the event in the old stream is in partition {oldEvent.Partition}"); - return true; - } - return false; - } -} diff --git a/Source/Events.Processing/Streams/ICanGetTimeToRetryFor.cs b/Source/Events.Processing/Streams/ICanGetTimeToRetryFor.cs deleted file mode 100644 index 3537869ac..000000000 --- a/Source/Events.Processing/Streams/ICanGetTimeToRetryFor.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Events.Store.Streams; - -namespace Dolittle.Runtime.Events.Processing.Streams; - -/// -/// Defines a system that can get the time when a stream processor should retry processing for a specific . -/// -/// A of . -public interface ICanGetTimeToRetryFor - where T : class, IStreamProcessorState -{ - /// - /// Tries to get the for when to retry processing. Outputs the maximum value if there is no retry time. - /// - /// The . - /// The for when to retry processsing a stream processor. - /// A value indicating whether there is a retry time. - bool TryGetTimespanToRetry(T streamProcessorState, out TimeSpan timeToRetry); -} \ No newline at end of file diff --git a/Source/Events.Processing/Streams/IResilientStreamProcessorStateRepository.cs b/Source/Events.Processing/Streams/IResilientStreamProcessorStateRepository.cs deleted file mode 100644 index 992507ff7..000000000 --- a/Source/Events.Processing/Streams/IResilientStreamProcessorStateRepository.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Events.Store.Streams; - -namespace Dolittle.Runtime.Events.Processing.Streams; - -/// -/// Defines a resilient . -/// -public interface IResilientStreamProcessorStateRepository : IStreamProcessorStateRepository -{ -} diff --git a/Source/Events.Processing/Streams/IResilientStreamProcessorStateRepositoryPolicies.cs b/Source/Events.Processing/Streams/IResilientStreamProcessorStateRepositoryPolicies.cs deleted file mode 100644 index 44735cb75..000000000 --- a/Source/Events.Processing/Streams/IResilientStreamProcessorStateRepositoryPolicies.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Rudimentary; -using Polly; - -namespace Dolittle.Runtime.Events.Processing.Streams; - -/// -/// Defines the policies to use for the . -/// -public interface IResilientStreamProcessorStateRepositoryPolicies -{ - /// - /// The policy to use for persisting stream processor states. - /// - IAsyncPolicy Persisting { get; } - - /// - /// The policy to use for getting stream processor states. - /// - IAsyncPolicy> Getting { get; } -} diff --git a/Source/Events.Processing/Streams/Partitioned/FailingPartitionState.cs b/Source/Events.Processing/Streams/Partitioned/FailingPartitionState.cs deleted file mode 100644 index 515e2dd18..000000000 --- a/Source/Events.Processing/Streams/Partitioned/FailingPartitionState.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Events.Store.Streams; - -namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned; - -/// -/// Represents the state of a failing partition. -/// -/// The . -/// The to retry processing. -/// The reason for failing. -/// The number of times the Event has been processed. -/// The for when this partition last failed. -public record FailingPartitionState(StreamPosition Position, DateTimeOffset RetryTime, string Reason, uint ProcessingAttempts, DateTimeOffset LastFailed); \ No newline at end of file diff --git a/Source/Events.Processing/Streams/Partitioned/StreamProcessorState.cs b/Source/Events.Processing/Streams/Partitioned/StreamProcessorState.cs deleted file mode 100644 index b458a9388..000000000 --- a/Source/Events.Processing/Streams/Partitioned/StreamProcessorState.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using Dolittle.Runtime.Events.Store.Streams; - -namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned; - -/// -/// Represents the state of an . -/// -/// The position of the stream. -/// The states of the failing partitions. -/// The for the last time when an Event in the Stream that the processes was processed successfully. -public record StreamProcessorState(StreamPosition Position, IDictionary FailingPartitions, DateTimeOffset LastSuccessfullyProcessed) : IStreamProcessorState -{ - /// - /// Gets a new, initial, . - /// - public static StreamProcessorState New => new(StreamPosition.Start, new Dictionary(), DateTimeOffset.MinValue); - - /// - public bool Partitioned => true; -} \ No newline at end of file diff --git a/Source/Events.Processing/Streams/Partitioned/TimeToRetryForPartitionedStreamProcessor.cs b/Source/Events.Processing/Streams/Partitioned/TimeToRetryForPartitionedStreamProcessor.cs deleted file mode 100644 index cd19afc4c..000000000 --- a/Source/Events.Processing/Streams/Partitioned/TimeToRetryForPartitionedStreamProcessor.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Linq; - -namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned; - -/// -/// Represents an implementation of . -/// -public class TimeToRetryForPartitionedStreamProcessor : ICanGetTimeToRetryFor -{ - /// - public bool TryGetTimespanToRetry(StreamProcessorState streamProcessorState, out TimeSpan timeToRetry) - { - timeToRetry = TimeSpan.MaxValue; - var failingStates = streamProcessorState.FailingPartitions; - if (failingStates.Count > 0) - { - var earliestRetryTime = failingStates.Min(_ => _.Value.RetryTime); - timeToRetry = RetryTimeIsInThePast(earliestRetryTime) ? TimeSpan.Zero : earliestRetryTime.Subtract(DateTimeOffset.UtcNow); - return true; - } - - return false; - } - - bool RetryTimeIsInThePast(DateTimeOffset retryTime) - => DateTimeOffset.UtcNow.CompareTo(retryTime) >= 0; -} \ No newline at end of file diff --git a/Source/Events.Processing/Streams/ResilientStreamProcessorStateRepository.cs b/Source/Events.Processing/Streams/ResilientStreamProcessorStateRepository.cs deleted file mode 100644 index e516fb432..000000000 --- a/Source/Events.Processing/Streams/ResilientStreamProcessorStateRepository.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.DependencyInversion; -using Dolittle.Runtime.DependencyInversion.Lifecycle; -using Dolittle.Runtime.DependencyInversion.Scoping; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Events.Processing.Streams; - -/// -/// Represents an implementation of . -/// -[Singleton, PerTenant, DisableAutoRegistration] // TODO: We get circular dependencies since we register this as IStreamProcessorStateRepository by convention -public class ResilientStreamProcessorStateRepository : IResilientStreamProcessorStateRepository -{ - readonly IStreamProcessorStateRepository _repository; - readonly IResilientStreamProcessorStateRepositoryPolicies _policies; - - /// - /// Initializes a new instance of the class. - /// - /// The underlying stream processor state repository. - /// The policies to use for resilience. - public ResilientStreamProcessorStateRepository(IStreamProcessorStateRepository repository, IResilientStreamProcessorStateRepositoryPolicies policies) - { - _repository = repository; - _policies = policies; - } - - /// - public Task Persist(IStreamProcessorId streamProcessorId, IStreamProcessorState streamProcessorState, CancellationToken cancellationToken) - => _policies.Persisting.ExecuteAsync(_ => _repository.Persist(streamProcessorId, streamProcessorState, _), cancellationToken); - - /// - public Task> TryGetFor(IStreamProcessorId streamProcessorId, CancellationToken cancellationToken) - => _policies.Getting.ExecuteAsync(_ => _repository.TryGetFor(streamProcessorId, _), cancellationToken); -} diff --git a/Source/Events.Processing/Streams/ResilientStreamProcessorStateRepositoryPolicies.cs b/Source/Events.Processing/Streams/ResilientStreamProcessorStateRepositoryPolicies.cs deleted file mode 100644 index eadd8548a..000000000 --- a/Source/Events.Processing/Streams/ResilientStreamProcessorStateRepositoryPolicies.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.DependencyInversion.Lifecycle; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Rudimentary; -using Microsoft.Extensions.Logging; -using Polly; - -namespace Dolittle.Runtime.Events.Processing.Streams; - -/// -/// Represents an implementation of . -/// -[Singleton] -public class ResilientStreamProcessorStateRepositoryPolicies : IResilientStreamProcessorStateRepositoryPolicies -{ - /// - /// Initializes a new instance of the class. - /// - /// The logger to use while retrying. - public ResilientStreamProcessorStateRepositoryPolicies(ILogger logger) - { - Persisting = Policy - .Handle(exception => - { - Log.RetryPersistStreamProcessorState(logger, exception); - return true; - }) - .WaitAndRetryForeverAsync(_ => TimeSpan.FromSeconds(1)); - - Getting = Policy> - .Handle(exception => - { - // TODO: Different log message for this - Log.RetryPersistStreamProcessorState(logger, exception); - return true; - }) - .WaitAndRetryForeverAsync(_ => TimeSpan.FromSeconds(1)); - } - - public IAsyncPolicy Persisting { get; } - public IAsyncPolicy> Getting { get; } -} diff --git a/Source/Events.Processing/Streams/StreamProcessorId.cs b/Source/Events.Processing/Streams/StreamProcessorId.cs deleted file mode 100644 index 2f0c0c401..000000000 --- a/Source/Events.Processing/Streams/StreamProcessorId.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; - -namespace Dolittle.Runtime.Events.Processing.Streams; - -/// -/// Represents a unique key for a . -/// -/// The . -/// . -/// The . -public record StreamProcessorId(ScopeId ScopeId, EventProcessorId EventProcessorId, StreamId SourceStreamId) : IStreamProcessorId -{ - /// - public override string ToString() => $"Scope: {ScopeId.Value} Event Processor Id: {EventProcessorId.Value} Source Stream: {SourceStreamId.Value}"; -} \ No newline at end of file diff --git a/Source/Events.Processing/Streams/StreamProcessorState.cs b/Source/Events.Processing/Streams/StreamProcessorState.cs deleted file mode 100644 index 7c3473d3a..000000000 --- a/Source/Events.Processing/Streams/StreamProcessorState.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Events.Store.Streams; - -namespace Dolittle.Runtime.Events.Processing.Streams; - -/// -/// Represents the state of an . -/// -/// The position of the stream. -/// The reason for failing. -/// The for when to retry processing. -/// The number of times it has processed the Event at . -/// Timestamp of last successfull Stream process. -/// Whether the stream processor is failing. -public record StreamProcessorState(StreamPosition Position, string FailureReason, DateTimeOffset RetryTime, uint ProcessingAttempts, DateTimeOffset LastSuccessfullyProcessed, bool IsFailing) : IStreamProcessorState -{ - /// - /// Initializes a new instance of the class. - /// - /// The position of the stream. - /// Timestamp of last successfull Stream process. - public StreamProcessorState(StreamPosition streamPosition, DateTimeOffset lastSuccessfullyProcessed) : this(streamPosition, string.Empty, DateTimeOffset.UtcNow, 0, lastSuccessfullyProcessed, false) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The position of the stream. - StreamProcessorState(StreamPosition streamPosition) : this(streamPosition, string.Empty, DateTimeOffset.UtcNow, 0, DateTimeOffset.MinValue, false) - { - } - - /// - public bool Partitioned => false; - - public static StreamProcessorState New => new(StreamPosition.Start); -} \ No newline at end of file diff --git a/Source/Events.Processing/Streams/TimeToRetryForUnpartitionedStreamProcessor.cs b/Source/Events.Processing/Streams/TimeToRetryForUnpartitionedStreamProcessor.cs deleted file mode 100644 index ca300763b..000000000 --- a/Source/Events.Processing/Streams/TimeToRetryForUnpartitionedStreamProcessor.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; - -namespace Dolittle.Runtime.Events.Processing.Streams; - -/// -/// Represents an implementation of . -/// -public class TimeToRetryForUnpartitionedStreamProcessor : ICanGetTimeToRetryFor -{ - /// - public bool TryGetTimespanToRetry(StreamProcessorState streamProcessorState, out TimeSpan timeToRetry) - { - timeToRetry = TimeSpan.MaxValue; - if (streamProcessorState.IsFailing) - { - var retryTime = streamProcessorState.RetryTime; - timeToRetry = RetryTimeIsInThePast(retryTime) ? TimeSpan.Zero : retryTime.Subtract(DateTimeOffset.UtcNow); - return true; - } - - return false; - } - - bool RetryTimeIsInThePast(DateTimeOffset retryTime) - => DateTimeOffset.UtcNow.CompareTo(retryTime) >= 0; -} \ No newline at end of file diff --git a/Source/Events.Store.MongoDB/CommittedEventsFetcher.cs b/Source/Events.Store.MongoDB/CommittedEventsFetcher.cs index e099111dd..57576f6b8 100644 --- a/Source/Events.Store.MongoDB/CommittedEventsFetcher.cs +++ b/Source/Events.Store.MongoDB/CommittedEventsFetcher.cs @@ -12,8 +12,11 @@ using Dolittle.Runtime.Events.Store.MongoDB.Events; using Dolittle.Runtime.Events.Store.MongoDB.Legacy; using Dolittle.Runtime.Events.Store.MongoDB.Streams; +using Dolittle.Runtime.Events.Store.Streams; using Dolittle.Runtime.MongoDB; using Microsoft.Extensions.Logging; +using Dolittle.Runtime.Rudimentary; +using Microsoft.Extensions.Logging; using MongoDB.Driver; using IAggregateRoots = Dolittle.Runtime.Events.Store.MongoDB.Aggregates.IAggregateRoots; @@ -90,18 +93,17 @@ public async Task FetchCommittedEvents(ScopeId scope, EventLogS try { var eventLog = await GetEventLog(scope, cancellationToken).ConfigureAwait(false); - var events = await eventLog + var raw = await eventLog .Find(_eventFilter.Gte(e => e.EventLogSequenceNumber, from)) .Sort(Builders.Sort.Ascending(_ => _.EventLogSequenceNumber)) .Limit(limit) .ToListAsync(cancellationToken).ConfigureAwait(false); - return new CommittedEvents( - events.Select(_ => _eventConverter.ToRuntimeStreamEvent(_)) - .Select(_ => _.Event) - .ToList()); + var events = raw.Select(evt => _eventConverter.ToRuntimeCommittedEvent(evt)).ToList(); + + return new CommittedEvents(events); } - catch (Exception ex) + catch (MongoWaitQueueFullException ex) { throw new EventStoreUnavailable("Mongo wait queue is full", ex); } diff --git a/Source/Events.Store.MongoDB/Development/MongoDB/README.md b/Source/Events.Store.MongoDB/Development/MongoDB/README.md index af0b5ebfe..e712816c3 100644 --- a/Source/Events.Store.MongoDB/Development/MongoDB/README.md +++ b/Source/Events.Store.MongoDB/Development/MongoDB/README.md @@ -1,3 +1,4 @@ + # Single server MongoDB replica set This directory contains scripts necessary to build a MongoDB Docker image that starts as a single server replica set. diff --git a/Source/Events.Store.MongoDB/EventHorizon/EventHorizonEventsWriter.cs b/Source/Events.Store.MongoDB/EventHorizon/EventHorizonEventsWriter.cs index 3de94b350..ef8b70db6 100644 --- a/Source/Events.Store.MongoDB/EventHorizon/EventHorizonEventsWriter.cs +++ b/Source/Events.Store.MongoDB/EventHorizon/EventHorizonEventsWriter.cs @@ -8,8 +8,6 @@ using Dolittle.Runtime.Events.Store.MongoDB.Events; using Dolittle.Runtime.Events.Store.MongoDB.Streams; using Dolittle.Runtime.Events.Store.Streams; -using Microsoft.Extensions.Logging; -using MongoDB.Driver; namespace Dolittle.Runtime.Events.Store.MongoDB.EventHorizon; @@ -56,7 +54,7 @@ await _streams.GetEventLog(scope, cancellationToken).ConfigureAwait(false), DateTimeOffset.UtcNow, consentId)), cancellationToken).ConfigureAwait(false); - _streamWatcher.NotifyForEvent(scope, StreamId.EventLog, writtenStreamPosition); + _streamWatcher.NotifyForEvent(scope, StreamId.EventLog, writtenStreamPosition.Value); return writtenStreamPosition.Value; } } diff --git a/Source/Events.Store.MongoDB/EventHorizon/EventsToPublicStreamsWriter.cs b/Source/Events.Store.MongoDB/EventHorizon/EventsToPublicStreamsWriter.cs index 4cc76195c..619e7cd3c 100644 --- a/Source/Events.Store.MongoDB/EventHorizon/EventsToPublicStreamsWriter.cs +++ b/Source/Events.Store.MongoDB/EventHorizon/EventsToPublicStreamsWriter.cs @@ -10,8 +10,6 @@ using Dolittle.Runtime.Events.Store.MongoDB.Streams; using Dolittle.Runtime.Events.Store.Streams; using Dolittle.Runtime.Events.Store.Streams.Filters.EventHorizon; -using Microsoft.Extensions.Logging; -using MongoDB.Driver; namespace Dolittle.Runtime.Events.Store.MongoDB.EventHorizon; diff --git a/Source/Events.Store.MongoDB/Events.Store.MongoDB.csproj b/Source/Events.Store.MongoDB/Events.Store.MongoDB.csproj index f10189789..a35534947 100644 --- a/Source/Events.Store.MongoDB/Events.Store.MongoDB.csproj +++ b/Source/Events.Store.MongoDB/Events.Store.MongoDB.csproj @@ -15,9 +15,7 @@ - + - - diff --git a/Source/Events.Store.MongoDB/Events/EventConverter.cs b/Source/Events.Store.MongoDB/Events/EventConverter.cs index 8d72fed17..0aac0a579 100644 --- a/Source/Events.Store.MongoDB/Events/EventConverter.cs +++ b/Source/Events.Store.MongoDB/Events/EventConverter.cs @@ -53,6 +53,15 @@ public runtime.Streams.StreamEvent ToRuntimeStreamEvent(mongoDB.Event @event) => StreamId.EventLog, PartitionId.None, false); + + /// + public runtime.Streams.StreamEvent ToPartitionedRuntimeStreamEvent(mongoDB.Event @event) => + new( + ToRuntimeCommittedEvent(@event), + @event.EventLogSequenceNumber, + StreamId.EventLog, + @event.Metadata.EventSource, + true); /// public runtime.Streams.StreamEvent ToRuntimeStreamEvent(mongoDB.StreamEvent @event, StreamId stream, bool partitioned) => @@ -63,7 +72,7 @@ public runtime.Streams.StreamEvent ToRuntimeStreamEvent(mongoDB.StreamEvent @eve @event.Partition, partitioned); - runtime.CommittedEvent ToRuntimeCommittedEvent(mongoDB.Event @event) => + public runtime.CommittedEvent ToRuntimeCommittedEvent(mongoDB.Event @event) => @event.Aggregate.WasAppliedByAggregate ? ToRuntimeCommittedAggregateEvent(@event) : @event.EventHorizon.FromEventHorizon @@ -152,4 +161,4 @@ runtime.CommittedExternalEvent ToRuntimeCommittedExternalEvent(mongoDB.StreamEve @event.EventHorizon.ExternalEventLogSequenceNumber, @event.EventHorizon.Received, @event.EventHorizon.Consent); -} \ No newline at end of file +} diff --git a/Source/Events.Store.MongoDB/Events/ExecutionContext.cs b/Source/Events.Store.MongoDB/Events/ExecutionContext.cs index cb8d84a57..a09994eb5 100644 --- a/Source/Events.Store.MongoDB/Events/ExecutionContext.cs +++ b/Source/Events.Store.MongoDB/Events/ExecutionContext.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using Dolittle.Runtime.Domain.Tenancy; using Dolittle.Runtime.Execution; using MongoDB.Bson.Serialization.Attributes; diff --git a/Source/Events.Store.MongoDB/Events/ExecutionExtensions.cs b/Source/Events.Store.MongoDB/Events/ExecutionExtensions.cs index c9370a844..94b4f7e39 100644 --- a/Source/Events.Store.MongoDB/Events/ExecutionExtensions.cs +++ b/Source/Events.Store.MongoDB/Events/ExecutionExtensions.cs @@ -1,11 +1,9 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; using System.Diagnostics; using System.Globalization; using System.Linq; -using Dolittle.Runtime.Execution; namespace Dolittle.Runtime.Events.Store.MongoDB.Events; diff --git a/Source/Events.Store.MongoDB/Events/IEventConverter.cs b/Source/Events.Store.MongoDB/Events/IEventConverter.cs index 8833f1a85..5812a2911 100644 --- a/Source/Events.Store.MongoDB/Events/IEventConverter.cs +++ b/Source/Events.Store.MongoDB/Events/IEventConverter.cs @@ -43,4 +43,14 @@ public interface IEventConverter /// Whether or not the Event is partitioned. /// The converted . runtime.Streams.StreamEvent ToRuntimeStreamEvent(mongoDB.StreamEvent @event, StreamId stream, bool partitioned); + + /// + /// Converts a to . + /// + /// The to be converted. + /// The converted . + runtime.CommittedEvent ToRuntimeCommittedEvent(mongoDB.Event @event); + + /// + runtime.Streams.StreamEvent ToPartitionedRuntimeStreamEvent(mongoDB.Event @event); } diff --git a/Source/Events.Store.MongoDB/Legacy/StringOrGuidFilterDefinition.cs b/Source/Events.Store.MongoDB/Legacy/StringOrGuidFilterDefinition.cs index 19e56b3ea..bf07b925f 100644 --- a/Source/Events.Store.MongoDB/Legacy/StringOrGuidFilterDefinition.cs +++ b/Source/Events.Store.MongoDB/Legacy/StringOrGuidFilterDefinition.cs @@ -6,6 +6,7 @@ using MongoDB.Bson.IO; using MongoDB.Bson.Serialization; using MongoDB.Driver; +using MongoDB.Driver.Linq; namespace Dolittle.Runtime.Events.Store.MongoDB.Legacy; @@ -45,6 +46,8 @@ public override BsonDocument Render(IBsonSerializer documentSerialize return document; } + public override BsonDocument Render(IBsonSerializer documentSerializer, IBsonSerializerRegistry serializerRegistry, LinqProvider linqProvider) => Render(documentSerializer, serializerRegistry); + void RenderEqualityQuery(IBsonWriter writer) { if (Guid.TryParse(_value, out var guidValue)) diff --git a/Source/Events.Store.MongoDB/Persistence/CommitWriter.cs b/Source/Events.Store.MongoDB/Persistence/CommitWriter.cs index 41b1dca49..17de0a4ea 100644 --- a/Source/Events.Store.MongoDB/Persistence/CommitWriter.cs +++ b/Source/Events.Store.MongoDB/Persistence/CommitWriter.cs @@ -59,7 +59,7 @@ await _streams.DefaultEventLog.InsertManyAsync( await session.CommitTransactionAsync(cancellationToken).ConfigureAwait(false); //TODO: Notifying for events should be a concern handled by actors _streamWatcher.NotifyForEvent(ScopeId.Default, StreamId.EventLog, eventsToStore.Max(_ => _.EventLogSequenceNumber)); - return Try.Succeeded(); + return Try.Succeeded; } catch (MongoWaitQueueFullException ex) { diff --git a/Source/Events.Store.MongoDB/Persistence/IUpdateAggregateVersionsAfterCommit.cs b/Source/Events.Store.MongoDB/Persistence/IUpdateAggregateVersionsAfterCommit.cs index 558639a6f..f6dd5786b 100644 --- a/Source/Events.Store.MongoDB/Persistence/IUpdateAggregateVersionsAfterCommit.cs +++ b/Source/Events.Store.MongoDB/Persistence/IUpdateAggregateVersionsAfterCommit.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Threading.Tasks; using Dolittle.Runtime.Events.Store.Persistence; -using Dolittle.Runtime.Rudimentary; using MongoDB.Driver; namespace Dolittle.Runtime.Events.Store.MongoDB.Persistence; diff --git a/Source/Events.Store.MongoDB/Processing/Streams/AbstractStreamProcessorState.cs b/Source/Events.Store.MongoDB/Processing/Streams/AbstractStreamProcessorState.cs index ce262f3f8..236546f49 100644 --- a/Source/Events.Store.MongoDB/Processing/Streams/AbstractStreamProcessorState.cs +++ b/Source/Events.Store.MongoDB/Processing/Streams/AbstractStreamProcessorState.cs @@ -24,17 +24,20 @@ public abstract class AbstractStreamProcessorState /// /// The . /// The . - /// The position. + /// The position in the stream (how many processed events). + /// The position in the event log /// The timestamp of when the Stream was last processed successfully. protected AbstractStreamProcessorState( Guid eventProcessorId, Guid sourceStreamId, ulong position, + ulong eventLogPosition, DateTime lastSuccessfullyProcessed) { EventProcessor = eventProcessorId; SourceStream = sourceStreamId; Position = position; + EventLogPosition = eventLogPosition; LastSuccessfullyProcessed = lastSuccessfullyProcessed; } @@ -53,6 +56,12 @@ protected AbstractStreamProcessorState( /// [BsonRepresentation(BsonType.Decimal128)] public ulong Position { get; set; } + + /// + /// Gets or sets the position. + /// + [BsonRepresentation(BsonType.Decimal128)] + public ulong EventLogPosition { get; set; } /// /// Gets or sets the timestamp when the StreamProcessor has processed the stream. @@ -65,4 +74,4 @@ protected AbstractStreamProcessorState( /// /// The converted . public abstract IStreamProcessorState ToRuntimeRepresentation(); -} \ No newline at end of file +} diff --git a/Source/Events.Store.MongoDB/Processing/Streams/EventHorizon/ISubscriptionStates.cs b/Source/Events.Store.MongoDB/Processing/Streams/EventHorizon/ISubscriptionStateCollections.cs similarity index 92% rename from Source/Events.Store.MongoDB/Processing/Streams/EventHorizon/ISubscriptionStates.cs rename to Source/Events.Store.MongoDB/Processing/Streams/EventHorizon/ISubscriptionStateCollections.cs index 2fbf34e23..8df1f849f 100644 --- a/Source/Events.Store.MongoDB/Processing/Streams/EventHorizon/ISubscriptionStates.cs +++ b/Source/Events.Store.MongoDB/Processing/Streams/EventHorizon/ISubscriptionStateCollections.cs @@ -10,7 +10,7 @@ namespace Dolittle.Runtime.Events.Store.MongoDB.Processing.Streams.EventHorizon; /// /// Defines a system that knows about the Subscription State repositories. /// -public interface ISubscriptionStates : IEventStoreConnection +public interface ISubscriptionStateCollections : IEventStoreConnection { /// /// Gets a Subscription collection. @@ -19,4 +19,4 @@ public interface ISubscriptionStates : IEventStoreConnection /// The . /// A that, when resolved, returns a of . Task> Get(ScopeId scopeId, CancellationToken token); -} \ No newline at end of file +} diff --git a/Source/Events.Store.MongoDB/Processing/Streams/EventHorizon/SubscriptionStates.cs b/Source/Events.Store.MongoDB/Processing/Streams/EventHorizon/SubscriptionStateCollections.cs similarity index 91% rename from Source/Events.Store.MongoDB/Processing/Streams/EventHorizon/SubscriptionStates.cs rename to Source/Events.Store.MongoDB/Processing/Streams/EventHorizon/SubscriptionStateCollections.cs index 56b040232..e1a812ce1 100644 --- a/Source/Events.Store.MongoDB/Processing/Streams/EventHorizon/SubscriptionStates.cs +++ b/Source/Events.Store.MongoDB/Processing/Streams/EventHorizon/SubscriptionStateCollections.cs @@ -11,19 +11,19 @@ namespace Dolittle.Runtime.Events.Store.MongoDB.Processing.Streams.EventHorizon; /// -/// Represents an implementation of . +/// Represents an implementation of . /// [Singleton, PerTenant] -public class SubscriptionStates : EventStoreConnection, ISubscriptionStates +public class SubscriptionStateCollections : EventStoreConnection, ISubscriptionStateCollections { readonly ILogger _logger; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The . /// The . - public SubscriptionStates(IDatabaseConnection connection, ILogger logger) + public SubscriptionStateCollections(IDatabaseConnection connection, ILogger logger) : base(connection) { _logger = logger; diff --git a/Source/Events.Store.MongoDB/Processing/Streams/EventHorizon/SubscriptionStateExtensions.cs b/Source/Events.Store.MongoDB/Processing/Streams/EventHorizon/SubscriptionStateExtensions.cs index c331fb514..500fddc55 100644 --- a/Source/Events.Store.MongoDB/Processing/Streams/EventHorizon/SubscriptionStateExtensions.cs +++ b/Source/Events.Store.MongoDB/Processing/Streams/EventHorizon/SubscriptionStateExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using Dolittle.Runtime.Events.Store.Streams; using runtime = Dolittle.Runtime.Events.Processing.Streams; namespace Dolittle.Runtime.Events.Store.MongoDB.Processing.Streams.EventHorizon; @@ -18,10 +19,10 @@ public static class SubscriptionStateExtensions /// The converted . public static runtime.StreamProcessorState ToRuntimeRepresentation(this SubscriptionState state) => new( - state.Position, + new ProcessingPosition(state.Position, state.Position), state.FailureReason, state.RetryTime, state.ProcessingAttempts, state.LastSuccessfullyProcessed, state.IsFailing); -} \ No newline at end of file +} diff --git a/Source/Events.Store.MongoDB/Processing/Streams/IStreamProcessorStates.cs b/Source/Events.Store.MongoDB/Processing/Streams/IStreamProcessorStateCollections.cs similarity index 92% rename from Source/Events.Store.MongoDB/Processing/Streams/IStreamProcessorStates.cs rename to Source/Events.Store.MongoDB/Processing/Streams/IStreamProcessorStateCollections.cs index 640e61c60..45487e463 100644 --- a/Source/Events.Store.MongoDB/Processing/Streams/IStreamProcessorStates.cs +++ b/Source/Events.Store.MongoDB/Processing/Streams/IStreamProcessorStateCollections.cs @@ -11,7 +11,7 @@ namespace Dolittle.Runtime.Events.Store.MongoDB; /// /// Defines a system that knows about the Stream Processor State repositories. /// -public interface IStreamProcessorStates : IEventStoreConnection +public interface IStreamProcessorStateCollections : IEventStoreConnection { /// /// Gets a Stream Processor State collection. @@ -20,4 +20,4 @@ public interface IStreamProcessorStates : IEventStoreConnection /// The . /// A that, when resolved, returns a of . Task> Get(ScopeId scopeId, CancellationToken token); -} \ No newline at end of file +} diff --git a/Source/Events.Store.MongoDB/Processing/Streams/LoggerExtensions.cs b/Source/Events.Store.MongoDB/Processing/Streams/LoggerExtensions.cs index e496b3472..f5f4918dc 100644 --- a/Source/Events.Store.MongoDB/Processing/Streams/LoggerExtensions.cs +++ b/Source/Events.Store.MongoDB/Processing/Streams/LoggerExtensions.cs @@ -7,7 +7,7 @@ namespace Dolittle.Runtime.Events.Store.MongoDB.Processing.Streams; -static class LoggerExtensions +static partial class LoggerExtensions { static readonly Action _gettingStreamProcessorState = LoggerMessage .Define( @@ -26,4 +26,7 @@ internal static void GettingStreamProcessorState(this ILogger logger, IStreamPro internal static void PersistingStreamProcessorState(this ILogger logger, IStreamProcessorId streamProcessor) => _persistingStreamProcessorState(logger, streamProcessor, null); -} \ No newline at end of file + + [LoggerMessage(0, LogLevel.Information, "Retrieving all stream processor state")] + internal static partial void GettingAllStreamProcessorState(this ILogger logger); +} diff --git a/Source/Events.Store.MongoDB/Processing/Streams/NotAllStreamProcessorStatesInSameScope.cs b/Source/Events.Store.MongoDB/Processing/Streams/NotAllStreamProcessorStatesInSameScope.cs new file mode 100644 index 000000000..bcf7eab00 --- /dev/null +++ b/Source/Events.Store.MongoDB/Processing/Streams/NotAllStreamProcessorStatesInSameScope.cs @@ -0,0 +1,17 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Dolittle.Runtime.Events.Store.MongoDB.Processing.Streams; + +/// +/// Exception that gets thrown when not all stream processor states to be persisted are not in the same scope. +/// +public class NotAllStreamProcessorStatesInSameScope : Exception +{ + public NotAllStreamProcessorStatesInSameScope(ScopeId expectedScope) + : base($"Expected all stream processor states to be persisted to be in the same scope {expectedScope}") + { + } +} diff --git a/Source/Events.Store.MongoDB/Processing/Streams/Partitioned/FailingPartitionState.cs b/Source/Events.Store.MongoDB/Processing/Streams/Partitioned/FailingPartitionState.cs index 7d2263450..f5fbd823d 100644 --- a/Source/Events.Store.MongoDB/Processing/Streams/Partitioned/FailingPartitionState.cs +++ b/Source/Events.Store.MongoDB/Processing/Streams/Partitioned/FailingPartitionState.cs @@ -15,20 +15,28 @@ public class FailingPartitionState /// /// Initializes a new instance of the class. /// - /// The position. + /// The position in the stream. + /// The position in the event log /// The retry time. /// The reason for failure. /// The number of times the event at position has been processed. /// The timestamp of when this partition last failed. - public FailingPartitionState(ulong position, DateTime retryTime, string reason, uint processingAttempts, DateTime lastFailed) + public FailingPartitionState(ulong position, ulong eventLogPosition, DateTime retryTime, string reason, uint processingAttempts, DateTime lastFailed) { Position = position; + EventLogPosition = eventLogPosition; RetryTime = retryTime; Reason = reason; ProcessingAttempts = processingAttempts; LastFailed = lastFailed; } + /// + /// Gets or sets the EventLogPosition. + /// + [BsonRepresentation(BsonType.Decimal128)] + public ulong EventLogPosition { get; set; } + /// /// Gets or sets the position. /// @@ -56,4 +64,4 @@ public FailingPartitionState(ulong position, DateTime retryTime, string reason, /// [BsonDateTimeOptions(Kind = DateTimeKind.Utc)] public DateTime LastFailed { get; set; } -} \ No newline at end of file +} diff --git a/Source/Events.Store.MongoDB/Processing/Streams/Partitioned/PartitionedStreamProcessorState.cs b/Source/Events.Store.MongoDB/Processing/Streams/Partitioned/PartitionedStreamProcessorState.cs index 2b76f5e71..98b7fc9fb 100644 --- a/Source/Events.Store.MongoDB/Processing/Streams/Partitioned/PartitionedStreamProcessorState.cs +++ b/Source/Events.Store.MongoDB/Processing/Streams/Partitioned/PartitionedStreamProcessorState.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; -using System.Linq; +using System.Collections.Immutable; using Dolittle.Runtime.Events.Processing; using Dolittle.Runtime.Events.Store.Streams; using MongoDB.Bson.Serialization.Attributes; @@ -23,11 +23,13 @@ public class PartitionedStreamProcessorState : AbstractStreamProcessorState /// /// The . /// The . - /// The position. + /// The position in the stream (how many processed events). + /// The position in the event log /// The states of the failing partitions. /// The timestamp of when the Stream was last processed successfully. - public PartitionedStreamProcessorState(Guid eventProcessorId, Guid sourceStreamId, ulong position, IDictionary failingPartitions, DateTime lastSuccessfullyProcessed) - : base(eventProcessorId, sourceStreamId, position, lastSuccessfullyProcessed) + public PartitionedStreamProcessorState(Guid eventProcessorId, Guid sourceStreamId, ulong position, ulong eventLogPosition, + IDictionary failingPartitions, DateTime lastSuccessfullyProcessed) + : base(eventProcessorId, sourceStreamId, position, eventLogPosition, lastSuccessfullyProcessed) { FailingPartitions = failingPartitions; } @@ -41,7 +43,7 @@ public PartitionedStreamProcessorState(Guid eventProcessorId, Guid sourceStreamI /// public override IStreamProcessorState ToRuntimeRepresentation() => new runtime.Partitioned.StreamProcessorState( - Position, - FailingPartitions.ToDictionary(_ => new PartitionId(_.Key), _ => _.Value.ToRuntimeRepresentation()), + new ProcessingPosition(Position, EventLogPosition), + FailingPartitions.ToImmutableDictionary(_ => new PartitionId(_.Key), _ => _.Value.ToRuntimeRepresentation()), LastSuccessfullyProcessed); -} \ No newline at end of file +} diff --git a/Source/Events.Store.MongoDB/Processing/Streams/Partitioned/StreamProcessorStateExtensions.cs b/Source/Events.Store.MongoDB/Processing/Streams/Partitioned/StreamProcessorStateExtensions.cs index 0cfd8ab99..8de5265e8 100644 --- a/Source/Events.Store.MongoDB/Processing/Streams/Partitioned/StreamProcessorStateExtensions.cs +++ b/Source/Events.Store.MongoDB/Processing/Streams/Partitioned/StreamProcessorStateExtensions.cs @@ -16,5 +16,5 @@ public static class StreamProcessorStateExtensions /// The . /// The converted . public static runtime.FailingPartitionState ToRuntimeRepresentation(this FailingPartitionState state) => - new(state.Position, state.RetryTime, state.Reason, state.ProcessingAttempts, state.LastFailed); -} \ No newline at end of file + new(state.Position, state.EventLogPosition, state.RetryTime, state.Reason, state.ProcessingAttempts, state.LastFailed); +} diff --git a/Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorState.cs b/Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorState.cs index 3e2aeec28..12ab53c25 100644 --- a/Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorState.cs +++ b/Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorState.cs @@ -26,8 +26,8 @@ public class StreamProcessorState : AbstractStreamProcessorState /// The number of times the event at has been processed. /// The timestamp of when the Stream was last processed successfully. /// Whether the stream processor is failing. - public StreamProcessorState(Guid eventProcessorId, Guid sourceStreamId, ulong position, DateTime retryTime, string failureReason, uint processingAttempts, DateTime lastSuccessfullyProcessed, bool isFailing) - : base(eventProcessorId, sourceStreamId, position, lastSuccessfullyProcessed) + public StreamProcessorState(Guid eventProcessorId, Guid sourceStreamId, ulong position, ulong eventLogPosition, DateTime retryTime, string failureReason, uint processingAttempts, DateTime lastSuccessfullyProcessed, bool isFailing) + : base(eventProcessorId, sourceStreamId, position, eventLogPosition,lastSuccessfullyProcessed) { RetryTime = retryTime; FailureReason = failureReason; @@ -59,10 +59,10 @@ public StreamProcessorState(Guid eventProcessorId, Guid sourceStreamId, ulong po /// public override IStreamProcessorState ToRuntimeRepresentation() => new runtime.StreamProcessorState( - Position, + new ProcessingPosition(Position, EventLogPosition), FailureReason, RetryTime, ProcessingAttempts, LastSuccessfullyProcessed, IsFailing); -} \ No newline at end of file +} diff --git a/Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorStates.cs b/Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorStateCollections.cs similarity index 94% rename from Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorStates.cs rename to Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorStateCollections.cs index d051c05e5..55f9b3a14 100644 --- a/Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorStates.cs +++ b/Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorStateCollections.cs @@ -11,10 +11,10 @@ namespace Dolittle.Runtime.Events.Store.MongoDB.Processing.Streams; /// -/// Represents an implementation of . +/// Represents an implementation of . /// [Singleton, PerTenant] -public class StreamProcessorStates : EventStoreConnection, IStreamProcessorStates +public class StreamProcessorStateCollections : EventStoreConnection, IStreamProcessorStateCollections { const string StreamProcessorStateCollectionName = "stream-processor-states"; @@ -22,11 +22,11 @@ public class StreamProcessorStates : EventStoreConnection, IStreamProcessorState readonly IMongoCollection _streamProcessorStates; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The . /// The . - public StreamProcessorStates(IDatabaseConnection connection, ILogger logger) + public StreamProcessorStateCollections(IDatabaseConnection connection, ILogger logger) : base(connection) { _logger = logger; diff --git a/Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorStateRepository.cs b/Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorStateRepository.cs index 233fc831a..b3b498a65 100644 --- a/Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorStateRepository.cs +++ b/Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorStateRepository.cs @@ -1,194 +1,73 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.Collections.Generic; using System.Linq; using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Rudimentary; +using Dolittle.Runtime.DependencyInversion.Scoping; using Dolittle.Runtime.Events.Processing.Streams; -using Dolittle.Runtime.Events.Store.MongoDB.Processing.Streams.EventHorizon; +using Dolittle.Runtime.Events.Store.Streams; using Microsoft.Extensions.Logging; using MongoDB.Driver; -using Dolittle.Runtime.EventHorizon.Consumer; -using Dolittle.Runtime.Events.Store.MongoDB.Legacy; -using MongoSubscriptionState = Dolittle.Runtime.Events.Store.MongoDB.Processing.Streams.EventHorizon.SubscriptionState; -using Dolittle.Runtime.Events.Store.Streams; namespace Dolittle.Runtime.Events.Store.MongoDB.Processing.Streams; /// -/// Represents an implementation of . +/// Represents an implementation of . /// -public class StreamProcessorStateRepository : IStreamProcessorStateRepository +[PerTenant] +public class StreamProcessorStateRepository : StreamProcessorStateRepositoryBase, IStreamProcessorStateRepository { - readonly FilterDefinitionBuilder _streamProcessorFilter; - readonly FilterDefinitionBuilder _subscriptionFilter; - readonly IStreamProcessorStates _streamProcessorStates; - readonly ISubscriptionStates _subscriptionStates; - readonly ILogger _logger; + readonly FilterDefinitionBuilder _streamProcessorFilter = Builders.Filter; /// /// Initializes a new instance of the class. /// - /// The . - /// The . + /// The . /// An . - public StreamProcessorStateRepository( - IStreamProcessorStates streamProcessorStates, - ISubscriptionStates subscriptionStates, - ILogger logger) - { - _streamProcessorStates = streamProcessorStates; - _subscriptionStates = subscriptionStates; - _streamProcessorFilter = Builders.Filter; - _subscriptionFilter = Builders.Filter; - _logger = logger; - } - - /// - /// Gets the for the given from the correct - /// collection, either or . - /// - /// The unique representing either the - /// or . - /// The . - /// A that, when resolved, returns . - public async Task> TryGetFor(IStreamProcessorId id, CancellationToken cancellationToken) + public StreamProcessorStateRepository(IStreamProcessorStateCollections streamProcessorStateCollections, ILogger logger) + : base(streamProcessorStateCollections.Get, logger) { - _logger.GettingStreamProcessorState(id); - try - { - if (id is SubscriptionId subscriptionId) - { - var states = await _subscriptionStates.Get(subscriptionId.ScopeId, cancellationToken).ConfigureAwait(false); - var persistedState = await states.Find(CreateFilter(subscriptionId)) - .FirstOrDefaultAsync(cancellationToken) - .ConfigureAwait(false); - - return persistedState == default - ? new StreamProcessorStateDoesNotExist(subscriptionId) - : persistedState.ToRuntimeRepresentation(); - } - else if (id is StreamProcessorId streamProcessorId) - { - var states = await _streamProcessorStates.Get(streamProcessorId.ScopeId, cancellationToken).ConfigureAwait(false); - var persistedState = await states.Find(CreateFilter(streamProcessorId)) - .FirstOrDefaultAsync(cancellationToken) - .ConfigureAwait(false); - return persistedState == default - ? new StreamProcessorStateDoesNotExist(streamProcessorId) - : Try.Succeeded(persistedState.ToRuntimeRepresentation()); - } - else - { - throw new StreamProcessorIdOfUnsupportedType(id); - } - } - catch (MongoWaitQueueFullException ex) - { - throw new EventStoreUnavailable("Mongo wait queue is full", ex); - } } - /// - /// Persist the for and . - /// Handles separately also. - /// IsUpsert option creates the document if one isn't found. - /// - /// The . - /// The . - /// The . - /// A representing the asynchronous operation. - public async Task Persist(IStreamProcessorId id, IStreamProcessorState baseStreamProcessorState, CancellationToken cancellationToken) - { - _logger.PersistingStreamProcessorState(id); - try - { - if (id is SubscriptionId subscriptionId) - { - if (baseStreamProcessorState is Runtime.Events.Processing.Streams.StreamProcessorState streamProcessorState) - { - var replacementState = new MongoSubscriptionState( - subscriptionId.ProducerMicroserviceId, - subscriptionId.ProducerTenantId, - subscriptionId.StreamId, - subscriptionId.PartitionId, - streamProcessorState.Position, - streamProcessorState.RetryTime.UtcDateTime, - streamProcessorState.FailureReason, - streamProcessorState.ProcessingAttempts, - streamProcessorState.LastSuccessfullyProcessed.UtcDateTime, - streamProcessorState.IsFailing); - var states = await _subscriptionStates.Get(subscriptionId.ScopeId, cancellationToken).ConfigureAwait(false); - var persistedState = await states.ReplaceOneAsync( - CreateFilter(subscriptionId), - replacementState, - new ReplaceOptions { IsUpsert = true }) - .ConfigureAwait(false); - } - else - { - throw new UnsupportedStreamProcessorStatewithSubscriptionId(subscriptionId, baseStreamProcessorState); - } - } - else if (baseStreamProcessorState is Runtime.Events.Processing.Streams.Partitioned.StreamProcessorState partitionedStreamProcessorState) - { - var streamProcessorId = id as StreamProcessorId; - var states = await _streamProcessorStates.Get(streamProcessorId.ScopeId, cancellationToken).ConfigureAwait(false); - var state = await states.ReplaceOneAsync( - CreateFilter(streamProcessorId), - new Partitioned.PartitionedStreamProcessorState( - streamProcessorId.EventProcessorId, - streamProcessorId.SourceStreamId, - partitionedStreamProcessorState.Position, - partitionedStreamProcessorState.FailingPartitions.ToDictionary( - kvp => kvp.Key.Value.ToString(), - kvp => new FailingPartitionState( - kvp.Value.Position, - kvp.Value.RetryTime.UtcDateTime, - kvp.Value.Reason, - kvp.Value.ProcessingAttempts, - kvp.Value.LastFailed.UtcDateTime)), - partitionedStreamProcessorState.LastSuccessfullyProcessed.UtcDateTime), - new ReplaceOptions { IsUpsert = true }) - .ConfigureAwait(false); - } - else if (baseStreamProcessorState is Runtime.Events.Processing.Streams.StreamProcessorState streamProcessorState) - { - var streamProcessorId = id as StreamProcessorId; - var states = await _streamProcessorStates.Get(streamProcessorId.ScopeId, cancellationToken).ConfigureAwait(false); - var state = await states.ReplaceOneAsync( - CreateFilter(streamProcessorId), - new StreamProcessorState( - streamProcessorId.EventProcessorId, - streamProcessorId.SourceStreamId, - streamProcessorState.Position, - streamProcessorState.RetryTime.UtcDateTime, - streamProcessorState.FailureReason, - streamProcessorState.ProcessingAttempts, - streamProcessorState.LastSuccessfullyProcessed.UtcDateTime, - streamProcessorState.IsFailing), - new ReplaceOptions { IsUpsert = true }) - .ConfigureAwait(false); - } - else - { - throw new StreamProcessorStateOfUnsupportedType(id, baseStreamProcessorState); - } - } - catch (MongoWaitQueueFullException ex) - { - throw new EventStoreUnavailable("Mongo wait queue is full", ex); - } - } - - FilterDefinition CreateFilter(StreamProcessorId id) => + /// + public IAsyncEnumerable> GetNonScoped(CancellationToken cancellationToken) + => GetForScope(ScopeId.Default, cancellationToken); + + protected override FilterDefinition CreateFilter(StreamProcessorId id) => _streamProcessorFilter.Eq(_ => _.EventProcessor, id.EventProcessorId.Value) & _streamProcessorFilter.Eq(_ => _.SourceStream, id.SourceStreamId.Value); - FilterDefinition CreateFilter(SubscriptionId id) => - _subscriptionFilter.Eq(_ => _.Microservice, id.ProducerMicroserviceId.Value) - & _subscriptionFilter.Eq(_ => _.Tenant, id.ProducerTenantId.Value) - & _subscriptionFilter.Eq(_ => _.Stream, id.StreamId.Value) - & _subscriptionFilter.EqStringOrGuid(_ => _.Partition, id.PartitionId.Value); + protected override AbstractStreamProcessorState CreateDocument(StreamProcessorId id, IStreamProcessorState state) + => state switch + { + Runtime.Events.Processing.Streams.Partitioned.StreamProcessorState partitionedStreamProcessorState => new Partitioned.PartitionedStreamProcessorState( + id.EventProcessorId, + id.SourceStreamId, + partitionedStreamProcessorState.Position.StreamPosition, + partitionedStreamProcessorState.Position.EventLogPosition, + partitionedStreamProcessorState.FailingPartitions.ToDictionary( + kvp => kvp.Key.Value.ToString(), + kvp => new FailingPartitionState( + kvp.Value.Position.StreamPosition, + kvp.Value.Position.EventLogPosition, + kvp.Value.RetryTime.UtcDateTime, + kvp.Value.Reason, + kvp.Value.ProcessingAttempts, + kvp.Value.LastFailed.UtcDateTime)), + partitionedStreamProcessorState.LastSuccessfullyProcessed.UtcDateTime), + Runtime.Events.Processing.Streams.StreamProcessorState streamProcessorState => new StreamProcessorState( + id.EventProcessorId, + id.SourceStreamId, + streamProcessorState.Position.StreamPosition, + streamProcessorState.Position.EventLogPosition, + streamProcessorState.RetryTime.UtcDateTime, + streamProcessorState.FailureReason, + streamProcessorState.ProcessingAttempts, + streamProcessorState.LastSuccessfullyProcessed.UtcDateTime, + streamProcessorState.IsFailing) + }; + + protected override StreamProcessorStateWithId ConvertToStateWithId(ScopeId scope, AbstractStreamProcessorState document) + => new(new StreamProcessorId(scope, document.EventProcessor, document.SourceStream), document.ToRuntimeRepresentation()); } diff --git a/Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorStateRepositoryBase.cs b/Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorStateRepositoryBase.cs new file mode 100644 index 000000000..9e0db8ce1 --- /dev/null +++ b/Source/Events.Store.MongoDB/Processing/Streams/StreamProcessorStateRepositoryBase.cs @@ -0,0 +1,97 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.MongoDB; +using Dolittle.Runtime.Rudimentary; +using Microsoft.Extensions.Logging; +using MongoDB.Driver; + +namespace Dolittle.Runtime.Events.Store.MongoDB.Processing.Streams; + +public abstract class StreamProcessorStateRepositoryBase : IStreamProcessorStateRepository + where TId : IStreamProcessorId + where TState : IStreamProcessorState +{ + readonly Func>> _getCollection; + readonly ILogger _logger; + + public StreamProcessorStateRepositoryBase(Func>> getCollection, ILogger logger) + { + _getCollection = getCollection; + _logger = logger; + } + + public async Task> TryGet(TId streamProcessorId, CancellationToken cancellationToken) + { + _logger.GettingStreamProcessorState(streamProcessorId); + try + { + var collection = await _getCollection(streamProcessorId.ScopeId, cancellationToken).ConfigureAwait(false); + var persistedState = await collection.Find(CreateFilter(streamProcessorId)) + .FirstOrDefaultAsync(cancellationToken) + .ConfigureAwait(false); + return persistedState == null + ? new StreamProcessorStateDoesNotExist(streamProcessorId) + : Try.Succeeded(ConvertToStateWithId(streamProcessorId.ScopeId, persistedState).State); + + } + catch (MongoWaitQueueFullException ex) + { + return new EventStoreUnavailable("Mongo wait queue is full", ex); + } + } + + public async IAsyncEnumerable> GetForScope(ScopeId scopeId, [EnumeratorCancellation] CancellationToken cancellationToken) + { + var collection = await _getCollection(scopeId, cancellationToken).ConfigureAwait(false); + var states = collection + .Find(FilterDefinition.Empty) + .ToAsyncEnumerable(cancellationToken: cancellationToken) + .Select(_ => ConvertToStateWithId(scopeId, _)); + await foreach (var state in states.WithCancellation(cancellationToken)) + { + yield return state; + } + } + + public async Task PersistForScope(ScopeId scope, IReadOnlyDictionary streamProcessorStates, CancellationToken cancellationToken) + { + if (!streamProcessorStates.Keys.All(_ => _.ScopeId.Equals(scope))) + { + return new NotAllStreamProcessorStatesInSameScope(scope); + } + try + { + var collection = await _getCollection(scope, cancellationToken).ConfigureAwait(false); + var writeResult = await collection + .BulkWriteAsync( + streamProcessorStates.Select(_ => new ReplaceOneModel(CreateFilter(_.Key), CreateDocument(_.Key, _.Value)) + { + IsUpsert = true + }), + cancellationToken: cancellationToken).ConfigureAwait(false); + + // The write result may or may not have written all models. Maybe that should be checked? + return Try.Succeeded; + } + catch (MongoWaitQueueFullException ex) + { + return new EventStoreUnavailable("Mongo wait queue is full", ex); + } + catch (Exception ex) + { + return ex; + } + } + + protected abstract FilterDefinition CreateFilter(TId id); + protected abstract TDocument CreateDocument(TId id, TState state); + protected abstract StreamProcessorStateWithId ConvertToStateWithId(ScopeId scope, TDocument document); +} diff --git a/Source/Events.Store.MongoDB/Processing/Streams/SubscriptionStateRepository.cs b/Source/Events.Store.MongoDB/Processing/Streams/SubscriptionStateRepository.cs new file mode 100644 index 000000000..275b3cd0f --- /dev/null +++ b/Source/Events.Store.MongoDB/Processing/Streams/SubscriptionStateRepository.cs @@ -0,0 +1,61 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.DependencyInversion.Scoping; +using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Store.MongoDB.Processing.Streams.EventHorizon; +using Microsoft.Extensions.Logging; +using MongoDB.Driver; +using Dolittle.Runtime.EventHorizon.Consumer; +using Dolittle.Runtime.Events.Store.MongoDB.Legacy; +using MongoSubscriptionState = Dolittle.Runtime.Events.Store.MongoDB.Processing.Streams.EventHorizon.SubscriptionState; +using UnPartitionedStreamProcessorState = Dolittle.Runtime.Events.Processing.Streams.StreamProcessorState; + +namespace Dolittle.Runtime.Events.Store.MongoDB.Processing.Streams; + +/// +/// Represents an implementation of . +/// +[PerTenant] +public class SubscriptionStateRepository : StreamProcessorStateRepositoryBase, ISubscriptionStateRepository +{ + readonly TenantId _tenant; + readonly FilterDefinitionBuilder _subscriptionFilter = Builders.Filter; + + /// + /// Initializes a new instance of the class. + /// + /// The tenant id. + /// The . + /// An . + public SubscriptionStateRepository( + TenantId tenant, + ISubscriptionStateCollections subscriptionStateCollections, + ILogger logger) + : base(subscriptionStateCollections.Get, logger) + { + _tenant = tenant; + } + + protected override FilterDefinition CreateFilter(SubscriptionId id) => + _subscriptionFilter.Eq(_ => _.Microservice, id.ProducerMicroserviceId.Value) + & _subscriptionFilter.Eq(_ => _.Tenant, id.ProducerTenantId.Value) + & _subscriptionFilter.Eq(_ => _.Stream, id.StreamId.Value) + & _subscriptionFilter.EqStringOrGuid(_ => _.Partition, id.PartitionId.Value); + + protected override MongoSubscriptionState CreateDocument(SubscriptionId id, UnPartitionedStreamProcessorState state) + => new( + id.ProducerMicroserviceId, + id.ProducerTenantId, + id.StreamId, + id.PartitionId, + state.Position.EventLogPosition, + state.RetryTime.UtcDateTime, + state.FailureReason, + state.ProcessingAttempts, + state.LastSuccessfullyProcessed.UtcDateTime, + state.IsFailing); + + protected override StreamProcessorStateWithId ConvertToStateWithId(ScopeId scope, MongoSubscriptionState document) + => new (new SubscriptionId(_tenant, document.Microservice, document.Tenant, scope, document.Stream, document.Partition), document.ToRuntimeRepresentation()); +} diff --git a/Source/Events.Store.MongoDB/Streams/EventFetchers.cs b/Source/Events.Store.MongoDB/Streams/EventFetchers.cs index 11a5a7ea5..2fb57794f 100644 --- a/Source/Events.Store.MongoDB/Streams/EventFetchers.cs +++ b/Source/Events.Store.MongoDB/Streams/EventFetchers.cs @@ -34,7 +34,7 @@ public async Task GetFetcherFor(ScopeId scopeId, IStr var stream = streamDefinition.StreamId; if (stream == StreamId.EventLog) { - return await CreateStreamFetcherForEventLog(scopeId, cancellationToken).ConfigureAwait(false); + return await CreateStreamFetcherForEventLog(scopeId, cancellationToken, streamDefinition.Partitioned).ConfigureAwait(false); } if (streamDefinition.Public) @@ -54,16 +54,19 @@ await _streams.Get(scopeId, stream, cancellationToken).ConfigureAwait(false), } /// - public async Task GetPartitionedFetcherFor(ScopeId scopeId, IStreamDefinition streamDefinition, CancellationToken cancellationToken) + public async Task GetPartitionedFetcherFor(ScopeId scopeId, IStreamDefinition streamDefinition, + CancellationToken cancellationToken) { if (!streamDefinition.Partitioned) { throw new CannotGetPartitionedFetcherForUnpartitionedStream(streamDefinition); } + if (streamDefinition.StreamId == StreamId.EventLog) { throw new CannotGetPartitionedFetcherForEventLog(); } + if (streamDefinition.Public) { return CreateStreamFetcherForStreamEventCollection( @@ -81,7 +84,8 @@ await _streams.Get(scopeId, streamDefinition.StreamId, cancellationToken).Config } /// - public async Task GetRangeFetcherFor(ScopeId scopeId, IStreamDefinition streamDefinition, CancellationToken cancellationToken) + public async Task GetRangeFetcherFor(ScopeId scopeId, IStreamDefinition streamDefinition, + CancellationToken cancellationToken) { return await GetFetcherFor(scopeId, streamDefinition, cancellationToken).ConfigureAwait(false) as ICanFetchRangeOfEventsFromStream; } @@ -93,29 +97,51 @@ public async Task GetTypeFetcherFor(ScopeId scope } /// - public async Task GetPartitionedTypeFetcherFor(ScopeId scopeId, IStreamDefinition streamDefinition, CancellationToken cancellationToken) + public async Task GetPartitionedTypeFetcherFor(ScopeId scopeId, IStreamDefinition streamDefinition, + CancellationToken cancellationToken) { return await GetPartitionedFetcherFor(scopeId, streamDefinition, cancellationToken).ConfigureAwait(false) as ICanFetchEventTypesFromPartitionedStream; } - async Task> CreateStreamFetcherForEventLog(ScopeId scopeId, CancellationToken cancellationToken) => - new( + async Task> CreateStreamFetcherForEventLog(ScopeId scopeId, CancellationToken cancellationToken, bool partitioned) + { + if (partitioned) + { + return new StreamFetcher( + StreamId.EventLog, + scopeId, + await _streams.GetEventLog(scopeId, cancellationToken).ConfigureAwait(false), + Builders.Filter, + _ => _.EventLogSequenceNumber, + _ => _.EventLogSequenceNumber, + _ => _eventConverter.ToPartitionedRuntimeStreamEvent(_), + _ => _.Metadata.TypeId, + _ => _.Metadata.TypeGeneration, + _ => _.Metadata.EventSource); + + } + + return new StreamFetcher( StreamId.EventLog, scopeId, await _streams.GetEventLog(scopeId, cancellationToken).ConfigureAwait(false), Builders.Filter, _ => _.EventLogSequenceNumber, + _ => _.EventLogSequenceNumber, _ => _eventConverter.ToRuntimeStreamEvent(_), _ => _.Metadata.TypeId, _ => _.Metadata.TypeGeneration); + } - StreamFetcher CreateStreamFetcherForStreamEventCollection(IMongoCollection collection, StreamId streamId, ScopeId scopeId, bool partitioned) => + StreamFetcher CreateStreamFetcherForStreamEventCollection(IMongoCollection collection, StreamId streamId, + ScopeId scopeId, bool partitioned) => new( streamId, scopeId, collection, Builders.Filter, _ => _.StreamPosition, + _ => _.StreamPosition, _ => _eventConverter.ToRuntimeStreamEvent(_, streamId, partitioned), _ => _.Metadata.TypeId, _ => _.Metadata.TypeGeneration, diff --git a/Source/Events.Store.MongoDB/Streams/EventsToStreamsWriter.cs b/Source/Events.Store.MongoDB/Streams/EventsToStreamsWriter.cs index 1ad2039c6..a26879bc5 100644 --- a/Source/Events.Store.MongoDB/Streams/EventsToStreamsWriter.cs +++ b/Source/Events.Store.MongoDB/Streams/EventsToStreamsWriter.cs @@ -23,7 +23,6 @@ public class EventsToStreamsWriter : IWriteEventsToStreamCollection, IWriteEvent { readonly IStreams _streams; readonly IEventConverter _eventConverter; - readonly IStreamEventWatcher _streamWatcher; readonly ILogger _logger; /// @@ -31,13 +30,11 @@ public class EventsToStreamsWriter : IWriteEventsToStreamCollection, IWriteEvent /// /// The . /// The . - /// The . /// An . - public EventsToStreamsWriter(IStreams streams, IEventConverter eventConverter, IStreamEventWatcher streamWatcher, ILogger logger) + public EventsToStreamsWriter(IStreams streams, IEventConverter eventConverter, ILogger logger) { _streams = streams; _eventConverter = eventConverter; - _streamWatcher = streamWatcher; _logger = logger; } @@ -60,7 +57,7 @@ eventAndPartition.Item1 is CommittedExternalEvent externalEvent .ToList(); }, cancellationToken).ConfigureAwait(false); - _streamWatcher.NotifyForEvent(scope, stream, lastWrittenStreamPosition); + // _streamWatcher.NotifyForEvent(scope, stream, lastWrittenStreamPosition); } /// @@ -140,6 +137,8 @@ async Task WriteOnlyNewEvents(IMongoCollection s } } + + static Task> GetStoredEventStreamHeadOfStreamToWrite(IMongoCollection stream, IReadOnlyList eventsToWrite, IClientSessionHandle transaction, CancellationToken cancellationToken) => stream .Find( diff --git a/Source/Events.Store.MongoDB/Streams/Filters/FilterDefinitionDiscriminatorConvention.cs b/Source/Events.Store.MongoDB/Streams/Filters/FilterDefinitionDiscriminatorConvention.cs index 0f599be82..da0401424 100644 --- a/Source/Events.Store.MongoDB/Streams/Filters/FilterDefinitionDiscriminatorConvention.cs +++ b/Source/Events.Store.MongoDB/Streams/Filters/FilterDefinitionDiscriminatorConvention.cs @@ -18,7 +18,7 @@ public class FilterDefinitionDiscriminatorConvention : IDiscriminatorConvention const string Type = "Type"; /// - /// Represents the differnet kinds of FilterDefinitions we have. + /// Represents the different kinds of FilterDefinitions we have. /// public enum FilterType { diff --git a/Source/Events.Store.MongoDB/Streams/IWriteEventsToStreamCollection.cs b/Source/Events.Store.MongoDB/Streams/IWriteEventsToStreamCollection.cs index a9e1354e1..a4112cae9 100644 --- a/Source/Events.Store.MongoDB/Streams/IWriteEventsToStreamCollection.cs +++ b/Source/Events.Store.MongoDB/Streams/IWriteEventsToStreamCollection.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Dolittle.Runtime.Events.Store.MongoDB.Events; using Dolittle.Runtime.Events.Store.Streams; using MongoDB.Driver; diff --git a/Source/Events.Store.MongoDB/Streams/StreamFetcher.cs b/Source/Events.Store.MongoDB/Streams/StreamFetcher.cs index 16e6e4fd1..7fa90e519 100644 --- a/Source/Events.Store.MongoDB/Streams/StreamFetcher.cs +++ b/Source/Events.Store.MongoDB/Streams/StreamFetcher.cs @@ -20,7 +20,8 @@ namespace Dolittle.Runtime.Events.Store.MongoDB.Streams; /// Represents a fetcher. ///
/// The type of the stored event. -public class StreamFetcher : ICanFetchEventsFromStream, ICanFetchEventsFromPartitionedStream, ICanFetchRangeOfEventsFromStream, ICanFetchEventTypesFromStream, ICanFetchEventTypesFromPartitionedStream +public class StreamFetcher : ICanFetchEventsFromStream, ICanFetchEventsFromPartitionedStream, ICanFetchRangeOfEventsFromStream, + ICanFetchEventTypesFromStream, ICanFetchEventTypesFromPartitionedStream where TEvent : class { const int FetchEventsBatchSize = 100; @@ -30,7 +31,8 @@ public class StreamFetcher : ICanFetchEventsFromStream, ICanFetchEventsF readonly IMongoCollection _collection; readonly FilterDefinitionBuilder _filter; readonly Expression> _sequenceNumberExpression; - readonly Expression> _eventToStreamEvent; + readonly Expression> _sequenceNumberSortByExpression; + readonly Func _eventToStreamEvent; readonly Expression> _eventToArtifactId; readonly Expression> _eventToArtifactGeneration; readonly Expression> _partitionIdExpression = default; @@ -52,6 +54,7 @@ public StreamFetcher( IMongoCollection collection, FilterDefinitionBuilder filter, Expression> sequenceNumberExpression, + Expression> sequenceNumberSortByExpression, Expression> eventToStreamEvent, Expression> eventToArtifactId, Expression> eventToArtifactGeneration) @@ -61,7 +64,9 @@ public StreamFetcher( _collection = collection; _filter = filter; _sequenceNumberExpression = sequenceNumberExpression; - _eventToStreamEvent = eventToStreamEvent; + _sequenceNumberSortByExpression = sequenceNumberSortByExpression; + _eventToStreamEvent = eventToStreamEvent.Compile(); + _eventToArtifactId = eventToArtifactId; _eventToArtifactGeneration = eventToArtifactGeneration; } @@ -74,6 +79,7 @@ public StreamFetcher( /// The . /// The . /// The for getting the sequence number from the stored event. + /// /// The for projecting the stored event to a . /// The for projecting the stored event to . /// The for getting the for the Partition Id from the stored event. @@ -83,27 +89,29 @@ public StreamFetcher( IMongoCollection collection, FilterDefinitionBuilder filter, Expression> sequenceNumberExpression, + Expression> sequenceNumberSortByExpression, Expression> eventToStreamEvent, Expression> eventToArtifactId, Expression> eventToArtifactGeneration, Expression> partitionIdExpression) - : this(stream, scope, collection, filter, sequenceNumberExpression, eventToStreamEvent, eventToArtifactId, eventToArtifactGeneration) + : this(stream, scope, collection, filter, sequenceNumberExpression, sequenceNumberSortByExpression, eventToStreamEvent, eventToArtifactId, + eventToArtifactGeneration) { _partitionIdExpression = partitionIdExpression; } /// - public async Task>> Fetch(StreamPosition streamPosition, CancellationToken cancellationToken) + public async Task>> Fetch(StreamPosition position, CancellationToken cancellationToken) { try { - var events = await _collection.Find( - _filter.Gte(_sequenceNumberExpression, streamPosition.Value)) + var results = await _collection.Find(_filter.Gte(_sequenceNumberExpression, position.Value)) .Limit(FetchEventsBatchSize) - .Project(_eventToStreamEvent) .ToListAsync(cancellationToken).ConfigureAwait(false); + var events = results.Select(_eventToStreamEvent).ToList(); + return events == default || events.Count == 0 - ? new NoEventInStreamAtPosition(_stream, _scope, streamPosition) + ? new NoEventInStreamAtPosition(_stream, _scope, position) : events; } catch (MongoWaitQueueFullException ex) @@ -112,14 +120,54 @@ public async Task>> Fetch(StreamPosition streamPosi } } + /// + public async Task> FetchSingle(StreamPosition position, CancellationToken cancellationToken) + { + try + { + var events = await _collection.Find(_filter.Eq(_sequenceNumberExpression, position.Value)) + .SingleOrDefaultAsync(cancellationToken); + + return events is null + ? new NoEventInStreamAtPosition(_stream, _scope, position) + : _eventToStreamEvent(events); + } + catch (MongoWaitQueueFullException ex) + { + throw new EventStoreUnavailable("Mongo wait queue is full", ex); + } + } + + public async Task> FetchLast(CancellationToken cancellationToken) + { + try + { + var events = await _collection.Find(_filter.Empty) + .SortByDescending(_sequenceNumberSortByExpression) + .FirstOrDefaultAsync(cancellationToken); + + return events is null + ? new NoEventInStreamAtPosition(_stream, _scope, StreamPosition.Start) + : _eventToStreamEvent(events); + } + catch (MongoWaitQueueFullException ex) + { + throw new EventStoreUnavailable("Mongo wait queue is full", ex); + } + } + /// public async Task> GetNextStreamPosition(CancellationToken cancellationToken) { try { - // TODO: Do not do this, get last document instead. - var numEvents = await _collection.CountDocumentsAsync(_filter.Empty, cancellationToken: cancellationToken).ConfigureAwait(false); - return Try.Succeeded((ulong)numEvents); + var last = await FetchLast(cancellationToken); + if (!last.Success) + { + return Try.Succeeded(StreamPosition.Start); + } + + return last.Result.Position.Increment(); } catch (MongoWaitQueueFullException ex) { @@ -128,19 +176,20 @@ public async Task> GetNextStreamPosition(CancellationToken c } /// - public async Task>> FetchInPartition(PartitionId partitionId, StreamPosition streamPosition, CancellationToken cancellationToken) + public async Task>> FetchInPartition(PartitionId partitionId, StreamPosition position, CancellationToken cancellationToken) { ThrowIfNotConstructedWithPartitionIdExpression(); try { - var events = await _collection.Find( + var results = await _collection.Find( _filter.EqStringOrGuid(_partitionIdExpression, partitionId.Value) - & _filter.Gte(_sequenceNumberExpression, streamPosition.Value)) + & _filter.Gte(_sequenceNumberExpression, position.Value)) .Limit(FetchEventsBatchSize) - .Project(_eventToStreamEvent) .ToListAsync(cancellationToken).ConfigureAwait(false); + var events = results.Select(_eventToStreamEvent).ToList(); + return events == default || events.Count == 0 - ? new NoEventInPartitionInStreamFromPosition(_stream, _scope, partitionId, streamPosition) + ? new NoEventInPartitionInStreamFromPosition(_stream, _scope, partitionId, position) : events; } catch (MongoWaitQueueFullException ex) @@ -149,6 +198,70 @@ public async Task>> FetchInPartition(PartitionId pa } } + public async Task<(IList events, bool hasMoreEvents)> FetchInPartition(PartitionId partitionId, StreamPosition from, StreamPosition to, + ISet artifactIds, + CancellationToken cancellationToken) + { + ThrowIfNotConstructedWithPartitionIdExpression(); + try + { + var composedFilter = _filter.EqStringOrGuid(_partitionIdExpression, partitionId.Value) + & _filter.Gte(_sequenceNumberExpression, from.Value) + & _filter.Lt(_sequenceNumberExpression, to.Value); + + if (artifactIds.Any()) + { + composedFilter &= _filter.In(_eventToArtifactId, artifactIds); + } + + var results = await _collection.Find(composedFilter) + .Limit(FetchEventsBatchSize) + .ToListAsync(cancellationToken).ConfigureAwait(false); + var events = results.Select(_eventToStreamEvent).ToList(); + + return (events, events.Count < FetchEventsBatchSize); + } + catch (MongoWaitQueueFullException ex) + { + throw new EventStoreUnavailable("Mongo wait queue is full", ex); + } + } + + public async Task<(StreamEvent? events, bool hasMoreEvents)> FetchNextEventInPartition(PartitionId partitionId, StreamPosition from, StreamPosition to, + ISet artifactIds, + CancellationToken cancellationToken) + { + ThrowIfNotConstructedWithPartitionIdExpression(); + try + { + var composedFilter = _filter.EqStringOrGuid(_partitionIdExpression, partitionId.Value) + & _filter.Gte(_sequenceNumberExpression, from.Value) + & _filter.Lt(_sequenceNumberExpression, to.Value); + if (artifactIds.Any()) + { + composedFilter &= _filter.In(_eventToArtifactId, artifactIds); + } + + var results = await _collection.Find(composedFilter) + .Limit(2) + .ToListAsync(cancellationToken).ConfigureAwait(false); + + if (results.Count == 0) + return (null, false); + + return results.Count switch + { + 0 => (null, false), + 1 => (_eventToStreamEvent(results[0]), false), + _ => (_eventToStreamEvent(results[0]), true) + }; + } + catch (MongoWaitQueueFullException ex) + { + throw new EventStoreUnavailable("Mongo wait queue is full", ex); + } + } + /// public IAsyncEnumerable FetchRange( StreamPositionRange range, @@ -156,11 +269,11 @@ public IAsyncEnumerable FetchRange( { try { - return _collection.Find( + var results = _collection.Find( _filter.Gte(_sequenceNumberExpression, range.From.Value) & _filter.Lt(_sequenceNumberExpression, range.From.Value + range.Length)) - .Project(_eventToStreamEvent) .ToAsyncEnumerable(cancellationToken); + return results.Select(_eventToStreamEvent); } catch (MongoWaitQueueFullException ex) { @@ -213,12 +326,12 @@ static ISet ExpandToArtifacts(IEnumerable art set.Add(new Artifact(artifactWithGenerations.Id, generation)); } } + return set; } class ArtifactWithGenerations { - public ArtifactWithGenerations(Guid id, IEnumerable generations) { Id = id; diff --git a/Source/Events.Store.MongoDB/Streams/StreamFetcherWasNotConstructedWithPartitionIdExpression.cs b/Source/Events.Store.MongoDB/Streams/StreamFetcherWasNotConstructedWithPartitionIdExpression.cs index 1d197593b..4589ab9ed 100644 --- a/Source/Events.Store.MongoDB/Streams/StreamFetcherWasNotConstructedWithPartitionIdExpression.cs +++ b/Source/Events.Store.MongoDB/Streams/StreamFetcherWasNotConstructedWithPartitionIdExpression.cs @@ -11,7 +11,7 @@ namespace Dolittle.Runtime.Events.Store.MongoDB.Streams; public class StreamFetcherWasNotConstructedWithPartitionIdExpression : Exception { public StreamFetcherWasNotConstructedWithPartitionIdExpression() - : base($"The StreamFetcher was constructed without a ParitionId expression. It cannot be used for fetching events or types in a specific partition") + : base($"The StreamFetcher was constructed without a PartitionId expression. It cannot be used for fetching events or types in a specific partition") { } } \ No newline at end of file diff --git a/Source/Events.Store.Services.Grpc/EventStoreGrpcService.cs b/Source/Events.Store.Services.Grpc/EventStoreGrpcService.cs index 41dd2c178..4bd8b6a07 100644 --- a/Source/Events.Store.Services.Grpc/EventStoreGrpcService.cs +++ b/Source/Events.Store.Services.Grpc/EventStoreGrpcService.cs @@ -1,15 +1,11 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Dolittle.Runtime.Artifacts; using Dolittle.Runtime.Events.Contracts; -using Dolittle.Runtime.Protobuf; using Dolittle.Runtime.Rudimentary.AsyncEnumerators; -using Dolittle.Runtime.Services; using Dolittle.Runtime.Services.Hosting; using Grpc.Core; using static Dolittle.Runtime.Events.Contracts.EventStore; diff --git a/Source/Events.Store.Services.Grpc/Events.Store.Services.Grpc.csproj b/Source/Events.Store.Services.Grpc/Events.Store.Services.Grpc.csproj index 3b1565425..4ee766526 100644 --- a/Source/Events.Store.Services.Grpc/Events.Store.Services.Grpc.csproj +++ b/Source/Events.Store.Services.Grpc/Events.Store.Services.Grpc.csproj @@ -12,9 +12,10 @@ + - + diff --git a/Source/Events.Store.Services.WebAPI/Events.Store.Services.WebAPI.csproj b/Source/Events.Store.Services.WebAPI/Events.Store.Services.WebAPI.csproj index 9e99d4956..5c99946a7 100644 --- a/Source/Events.Store.Services.WebAPI/Events.Store.Services.WebAPI.csproj +++ b/Source/Events.Store.Services.WebAPI/Events.Store.Services.WebAPI.csproj @@ -12,8 +12,8 @@ + - diff --git a/Source/Events.Store/Actors/EventStore.proto b/Source/Events.Store/Actors/EventStore.proto deleted file mode 100644 index 8205294bf..000000000 --- a/Source/Events.Store/Actors/EventStore.proto +++ /dev/null @@ -1,80 +0,0 @@ -syntax = "proto3"; - -package dolittle.runtime.events.actors; - -option csharp_namespace = "Dolittle.Runtime.Events.Store.Actors"; - -import "Runtime/Events/EventStore.proto"; -import "Runtime/Events/Committed.proto"; - -import "Protobuf/Failure.proto"; -import "Protobuf/Uuid.proto"; -import "Artifacts/Artifact.proto"; - - -message EventStoreSubscriptionRequest{ - protobuf.Uuid subscription_id = 1; - protobuf.Uuid scope_id = 2; - repeated protobuf.Uuid event_type_ids = 3; - string pid_id = 4; - string pid_address = 5; - uint64 from_offset = 6; -} - -message StartEventStoreSubscription{ - protobuf.Uuid subscription_id = 1; - protobuf.Uuid scope_id = 2; - repeated protobuf.Uuid event_type_ids = 3; - string pid_id = 4; - string pid_address = 5; - uint64 from_offset = 6; - uint64 current_high_watermark = 7; -} - -message EventStoreSubscriptionAck{ - protobuf.Uuid subscription_id = 1; - protobuf.Uuid scope_id = 2; - bool ok = 3; -} - -message CancelEventStoreSubscription{ - protobuf.Uuid subscription_id = 1; - protobuf.Uuid scope_id = 2; -} - -message CancelEventStoreSubscriptionAck{ - protobuf.Uuid subscription_id = 1; -} - -message CommittedEventsRequest{ - uint64 from_offset = 1; - uint64 to_offset = 2; - repeated CommittedEvent events = 3; -} - -message SubscriptionEvents{ - protobuf.Uuid subscription_id = 1; - uint64 from_offset = 2; - uint64 to_offset = 3; - repeated CommittedEvent events = 4; -} - -message SubscriptionEventsAck{ - uint64 continue_from_offset = 1; -} - -message CommitExternalEventsRequest{ - CommittedEvent event = 1; - protobuf.Uuid scope_id = 2; -} -message CommitExternalEventsResponse{ - protobuf.Failure failure = 1; -} - -service EventStore { - rpc Commit (CommitEventsRequest) returns (CommitEventsResponse); - rpc CommitForAggregate (CommitAggregateEventsRequest) returns (CommitAggregateEventsResponse); - rpc CommitExternal (CommitExternalEventsRequest) returns (CommitExternalEventsResponse); - rpc RegisterSubscription(EventStoreSubscriptionRequest) returns (EventStoreSubscriptionAck); - rpc CancelSubscription(CancelEventStoreSubscription) returns (CancelEventStoreSubscriptionAck); -} diff --git a/Source/Events.Store/Actors/Log.cs b/Source/Events.Store/Actors/Log.cs deleted file mode 100644 index 6e30de77e..000000000 --- a/Source/Events.Store/Actors/Log.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Dolittle.Runtime.Aggregates; -using Dolittle.Runtime.Artifacts; -using Microsoft.Extensions.Logging; - -namespace Dolittle.Runtime.Events.Store.Actors; - -static partial class Log -{ - [LoggerMessage(0, LogLevel.Warning, "Aggregate root '{AggregateRootId}' with event source '{EventSourceId}' has version inconsistency in cache. Expected {ExpectedAggregateRootVersion} but current is {CurrentAggregateRootVersion}")] - internal static partial void AggregateRootVersionCacheInconsistency(this ILogger logger, ArtifactId aggregateRootId, EventSourceId eventSourceId, AggregateRootVersion expectedAggregateRootVersion, AggregateRootVersion currentAggregateRootVersion); - - [LoggerMessage(0, LogLevel.Warning, "Aggregate root '{AggregateRootId}' with event source '{EventSourceId}' version inconsistency resolved it self. Aggregate root version is at the expected version {ExpectedAggregateRootVersion}")] - internal static partial void AggregateRootVersionCacheInconsistencyResolved(this ILogger logger, ArtifactId aggregateRootId, EventSourceId eventSourceId, AggregateRootVersion expectedAggregateRootVersion); - - [LoggerMessage(0, LogLevel.Warning, "Aggregate root '{AggregateRootId}' with event source '{EventSourceId}' version has a concurrency conflict, expected version {ExpectedAggregateRootVersion} but cached version {CachedVersion} was not consistent with stored version {StoredVersion}. Updating cache")] - internal static partial void AggregateRootConcurrencyConflictWithInconsistentCache(this ILogger logger, ArtifactId aggregateRootId, EventSourceId eventSourceId, AggregateRootVersion expectedAggregateRootVersion, AggregateRootVersion cachedVersion, AggregateRootVersion storedVersion); - - [LoggerMessage(0, LogLevel.Warning, "Aggregate root '{AggregateRootId}' with event source '{EventSourceId}' version has a concurrency conflict, expected version {ExpectedAggregateRootVersion} but cached version {CachedVersion} is consistent with storage")] - internal static partial void AggregateRootConcurrencyConflictWithConsistentCache(this ILogger logger, ArtifactId aggregateRootId, EventSourceId eventSourceId, AggregateRootVersion expectedAggregateRootVersion, AggregateRootVersion cachedVersion); -} diff --git a/Source/Events.Store/Events.Store.csproj b/Source/Events.Store/Events.Store.csproj deleted file mode 100644 index 22b56a3e0..000000000 --- a/Source/Events.Store/Events.Store.csproj +++ /dev/null @@ -1,37 +0,0 @@ - - - - - Dolittle.Runtime.Events.Store - Dolittle.Runtime.Events.Store - - - - - - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - diff --git a/Source/Events.Store/Streams/ICanFetchEventsFromPartitionedStream.cs b/Source/Events.Store/Streams/ICanFetchEventsFromPartitionedStream.cs deleted file mode 100644 index 6a44b672e..000000000 --- a/Source/Events.Store/Streams/ICanFetchEventsFromPartitionedStream.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Rudimentary; - -namespace Dolittle.Runtime.Events.Store.Streams; - -/// -/// Defines a system that can fetch events from streams. -/// -public interface ICanFetchEventsFromPartitionedStream : ICanFetchEventsFromStream -{ - /// - /// Fetch the first event in the given partition from a given . - /// - /// The . - /// the position in the stream. - /// The . - /// The with result. - Task>> FetchInPartition(PartitionId partitionId, StreamPosition streamPosition, CancellationToken cancellationToken); -} diff --git a/Source/Events.Store/Streams/IStreamProcessorState.cs b/Source/Events.Store/Streams/IStreamProcessorState.cs deleted file mode 100644 index a281bdb15..000000000 --- a/Source/Events.Store/Streams/IStreamProcessorState.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Dolittle.Runtime.Events.Store.Streams; - -/// -/// Defines the basis for the state of a . -/// -public interface IStreamProcessorState -{ - /// - /// Gets the . - /// - StreamPosition Position { get; } - - /// - /// Gets a value indicating whether this is partitioned or not. - /// - bool Partitioned { get; } -} \ No newline at end of file diff --git a/Source/Events/ActorPropsAdder.cs b/Source/Events/ActorPropsAdder.cs new file mode 100644 index 000000000..982004782 --- /dev/null +++ b/Source/Events/ActorPropsAdder.cs @@ -0,0 +1,29 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Dolittle.Runtime.Actors; +using Dolittle.Runtime.DependencyInversion; +using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Processing.EventHandlers.Actors; +using Microsoft.Extensions.DependencyInjection; + +namespace Dolittle.Runtime.Events; + +public class ActorPropsAdder : ICanAddServices +{ + public void AddTo(IServiceCollection services) + { + services.AddSingleton(sp => EventHandlerProcessorActor.CreateFactory(new CreateProps(sp))); + services.AddScoped>(globalServiceProvider => + tenant => + { + var createProps = globalServiceProvider.GetRequiredService>()(tenant); + + // var getTenantedServiceProvider = globalServiceProvider.GetRequiredService>(); + // var serviceProvider = getTenantedServiceProvider(tenant); + // var createProps = new CreateProps(serviceProvider); + return TenantScopedStreamProcessorActor.CreateFactory(createProps); + }); + } +} diff --git a/Source/Aggregates/AggregateRoot.cs b/Source/Events/Aggregates/AggregateRoot.cs similarity index 100% rename from Source/Aggregates/AggregateRoot.cs rename to Source/Events/Aggregates/AggregateRoot.cs diff --git a/Source/Aggregates/AggregateRootAlias.cs b/Source/Events/Aggregates/AggregateRootAlias.cs similarity index 100% rename from Source/Aggregates/AggregateRootAlias.cs rename to Source/Events/Aggregates/AggregateRootAlias.cs diff --git a/Source/Aggregates/AggregateRootId.cs b/Source/Events/Aggregates/AggregateRootId.cs similarity index 100% rename from Source/Aggregates/AggregateRootId.cs rename to Source/Events/Aggregates/AggregateRootId.cs diff --git a/Source/Aggregates/AggregateRootInstance.cs b/Source/Events/Aggregates/AggregateRootInstance.cs similarity index 100% rename from Source/Aggregates/AggregateRootInstance.cs rename to Source/Events/Aggregates/AggregateRootInstance.cs diff --git a/Source/Aggregates/AggregateRootInstances.cs b/Source/Events/Aggregates/AggregateRootInstances.cs similarity index 100% rename from Source/Aggregates/AggregateRootInstances.cs rename to Source/Events/Aggregates/AggregateRootInstances.cs diff --git a/Source/Aggregates/AggregateRootVersion.cs b/Source/Events/Aggregates/AggregateRootVersion.cs similarity index 100% rename from Source/Aggregates/AggregateRootVersion.cs rename to Source/Events/Aggregates/AggregateRootVersion.cs diff --git a/Source/Aggregates/AggregateRootWithInstances.cs b/Source/Events/Aggregates/AggregateRootWithInstances.cs similarity index 100% rename from Source/Aggregates/AggregateRootWithInstances.cs rename to Source/Events/Aggregates/AggregateRootWithInstances.cs diff --git a/Source/Aggregates/AggregateRoots.cs b/Source/Events/Aggregates/AggregateRoots.cs similarity index 100% rename from Source/Aggregates/AggregateRoots.cs rename to Source/Events/Aggregates/AggregateRoots.cs diff --git a/Source/Aggregates/AggregateRootsService.cs b/Source/Events/Aggregates/AggregateRootsService.cs similarity index 100% rename from Source/Aggregates/AggregateRootsService.cs rename to Source/Events/Aggregates/AggregateRootsService.cs diff --git a/Source/Aggregates/ArtifactsExtensions.cs b/Source/Events/Aggregates/ArtifactsExtensions.cs similarity index 100% rename from Source/Aggregates/ArtifactsExtensions.cs rename to Source/Events/Aggregates/ArtifactsExtensions.cs diff --git a/Source/Aggregates/IAggregateRootInstances.cs b/Source/Events/Aggregates/IAggregateRootInstances.cs similarity index 100% rename from Source/Aggregates/IAggregateRootInstances.cs rename to Source/Events/Aggregates/IAggregateRootInstances.cs diff --git a/Source/Aggregates/IAggregateRoots.cs b/Source/Events/Aggregates/IAggregateRoots.cs similarity index 100% rename from Source/Aggregates/IAggregateRoots.cs rename to Source/Events/Aggregates/IAggregateRoots.cs diff --git a/Source/Aggregates/IFetchAggregateRootInstances.cs b/Source/Events/Aggregates/IFetchAggregateRootInstances.cs similarity index 100% rename from Source/Aggregates/IFetchAggregateRootInstances.cs rename to Source/Events/Aggregates/IFetchAggregateRootInstances.cs diff --git a/Source/Aggregates.Management/AggregateRootIsNotRegistered.cs b/Source/Events/Aggregates/Management/AggregateRootIsNotRegistered.cs similarity index 100% rename from Source/Aggregates.Management/AggregateRootIsNotRegistered.cs rename to Source/Events/Aggregates/Management/AggregateRootIsNotRegistered.cs diff --git a/Source/Aggregates.Management/AggregateRootWithTenantScopedInstances.cs b/Source/Events/Aggregates/Management/AggregateRootWithTenantScopedInstances.cs similarity index 100% rename from Source/Aggregates.Management/AggregateRootWithTenantScopedInstances.cs rename to Source/Events/Aggregates/Management/AggregateRootWithTenantScopedInstances.cs diff --git a/Source/Aggregates.Management/AggregateRootsService.cs b/Source/Events/Aggregates/Management/AggregateRootsService.cs similarity index 100% rename from Source/Aggregates.Management/AggregateRootsService.cs rename to Source/Events/Aggregates/Management/AggregateRootsService.cs diff --git a/Source/Aggregates.Management/GetTenantScopedAggregateRoot.cs b/Source/Events/Aggregates/Management/GetTenantScopedAggregateRoot.cs similarity index 100% rename from Source/Aggregates.Management/GetTenantScopedAggregateRoot.cs rename to Source/Events/Aggregates/Management/GetTenantScopedAggregateRoot.cs diff --git a/Source/Aggregates.Management/IGetTenantScopedAggregateRoot.cs b/Source/Events/Aggregates/Management/IGetTenantScopedAggregateRoot.cs similarity index 100% rename from Source/Aggregates.Management/IGetTenantScopedAggregateRoot.cs rename to Source/Events/Aggregates/Management/IGetTenantScopedAggregateRoot.cs diff --git a/Source/Aggregates.Management/LoggerExtensions.cs b/Source/Events/Aggregates/Management/LoggerExtensions.cs similarity index 100% rename from Source/Aggregates.Management/LoggerExtensions.cs rename to Source/Events/Aggregates/Management/LoggerExtensions.cs diff --git a/Source/Aggregates.Management/TenantScopedAggregateRootInstance.cs b/Source/Events/Aggregates/Management/TenantScopedAggregateRootInstance.cs similarity index 100% rename from Source/Aggregates.Management/TenantScopedAggregateRootInstance.cs rename to Source/Events/Aggregates/Management/TenantScopedAggregateRootInstance.cs diff --git a/Source/Events/Events.csproj b/Source/Events/Events.csproj index 6aac77bb3..31dd8e229 100644 --- a/Source/Events/Events.csproj +++ b/Source/Events/Events.csproj @@ -6,12 +6,41 @@ Dolittle.Runtime.Events + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + - + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Events/InternalsVisibleTo.cs b/Source/Events/InternalsVisibleTo.cs new file mode 100644 index 000000000..362d61fd0 --- /dev/null +++ b/Source/Events/InternalsVisibleTo.cs @@ -0,0 +1,6 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +[assembly:InternalsVisibleTo("Events.Processing.Tests")] \ No newline at end of file diff --git a/Source/Events.Management/EventTypesService.cs b/Source/Events/Management/EventTypesService.cs similarity index 100% rename from Source/Events.Management/EventTypesService.cs rename to Source/Events/Management/EventTypesService.cs diff --git a/Source/Events.Management/LoggerExtensions.cs b/Source/Events/Management/LoggerExtensions.cs similarity index 100% rename from Source/Events.Management/LoggerExtensions.cs rename to Source/Events/Management/LoggerExtensions.cs diff --git a/Source/Events/MappingExtensions.cs b/Source/Events/MappingExtensions.cs new file mode 100644 index 000000000..14278ed71 --- /dev/null +++ b/Source/Events/MappingExtensions.cs @@ -0,0 +1,23 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Protobuf; + +namespace Dolittle.Runtime.Events; + +public static class MappingExtensions +{ + public static CommittedEvent FromProtobuf(this Contracts.CommittedEvent committedEvent) + { + return new CommittedEvent( + committedEvent.EventLogSequenceNumber, + committedEvent.Occurred.ToDateTimeOffset(), + committedEvent.EventSourceId, + committedEvent.ExecutionContext.ToExecutionContext(), + committedEvent.EventType.ToArtifact(), + committedEvent.Public, + committedEvent.Content); + + } +} diff --git a/Source/Events/Processing/EventHandlers/Actors/ActorEventHandler.cs b/Source/Events/Processing/EventHandlers/Actors/ActorEventHandler.cs new file mode 100644 index 000000000..ba81119fe --- /dev/null +++ b/Source/Events/Processing/EventHandlers/Actors/ActorEventHandler.cs @@ -0,0 +1,293 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Runtime.ExceptionServices; +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Artifacts; +using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Events.Store.Streams.Filters; +using Dolittle.Runtime.Protobuf; +using Dolittle.Runtime.Rudimentary; +using Dolittle.Runtime.Tenancy; +using Microsoft.Extensions.Logging; +using Proto; +using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; +using Failure = Dolittle.Runtime.Protobuf.Failure; + +namespace Dolittle.Runtime.Events.Processing.EventHandlers.Actors; + +/// +/// Represents an event handler in the system. +/// +/// +/// An event handler is a formalized type that consists of a filter and an event processor. +/// The filter filters off of an event log based on the types of events the handler is interested in +/// and puts these into a stream for the filter. From this new stream, the event processor will handle +/// the forwarding to the client for it to handle the event. +/// What sets an event handler apart is that it has a formalization around the stream definition that +/// consists of the events it is interested in, which is defined from the client. +/// +public class ActorEventHandler : IEventHandler +{ + readonly ActorSystem _actorSystem; + readonly ITenants _tenants; + readonly CreateStreamProcessorActorProps _createStreamProcessorActorProps; + readonly IStreamDefinitions _streamDefinitions; + readonly EventHandlerRegistrationArguments _arguments; + readonly Func _eventProcessorForTenant; + readonly Func _acceptRegistration; + readonly Func _rejectRegistration; + readonly IMetricsCollector _metrics; + readonly ExecutionContext _executionContext; + readonly ILogger _logger; + readonly CancellationTokenSource _cancellationTokenSource; + + PID? _eventHandlerKindPid; + + bool _disposed; + + /// + /// Initializes a new instance of . + /// + /// The. + /// Connecting arguments. + /// The event processor. + /// Accepts the event handler registration. + /// Rejects the event handler registration. + /// The collector to use for metrics. + /// Logger for logging. + /// The execution context for the event handler. + /// Cancellation token that can cancel the hierarchy. + /// + /// + /// + public ActorEventHandler( + IStreamDefinitions streamDefinitions, + EventHandlerRegistrationArguments arguments, + Func eventProcessorForTenant, + Func acceptRegistration, + Func rejectRegistration, + IMetricsCollector metrics, + ILogger logger, + ExecutionContext executionContext, + ActorSystem actorSystem, + ITenants tenants, + CreateStreamProcessorActorProps createStreamProcessorActorProps, + CancellationToken cancellationToken + ) + { + _logger = logger; + _streamDefinitions = streamDefinitions; + _arguments = arguments; + _executionContext = executionContext; + _actorSystem = actorSystem; + _tenants = tenants; + _createStreamProcessorActorProps = createStreamProcessorActorProps; + _eventProcessorForTenant = eventProcessorForTenant; + _acceptRegistration = acceptRegistration; + _rejectRegistration = rejectRegistration; + _metrics = metrics; + _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + } + + StreamId TargetStream => _arguments.EventHandler.Value; + + /// + public EventHandlerInfo Info => new( + new EventHandlerId(_arguments.Scope, _arguments.EventHandler), + _arguments.HasAlias, + _arguments.Alias, + _arguments.EventTypes, + _arguments.Partitioned, + _arguments.Concurrency); + + public ScopeId Scope => _arguments.Scope.Value; + + public EventProcessorId EventProcessor => _arguments.EventHandler.Value; + + StreamProcessorId StreamProcessorId => new(Scope, EventProcessor, EventProcessor.Value); + + IEnumerable EventTypes => _arguments.EventTypes; + + bool Partitioned => _arguments.Partitioned; + + public StreamDefinition FilteredStreamDefinition => new( + new TypeFilterWithEventSourcePartitionDefinition( + TargetStream, + TargetStream, + EventTypes, + Partitioned)); + + public Task>> GetEventHandlerCurrentState() => + RequestAsync, GetCurrentProcessorState>(GetCurrentProcessorState.Instance); + + public Task> ReprocessEventsFrom(TenantId tenant, ProcessingPosition position) + => RequestAsync(new ReprocessEventsFrom(tenant, position)); + + public Task>>> ReprocessAllEvents() => Try>>.DoAsync( + async () => + { + var results = new Dictionary>(); + + foreach (var tenantId in _tenants.All) + { + var result = await RequestAsync(new ReprocessEventsFrom(tenantId, ProcessingPosition.Initial)); + results.Add(tenantId, result); + } + + return results; + }); + + + Task> RequestAsync(TM message, CancellationToken cancellationToken = default) where TM : class + { + if (_eventHandlerKindPid == null) + return Task.FromResult(Try.Failed(new ArgumentException("Event handler is in an invalid state"))); + return Try.DoAsync( + async () => + { + var response = await _actorSystem.Root.RequestAsync(_eventHandlerKindPid, + message, + cancellationToken); + return response switch + { + TR state => state, + Exception exception => throw exception, + _ => throw new ArgumentException("Unexpected response from GetEventHandlerCurrentState: " + response) + }; + }); + } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Dispose managed and unmanaged resources. + /// + /// Whether to dispose managed resources. + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + if (disposing) + { + if (_eventHandlerKindPid != null) + { + _actorSystem.Root.StopAsync(_eventHandlerKindPid).GetAwaiter().GetResult(); + } + + // EventProcessorStreamProcessor?.Dispose(); + _cancellationTokenSource.Dispose(); + } + + _disposed = true; + } + + /// + public async Task RegisterAndStart() + { + _logger.ConnectingEventHandlerWithId(EventProcessor); + await Start().ConfigureAwait(false); + } + + // /// + // public event EventHandlerRegistrationFailed? OnRegistrationFailed; + + + async Task Start() + { + void ProcessedEvent(TenantId tenant, StreamEvent @event, TimeSpan time) + { + _metrics.IncrementEventsProcessedTotal(Info, tenant, @event, time); + } + + void FailedToProcessEvent(TenantId tenant, StreamEvent @event, TimeSpan time) + { + _metrics.IncrementEventsProcessedTotal(Info, tenant, @event, time); + _metrics.IncrementEventProcessingFailuresTotal(Info, tenant, @event); + } + + var props = _createStreamProcessorActorProps.Invoke(StreamProcessorId, FilteredStreamDefinition, _eventProcessorForTenant, + ProcessedEvent, FailedToProcessEvent, _executionContext, Info, _cancellationTokenSource); + try + { + _eventHandlerKindPid = _actorSystem.Root.SpawnNamed(props, EventProcessor.Value.ToString()); + } + catch (ProcessNameExistException ex) + { + _logger.ErrorWhileStartingEventHandler(ex, EventProcessor, Scope); + ExceptionDispatchInfo.Capture(ex).Throw(); + } + + + // _logger.StartingEventHandler(FilterDefinition.TargetStream); + // Ensure that the event handler can terminate gracefully if the application is shutting down. + try + { + var runningDispatcher = _acceptRegistration(_cancellationTokenSource.Token); + var processorDone = _actorSystem.DeathWatch(_eventHandlerKindPid); + + + await PersistFilter().ConfigureAwait(false); + var tasks = new List + { + runningDispatcher, + processorDone + }; + var taskGroup = new TaskGroup(tasks); + + + taskGroup.OnFirstTaskFailure += (_, ex) => + { + if (ex is OperationCanceledException) + { + _logger.CancelledRunningEventHandler(ex, EventProcessor, Scope); + } + else + { + _logger.ErrorWhileRunningEventHandler(ex, EventProcessor, Scope); + } + }; + taskGroup.OnAllTasksCompleted += () => _logger.EventHandlerDisconnected(EventProcessor, Scope); + + await taskGroup.WaitForAllCancellingOnFirst(_cancellationTokenSource).ConfigureAwait(false); + } + catch (Exception ex) + { + if (!_cancellationTokenSource.Token.IsCancellationRequested) + { + _logger.ErrorWhileStartingEventHandler(ex, EventProcessor, Scope); + } + + ExceptionDispatchInfo.Capture(ex).Throw(); + } + } + + async Task PersistFilter() + { + var filteredStreamDefinition = new StreamDefinition(FilteredStreamDefinition.FilterDefinition); + _logger.PersistingStreamDefinition(filteredStreamDefinition.StreamId); + await _streamDefinitions.Persist(Scope, filteredStreamDefinition, _cancellationTokenSource.Token).ConfigureAwait(false); + } + + Task Fail(FailureId failureId, string message) + => Fail(new Failure(failureId, message)); + + Task Fail(Failure failure) + { + return _rejectRegistration(failure, _cancellationTokenSource.Token); + } +} diff --git a/Source/Events/Processing/EventHandlers/Actors/ActorSystemExtensions.cs b/Source/Events/Processing/EventHandlers/Actors/ActorSystemExtensions.cs new file mode 100644 index 000000000..57862b40c --- /dev/null +++ b/Source/Events/Processing/EventHandlers/Actors/ActorSystemExtensions.cs @@ -0,0 +1,34 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading.Tasks; +using Proto; + +namespace Dolittle.Runtime.Events.Processing.EventHandlers.Actors; + +static class ActorSystemExtensions +{ + // Wait for the actor represented by the PID to be terminated + public static Task DeathWatch(this ActorSystem system, PID pid) + { + var tcs = new TaskCompletionSource(); + system.Root.Spawn(Props.FromFunc(ctx => + { + switch (ctx.Message) + { + case Started: + ctx.Watch(pid); + return Task.CompletedTask; + + case Terminated: + tcs.SetResult(); + ctx.Stop(ctx.Self); + return Task.CompletedTask; + + default: + return Task.CompletedTask; + } + })); + return tcs.Task; + } +} diff --git a/Source/Events/Processing/EventHandlers/Actors/ConcurrentPartitionedProcessor.cs b/Source/Events/Processing/EventHandlers/Actors/ConcurrentPartitionedProcessor.cs new file mode 100644 index 000000000..6427edc38 --- /dev/null +++ b/Source/Events/Processing/EventHandlers/Actors/ConcurrentPartitionedProcessor.cs @@ -0,0 +1,412 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading; +using System.Threading.Channels; +using System.Threading.Tasks; +using Dolittle.Runtime.Artifacts; +using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Events.Store.Streams; +using Microsoft.Extensions.Logging; +using Proto; +using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; +using StreamProcessorState = Dolittle.Runtime.Events.Processing.Streams.Partitioned.StreamProcessorState; + +namespace Dolittle.Runtime.Events.Processing.EventHandlers.Actors; + +public class ConcurrentPartitionedProcessor : ProcessorBase +{ + readonly ICanFetchEventsFromPartitionedStream _fetcher; + + internal delegate State ReceiveResult(State current); + + internal class ActiveRequests + { + readonly int _concurrency; + readonly HashSet _currentPartitions = new(); + readonly Channel<(PartitionId partition, Task callback)> _currentlyProcessing; + readonly ChannelReader<(PartitionId partition, Task callback)> _reader; + + public IReadOnlySet PartitionsBeingProcessed => _currentPartitions; + + public ActiveRequests(int concurrency) + { + _concurrency = concurrency; + _currentlyProcessing = Channel.CreateUnbounded<(PartitionId, Task)>(new UnboundedChannelOptions + { + SingleReader = true, + SingleWriter = true + }); + _reader = _currentlyProcessing.Reader; + } + + public bool IsProcessing(PartitionId partitionId) => _currentPartitions.Contains(partitionId); + + public ValueTask Add(PartitionId partitionId, Task callBack) + { + if (!_currentPartitions.Add(partitionId)) throw new ArgumentException($"Partition {partitionId} is already being processed"); + return _currentlyProcessing.Writer.WriteAsync((partitionId, callBack)); + } + + public ValueTask AddSkipped(Task callBack) + { + return _currentlyProcessing.Writer.WriteAsync((PartitionId.None, callBack)); + } + + public bool HasCompletedRequests() + { + return _reader.TryPeek(out var next) && next.callback.IsCompleted; + } + + public async Task WaitForNextCompleted(CancellationToken cancellationToken) + { + await _reader.WaitToReadAsync(cancellationToken); + _reader.TryPeek(out var next); + await next.callback; + } + + public async ValueTask> GetNextCompleted(CancellationToken cancellationToken) + { + var (partition, callback) = await _reader.ReadAsync(cancellationToken).ConfigureAwait(false); + if (partition != PartitionId.None) + { + _currentPartitions.Remove(partition); + } + + return callback; + } + + public bool IsEmpty => _currentPartitions.Count == 0; + public bool IsFull => _currentPartitions.Count >= _concurrency; + public int Count => _currentPartitions.Count; + } + + internal record State(StreamProcessorState ProcessorState, ActiveRequests ActiveRequests) + { + public bool NoFailingEvents => ProcessorState.FailingPartitions.IsEmpty; + + public bool TryGetTimeToRetry(ActiveRequests activeRequests, out TimeSpan timeToRetry, [NotNullWhen(true)] out PartitionId? selectedPartitionId) + { + timeToRetry = TimeSpan.MaxValue; + selectedPartitionId = default; + if (NoFailingEvents) return false; + var processing = activeRequests.PartitionsBeingProcessed; + foreach (var (partitionId, failingPartitionState) in ProcessorState.FailingPartitions) + { + if (processing.Contains(partitionId)) continue; + if (failingPartitionState.TryGetTimespanToRetry(out var partitionTimeToRetry) && partitionTimeToRetry < timeToRetry) + { + timeToRetry = partitionTimeToRetry; + selectedPartitionId = partitionId; + } + } + + return timeToRetry < TimeSpan.MaxValue; + } + + /// + /// Mark the event as skipped. Used when the event partition is failing, and the event should be retried out of band + /// + /// + /// + public State WithSkippedEvent(StreamEvent streamEvent) => + this with { ProcessorState = ProcessorState.WithResult(SkippedProcessing.Instance, streamEvent, DateTimeOffset.UtcNow) }; + } + + readonly ImmutableHashSet _handledTypes; + readonly int _concurrency; + + + public ConcurrentPartitionedProcessor( + StreamProcessorId streamProcessorId, + IEnumerable handledEventTypes, + IEventProcessor processor, + IStreamProcessorStates streamProcessorStates, + ExecutionContext executionContext, + ScopedStreamProcessorProcessedEvent onProcessed, + ScopedStreamProcessorFailedToProcessEvent onFailedToProcess, + TenantId tenantId, + ICanFetchEventsFromPartitionedStream fetcher, + int concurrency, + ILogger logger) + : + base( + streamProcessorId, processor, streamProcessorStates, executionContext, onProcessed, onFailedToProcess, tenantId, logger) + { + _fetcher = fetcher; + _concurrency = concurrency; + _handledTypes = handledEventTypes.Select(_ => _.Value).ToImmutableHashSet(); + } + + public async Task Process(ChannelReader messages, IStreamProcessorState state, CancellationToken cancellationToken, + CancellationToken deadlineToken) + { + var currentState = new State(AsPartitioned(state), new ActiveRequests(_concurrency)); + try + { + while (!cancellationToken.IsCancellationRequested) + { + var (nextAction, partitionId) = await WaitForNextAction(messages, currentState, cancellationToken); + try + { + switch (nextAction) + { + case NextAction.ReceiveResult: + currentState = await ProcessReceiveResult(currentState, cancellationToken, deadlineToken); + break; + + case NextAction.ProcessNextEvent: + currentState = await ProcessNextEvent(messages, currentState, cancellationToken, deadlineToken); + + break; + case NextAction.ProcessFailedEvent: + currentState = await CatchUpForPartition(currentState, partitionId!, cancellationToken, deadlineToken); + + break; + case NextAction.Completed: + return; + } + } + finally + { + await PersistNewState(currentState.ProcessorState, deadlineToken); + } + } + } + finally + { + // If there are requests in-flight, let's try to wait for them to complete + + await WaitForCompletions(currentState, deadlineToken); + } + } + + async Task WaitForCompletions(State currentState, CancellationToken deadlineToken) + { + if (currentState.ActiveRequests.IsEmpty) + return; + + Logger.WaitingForCompletions(Identifier.EventProcessorId, Identifier.ScopeId, currentState.ActiveRequests.Count); + + try + { + var timeout = CancellationTokens.FromSeconds(10); + while (!currentState.ActiveRequests.IsEmpty && !deadlineToken.IsCancellationRequested) + { + currentState = await ProcessReceiveResult(currentState, timeout, deadlineToken); + } + + Logger.FinishedWaitingForCompletions(Identifier.EventProcessorId, Identifier.ScopeId); + } + catch (Exception e) + { + Logger.FailedWaitingForCompletions(e, Identifier.EventProcessorId, Identifier.ScopeId, currentState.ActiveRequests.Count); + } + } + + async Task ProcessNextEvent(ChannelReader messages, State currentState, CancellationToken stoppingToken, + CancellationToken deadlineToken) + { + var evt = await messages.ReadAsync(stoppingToken); + if (currentState.ProcessorState.FailingPartitions.TryGetValue(evt.Partition, out _)) + { + await currentState.ActiveRequests.AddSkipped(Task.FromResult(AsSkippedEvent(evt))); + return currentState; + } + + var newTask = ProcessEventAndReturnStateUpdateCallback(evt, deadlineToken); + await currentState.ActiveRequests.Add(evt.Partition, newTask).ConfigureAwait(false); + return currentState; + } + + ReceiveResult AsSkippedEvent(StreamEvent evt) => current => current.WithSkippedEvent(evt); + + async Task ProcessReceiveResult(State currentState, CancellationToken cancellationToken, CancellationToken deadlineToken) + { + var readAsync = await currentState.ActiveRequests.GetNextCompleted(cancellationToken); + var receive = await readAsync; + currentState = receive(currentState); + await PersistNewState(currentState.ProcessorState, deadlineToken); + return currentState; + } + + async Task ProcessEventAndReturnStateUpdateCallback(StreamEvent evt, CancellationToken cancellationToken) + { + var (processingResult, elapsed) = await ProcessEvent(evt, cancellationToken); + + return state => + { + var updatedState = HandleProcessingResult(processingResult, evt, elapsed, state.ProcessorState); + + return state with { ProcessorState = updatedState }; + }; + } + + internal enum NextAction + { + /// + /// Process the next event in the event stream. + /// + ProcessNextEvent, + + /// + /// Receive the result of the current event being processed + /// + ReceiveResult, + + /// + /// Retry processing of failed events. + /// + ProcessFailedEvent, + + /// + /// Processing is complete. + /// + Completed + } + + /// + /// Determines which action to take next. + /// If the current processing is complete, it will return . + /// Else it will wait for new data to become available or for the retry delay to expire. + /// + /// + /// + /// + /// + /// + internal static async ValueTask<(NextAction, PartitionId?)> WaitForNextAction( + ChannelReader messages, + State state, + CancellationToken cancellationToken) + { + Task? resultReady = null; + + if (state.ActiveRequests.IsFull || state.ActiveRequests.HasCompletedRequests()) + { + return (NextAction.ReceiveResult, default); + } + + if (!state.ActiveRequests.IsEmpty) + { + resultReady = state.ActiveRequests.WaitForNextCompleted(cancellationToken); + } + + Task? retryAfter = null; + + if (state.TryGetTimeToRetry(state.ActiveRequests, out var timeToRetry, out var partitionId)) + { + if (timeToRetry <= TimeSpan.Zero) + { + return (NextAction.ProcessFailedEvent, partitionId); + } + + // Not ready to retry yet + retryAfter = Task.Delay(timeToRetry, cancellationToken); + } + + var tasks = new List(3); + if (resultReady != null) + { + tasks.Add(resultReady); + } + + if (retryAfter != null) + { + tasks.Add(retryAfter); + } + + var readyToRead = messages.WaitToReadAsync(cancellationToken).AsTask(); + tasks.Add(readyToRead); + + await Task.WhenAny(tasks); + + // Prioritize processing of results over retrying + if (resultReady is not null && resultReady.IsCompleted) + { + return (NextAction.ReceiveResult, partitionId); + } + + // If a partition is ready to retry, do that + if (retryAfter is not null && retryAfter.IsCompletedSuccessfully) + { + return (NextAction.ProcessFailedEvent, partitionId); + } + + // Else check if there are more events to process + var hasMoreEvents = readyToRead.IsCompleted && readyToRead.Result; + + // Channel has closed, processor is terminating + if (!hasMoreEvents) + { + if (state.ActiveRequests.IsEmpty) + { + return (NextAction.Completed, default); + } + + return (NextAction.ReceiveResult, default); + } + + if (messages.TryPeek(out var streamEvent) && state.ActiveRequests.IsProcessing(streamEvent.Partition)) + { + return (NextAction.ReceiveResult, streamEvent.Partition); + } + + return (NextAction.ProcessNextEvent, default); + } + + StreamProcessorState AsPartitioned(IStreamProcessorState state) + { + switch (state) + { + case StreamProcessorState partitionedState: + return partitionedState; + + case Dolittle.Runtime.Events.Processing.Streams.StreamProcessorState nonPartitionedState: + if (!nonPartitionedState.IsFailing) + { + Logger.LogInformation("Converting non-partitioned state to partitioned for {StreamProcessorId}", Identifier); + return new StreamProcessorState(nonPartitionedState.Position, nonPartitionedState.LastSuccessfullyProcessed); + } + + throw new ArgumentException("State is not convertible to partitioned"); + + default: + throw new ArgumentException("State is of invalid type"); + } + } + + async Task CatchUpForPartition(State state, + PartitionId partition, + CancellationToken cancellationToken, CancellationToken deadlineToken) + { + var failingPartitionState = state.ProcessorState.FailingPartitions[partition]; + if (!ShouldRetryProcessing(failingPartitionState)) return state; // Should not really happen, since we explicitly wait for each partition + + var startPosition = new StreamPosition(failingPartitionState.Position.EventLogPosition.Value); + var highWatermark = new StreamPosition(state.ProcessorState.Position.EventLogPosition.Value); + + var (evt, _) = await _fetcher.FetchNextEventInPartition(partition, startPosition, highWatermark, _handledTypes, cancellationToken); + + if (evt is null) + { + // No more events before the high water mark for this partition, remove it + state = state with { ProcessorState = state.ProcessorState.WithoutFailingPartition(partition) }; + await PersistNewState(state.ProcessorState, deadlineToken); + return state; + } + + var newTask = ProcessEventAndReturnStateUpdateCallback(evt, deadlineToken); + await state.ActiveRequests.Add(evt.Partition, newTask); + return state; + } + + static bool ShouldRetryProcessing(FailingPartitionState state) => DateTimeOffset.UtcNow.CompareTo(state.RetryTime) >= 0; +} diff --git a/Source/Events/Processing/EventHandlers/Actors/EventHandlerClient.cs b/Source/Events/Processing/EventHandlers/Actors/EventHandlerClient.cs new file mode 100644 index 000000000..b572b5a55 --- /dev/null +++ b/Source/Events/Processing/EventHandlers/Actors/EventHandlerClient.cs @@ -0,0 +1,66 @@ +// // Copyright (c) Dolittle. All rights reserved. +// // Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// using System.Collections.Generic; +// using System.Threading; +// using System.Threading.Tasks; +// using Dolittle.Runtime.Domain.Tenancy; +// using Dolittle.Runtime.Events.Processing.Streams.Actors; +// using Dolittle.Runtime.Events.Store.Streams; +// using Dolittle.Runtime.Rudimentary; +// using Dolittle.Runtime.Tenancy; +// using Proto; +// +// namespace Dolittle.Runtime.Events.Processing.EventHandlers.Actors; +// +// +// +// public class EventHandlerClient: IEventHandler +// { +// readonly ActorSystem _actorSystem; +// readonly ITenants _tenants; +// readonly PID _kindPid; +// +// public EventHandlerClient(PID kindPid, ActorSystem actorSystem, ITenants tenants) +// { +// _kindPid = kindPid; +// _actorSystem = actorSystem; +// _tenants = tenants; +// } +// +// public EventHandlerInfo Info { get; } +// +// public Task>> GetEventHandlerCurrentState() => Try>.DoAsync(async () => +// { +// var response = await _actorSystem.Root.RequestAsync>(_kindPid, new GetCurrentProcessorState(), +// CancellationToken.None); +// return response; +// }); +// +// public Task> ReprocessEventsFrom(TenantId tenant, ProcessingPosition position) => Try.DoAsync(async () => +// { +// var response = await _actorSystem.Root.RequestAsync(_kindPid, new ReprocessEventsFrom(tenant,position), +// CancellationToken.None); +// return response; +// }); +// +// public Task>>> ReprocessAllEvents() => Try>>.DoAsync(async () => +// { +// var results = new Dictionary>(); +// +// foreach (var tenantId in _tenants.All) +// { +// var result = await _actorSystem.Root.RequestAsync(_kindPid, new ReprocessEventsFrom(tenantId,ProcessingPosition.Initial), +// CancellationToken.None); +// results.Add(tenantId, result); +// } +// +// return results; +// }); +// +// public Task RegisterAndStart() => throw new System.NotImplementedException(); +// +// public void Dispose() => throw new System.NotImplementedException(); +// +// public event EventHandlerRegistrationFailed? OnRegistrationFailed; +// } diff --git a/Source/Events/Processing/EventHandlers/Actors/EventHandlerProcessorActor.cs b/Source/Events/Processing/EventHandlers/Actors/EventHandlerProcessorActor.cs new file mode 100644 index 000000000..42d8b6756 --- /dev/null +++ b/Source/Events/Processing/EventHandlers/Actors/EventHandlerProcessorActor.cs @@ -0,0 +1,321 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Actors; +using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Events.Store.Streams.Filters; +using Dolittle.Runtime.Tenancy; +using Microsoft.Extensions.Logging; +using Proto; +using Proto.Cluster; +using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; +using StreamProcessorState = Dolittle.Runtime.Events.Processing.Streams.StreamProcessorState; + +namespace Dolittle.Runtime.Events.Processing.EventHandlers.Actors; + +public delegate Props CreateStreamProcessorActorProps( + StreamProcessorId streamProcessorId, + IStreamDefinition streamDefinition, + Func createEventProcessorFor, + StreamProcessorProcessedEvent processedEvent, + StreamProcessorFailedToProcessEvent failedToProcessEvent, + ExecutionContext executionContext, + EventHandlerInfo eventHandlerInfo, + CancellationTokenSource cancellationTokenSource); + +/// +/// Represents a system for working with all the registered for . +/// +public class EventHandlerProcessorActor : IDisposable, IActor +{ + readonly StreamProcessorId _identifier; + readonly ITenants _tenants; + readonly Func _getStreamProcessorStates; + readonly EventHandlerInfo _eventHandlerInfo; + readonly Func _createEventProcessorFor; + readonly Streams.IMetricsCollector _metrics; + readonly ILogger _logger; + readonly Func _getCreateScopedStreamProcessorProps; + readonly StreamProcessorProcessedEvent _onProcessedEvent; + readonly StreamProcessorFailedToProcessEvent _onFailedToProcessEvent; + readonly ExecutionContext _executionContext; + readonly CancellationTokenSource _stopAllProcessors; + readonly TypeFilterWithEventSourcePartitionDefinition _filter; + readonly Dictionary _streamProcessors = new(); + readonly CancellationTokenSource _stopEverything; + bool _started; + bool _disposed; + + + /// + /// Initializes a new instance of the class. + /// + /// The identifier of the stream processor. + /// The definition of the stream the processor should process events from. + /// The factory to use to create an event processor per tenant. + /// The execution context to run the processor in. + /// + /// + /// + /// The logger to use for logging. + /// The factory to us to get the scoped stream processor creator per tenant. + /// + /// + /// + /// The cancellation token that is cancelled when the stream processor should stop processing. + public EventHandlerProcessorActor( + StreamProcessorId streamProcessorId, + IStreamDefinition streamDefinition, + Func createEventProcessorFor, + ExecutionContext executionContext, + Streams.IMetricsCollector metrics, + StreamProcessorProcessedEvent onProcessedEvent, + StreamProcessorFailedToProcessEvent onFailedToProcessEvent, + ILogger logger, + Func getCreateScopedStreamProcessorProps, + ITenants tenants, + Func getStreamProcessorStates, + EventHandlerInfo eventHandlerInfo, + CancellationTokenSource stoppingToken) + { + if (streamDefinition.FilterDefinition is not TypeFilterWithEventSourcePartitionDefinition filter) + { + throw new ArgumentException("streamDefinition.FilterDefinition definition must be of type TypeFilterWithEventSourcePartitionDefinition", + nameof(streamDefinition)); + } + + _filter = filter; + _identifier = streamProcessorId; + _tenants = tenants; + _getStreamProcessorStates = getStreamProcessorStates; + _eventHandlerInfo = eventHandlerInfo; + _createEventProcessorFor = createEventProcessorFor; + _metrics = metrics; + _logger = logger; + _getCreateScopedStreamProcessorProps = getCreateScopedStreamProcessorProps; + _onProcessedEvent = onProcessedEvent; + _onFailedToProcessEvent = onFailedToProcessEvent; + _executionContext = executionContext; + _stopAllProcessors = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken.Token); + _stopEverything = stoppingToken; + } + + public static CreateStreamProcessorActorProps CreateFactory(ICreateProps provider) + => (streamProcessorId, streamDefinition, createEventProcessorFor, processedEvent, failedToProcessEvent, executionContext, eventHandlerInfo, cancellationTokenSource) => + CreatePropsFor(provider, streamProcessorId, streamDefinition, createEventProcessorFor, processedEvent, failedToProcessEvent, executionContext, eventHandlerInfo, + cancellationTokenSource); + + static Props CreatePropsFor(ICreateProps provider, + StreamProcessorId streamProcessorId, + IStreamDefinition streamDefinition, + Func createEventProcessorFor, + StreamProcessorProcessedEvent processedEvent, + StreamProcessorFailedToProcessEvent failedToProcessEvent, + ExecutionContext executionContext, + EventHandlerInfo eventHandlerInfo, + CancellationTokenSource cancellationTokenSource) + => provider.PropsFor( + streamProcessorId, streamDefinition, createEventProcessorFor, executionContext, processedEvent, failedToProcessEvent, eventHandlerInfo, cancellationTokenSource); + + public async Task ReceiveAsync(IContext context) + { + try + { + switch (context.Message) + { + case Started: + await OnStarted(context); + break; + case Stopping: + await OnStopping(context); + break; + case GetCurrentProcessorState: + await OnGetCurrentProcessorState(context); + break; + case ReprocessEventsFrom reprocess: + await OnReprocessEventsFrom(reprocess, context); + break; + case Terminated terminated: + await OnTerminated(terminated, context); + break; + } + } + catch (Exception e) + { + _logger.LogError(e, "Error while processing message {Message}", context.Message); + throw; + } + } + + async Task OnReprocessEventsFrom(ReprocessEventsFrom reprocess, IContext context) + { + try + { + if (_streamProcessors.Remove(reprocess.TenantId, out var pid)) + { + await context.StopAsync(pid); + await _getStreamProcessorStates(reprocess.TenantId).Persist(_identifier, + CreateProcessorState(reprocess.ProcessingPosition, _filter.Partitioned), CancellationToken.None); + InitTenant(reprocess.TenantId, context); + } + else + { + context.Respond(new ArgumentException("TenantId not found")); + } + } + catch (Exception e) + { + context.Respond(e); + } + } + + IStreamProcessorState CreateProcessorState(ProcessingPosition fromPosition, bool partitioned) + { + return partitioned switch + { + true => new Dolittle.Runtime.Events.Processing.Streams.Partitioned.StreamProcessorState(fromPosition, + ImmutableDictionary.Empty, default), + false => new StreamProcessorState(fromPosition, default) + }; + } + + async Task OnGetCurrentProcessorState(IContext context) + { + var states = new Dictionary(); + try + { + foreach (var (tenantId, pid) in _streamProcessors) + { + var forTenant = await _getStreamProcessorStates(tenantId).TryGetFor(_identifier, context.CancellationToken); + // var state = await context.RequestAsync(pid, GetCurrentProcessorState.Instance); + if (forTenant.Success) + { + states.Add(tenantId, forTenant.Result); + } + } + + context.Respond(states); + } + catch (Exception exception) + { + context.Respond(exception); + } + } + + Task OnTerminated(Terminated terminated, IContext context) + { + var stoppedChild = _streamProcessors.FirstOrDefault(_ => _.Value.Equals(terminated.Who)); + if (stoppedChild.Key is not null) + { + if (_stopEverything.IsCancellationRequested) + { + _stopEverything.Cancel(); + } + + _streamProcessors.Remove(stoppedChild.Key); + } + + if (_streamProcessors.Count == 0) + { + context.Stop(context.Self); + } + + return Task.CompletedTask; + } + + async Task OnStopping(IContext context) + { + // Log.StoppingStreamProcessor(_logger, _identifier); + _stopAllProcessors.Cancel(); + await Task.WhenAll(context.Children.Select(context.StopAsync)); + } + + async Task OnStarted(IContext context) + { + while (context.System.Cluster().MemberList is null) + { + await Task.Delay(100); + } + if (!context.System.Cluster().MemberList.Started.IsCompletedSuccessfully) + { + await context.System.Cluster().MemberList.Started; + } + + Streams.Log.InitializingStreamProcessor(_logger, _identifier); + + if (_stopAllProcessors.Token.IsCancellationRequested) + { + // ReSharper disable once MethodHasAsyncOverload + context.Stop(context.Self); + return; + } + + _metrics.IncrementInitializations(EventProcessorKind.Actor); + + foreach (var tenantId in _tenants.All) + { + InitTenant(tenantId, context); + } + + context.ReenterAfterCancellation(_stopEverything.Token, () => context.Stop(context.Self)); + } + + void InitTenant(TenantId tenant, IContext context) + { + void OnProcessed(StreamEvent @event, TimeSpan time) + { + _metrics.IncrementEventsProcessed(EventProcessorKind.Actor, time); + _onProcessedEvent?.Invoke(tenant, @event, time); + } + + void FailedToProcessedEvent(StreamEvent @event, TimeSpan time) + { + _metrics.IncrementEventsProcessed(EventProcessorKind.Actor, time); + _metrics.IncrementFailedEventsProcessed(EventProcessorKind.Actor); + _onFailedToProcessEvent?.Invoke(tenant, @event, time); + } + + var props = _getCreateScopedStreamProcessorProps(tenant).Invoke(_identifier, _filter, _createEventProcessorFor(tenant), _executionContext, + OnProcessed, FailedToProcessedEvent, _eventHandlerInfo, tenant); + + var tenantProcessorPid = context.Spawn(props); + + _streamProcessors.Add(tenant, tenantProcessorPid); + } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Dispose the object. + /// + /// Whether to dispose managed state. + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + if (disposing) + { + _stopAllProcessors.Cancel(); + _stopAllProcessors.Dispose(); + } + + _disposed = true; + } +} diff --git a/Source/Events/Processing/EventHandlers/Actors/Messages.cs b/Source/Events/Processing/EventHandlers/Actors/Messages.cs new file mode 100644 index 000000000..1741feb32 --- /dev/null +++ b/Source/Events/Processing/EventHandlers/Actors/Messages.cs @@ -0,0 +1,18 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Store.Streams; + +namespace Dolittle.Runtime.Events.Processing.EventHandlers.Actors; + +class GetCurrentProcessorState +{ + GetCurrentProcessorState() + { + } + + public static readonly GetCurrentProcessorState Instance = new(); +}; + +record ReprocessEventsFrom(TenantId TenantId, ProcessingPosition ProcessingPosition); diff --git a/Source/Events/Processing/EventHandlers/Actors/NonPartitionedProcessor.cs b/Source/Events/Processing/EventHandlers/Actors/NonPartitionedProcessor.cs new file mode 100644 index 000000000..34f889155 --- /dev/null +++ b/Source/Events/Processing/EventHandlers/Actors/NonPartitionedProcessor.cs @@ -0,0 +1,103 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Linq; +using System.Threading; +using System.Threading.Channels; +using System.Threading.Tasks; +using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Events.Store.Streams.Filters; +using Microsoft.Extensions.Logging; +using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; + +namespace Dolittle.Runtime.Events.Processing.EventHandlers.Actors; + +public class NonPartitionedProcessor : ProcessorBase +{ + public NonPartitionedProcessor( + StreamProcessorId streamProcessorId, + TypeFilterWithEventSourcePartitionDefinition filterDefinition, + IEventProcessor processor, + IStreamProcessorStates streamProcessorStates, + ExecutionContext executionContext, + ScopedStreamProcessorProcessedEvent onProcessed, + ScopedStreamProcessorFailedToProcessEvent onFailedToProcess, + TenantId tenantId, + ILogger logger) + : base( + streamProcessorId, processor, streamProcessorStates, executionContext, onProcessed, onFailedToProcess, tenantId, logger) + { + } + + + public async Task Process(ChannelReader messages, IStreamProcessorState state, CancellationToken cancellationToken, + CancellationToken deadlineToken) + { + var currentState = AsNonPartitioned(state); + while (!cancellationToken.IsCancellationRequested) + { + try + { + var evt = await messages.ReadAsync(cancellationToken); + + (currentState, var processingResult) = await ProcessEventAndHandleResult(evt, currentState, deadlineToken); + await PersistNewState(currentState, deadlineToken); + + while (processingResult is { Succeeded: false, Retry: true }) + { + if (state.TryGetTimespanToRetry(out var retryTimeout)) + { + Logger.LogInformation("Will retry processing event {evt.Position} after {Timeout}", evt, retryTimeout); + await Task.Delay(retryTimeout, cancellationToken); + } + else + { + Logger.LogInformation("Will retry processing event {evt.Position} directly", evt); + } + + if (cancellationToken.IsCancellationRequested) + { + return; + } + + (currentState, processingResult) = await RetryProcessingEventAndHandleResult(evt, currentState, processingResult.FailureReason, + currentState.ProcessingAttempts + 1, deadlineToken); + } + + if (!processingResult.Succeeded) + { + Logger.StoppedFailingEventHandler(Identifier.EventProcessorId, Identifier.ScopeId, currentState.FailureReason); + return; + } + } + finally + { + await PersistNewState(currentState, deadlineToken); + } + } + } + + StreamProcessorState AsNonPartitioned(IStreamProcessorState state) + { + switch (state) + { + case StreamProcessorState nonPartitionedState: + return nonPartitionedState; + + case Dolittle.Runtime.Events.Processing.Streams.Partitioned.StreamProcessorState partitionedState: + if (!partitionedState.FailingPartitions.Any()) + { + Logger.LogInformation("Converting partitioned state to non-partitioned for {StreamProcessorId}", Identifier); + return new StreamProcessorState(partitionedState.Position, partitionedState.LastSuccessfullyProcessed); + } + + throw new ArgumentException("State is not convertible to non-partitioned"); + + default: + throw new ArgumentException("Invalid state type"); + } + } +} diff --git a/Source/Events/Processing/EventHandlers/Actors/PartitionedProcessor.cs b/Source/Events/Processing/EventHandlers/Actors/PartitionedProcessor.cs new file mode 100644 index 000000000..eb789bd61 --- /dev/null +++ b/Source/Events/Processing/EventHandlers/Actors/PartitionedProcessor.cs @@ -0,0 +1,272 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading; +using System.Threading.Channels; +using System.Threading.Tasks; +using Dolittle.Runtime.Artifacts; +using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Events.Store.Streams; +using Microsoft.Extensions.Logging; +using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; +using StreamProcessorState = Dolittle.Runtime.Events.Processing.Streams.Partitioned.StreamProcessorState; + +namespace Dolittle.Runtime.Events.Processing.EventHandlers.Actors; + +public class PartitionedProcessor : ProcessorBase +{ + readonly ICanFetchEventsFromPartitionedStream _fetcher; + + record State(StreamProcessorState ProcessorState) + { + public bool NoFailingEvents => ProcessorState.FailingPartitions.IsEmpty; + + public bool TryGetTimeToRetry(out TimeSpan timeToRetry, [NotNullWhen(true)] out PartitionId? selectedPartitionId) + { + timeToRetry = TimeSpan.MaxValue; + selectedPartitionId = default; + if (NoFailingEvents) return false; + + foreach (var (partitionId, failingPartitionState) in ProcessorState.FailingPartitions) + { + if (failingPartitionState.TryGetTimespanToRetry(out var partitionTimeToRetry) && partitionTimeToRetry < timeToRetry) + { + timeToRetry = partitionTimeToRetry; + selectedPartitionId = partitionId; + } + } + + return timeToRetry < TimeSpan.MaxValue; + } + } + + bool _catchingUp = true; + readonly ImmutableHashSet _handledTypes; + + + public PartitionedProcessor( + StreamProcessorId streamProcessorId, + IEnumerable handledEventTypes, + IEventProcessor processor, + IStreamProcessorStates streamProcessorStates, + ExecutionContext executionContext, + ScopedStreamProcessorProcessedEvent onProcessed, + ScopedStreamProcessorFailedToProcessEvent onFailedToProcess, + TenantId tenantId, + ICanFetchEventsFromPartitionedStream fetcher, + ILogger logger) + : + base( + streamProcessorId, processor, streamProcessorStates, executionContext, onProcessed, onFailedToProcess, tenantId, logger) + { + _fetcher = fetcher; + _handledTypes = handledEventTypes.Select(_ => _.Value).ToImmutableHashSet(); + } + + public async Task Process(ChannelReader messages, IStreamProcessorState state, CancellationToken cancellationToken, CancellationToken deadlineToken) + { + var currentState = new State(AsPartitioned(state)); + + while (!cancellationToken.IsCancellationRequested) + { + var (nextAction, partitionId) = await WaitForNextAction(messages, currentState, cancellationToken); + + try + { + switch (nextAction) + { + case NextAction.ProcessCatchUpEvent: + _ = await messages.ReadAsync(cancellationToken); + // Skip message, handled in the catch-up process + break; + case NextAction.ProcessNextEvent: + var evt = await messages.ReadAsync(cancellationToken); + currentState = await HandleNewEvent(evt, currentState, deadlineToken); + break; + case NextAction.ProcessFailedEvents: + currentState = await CatchUpForPartition(currentState, partitionId!, cancellationToken,deadlineToken); + break; + } + } + finally + { + await PersistNewState(currentState.ProcessorState, deadlineToken); + } + } + } + + enum NextAction + { + /// + /// Process the next event in the event stream. + /// + ProcessNextEvent, + + /// + /// Process an event from before the current position in the event stream. + /// Skips events in non failing partitions + /// + ProcessCatchUpEvent, + + /// + /// Retry processing of failed events. + /// + ProcessFailedEvents, + } + + /// + /// Determines which action to take next. + /// Either waits for new data to become available or for the retry delay to expire. + /// + /// + /// + /// + /// + /// + async ValueTask<(NextAction, PartitionId?)> WaitForNextAction(ChannelReader messages, State state, CancellationToken cancellationToken) + { + if (!state.TryGetTimeToRetry(out var timeToRetry, out var partitionId)) + { + return (await WaitForNextEvent(), default); + } + + if (timeToRetry <= TimeSpan.Zero) + { + return (NextAction.ProcessFailedEvents, partitionId); + } + + var retryFailureAfter = Task.Delay(timeToRetry, cancellationToken); + var readyToRead = messages.WaitToReadAsync(cancellationToken).AsTask(); + await Task.WhenAny(retryFailureAfter, readyToRead); + + if (retryFailureAfter.IsCompletedSuccessfully) + { + return (NextAction.ProcessFailedEvents, partitionId); + } + + return (await WaitForNextEvent(), default); + + async Task WaitForNextEvent() + { + var notClosed = await messages.WaitToReadAsync(cancellationToken); + if (notClosed) + { + if (_catchingUp && messages.TryPeek(out var evt)) + { + if (evt.Event.EventLogSequenceNumber < state.ProcessorState.Position.EventLogPosition) + { + return NextAction.ProcessCatchUpEvent; + } + + _catchingUp = false; + + return NextAction.ProcessNextEvent; + } + + return NextAction.ProcessNextEvent; + } + + throw new OperationCanceledException("Channel was closed"); + } + } + + async Task HandleNewEvent(StreamEvent evt, State state, CancellationToken deadlineToken) + { + if (state.ProcessorState.FailingPartitions.TryGetValue(evt.Partition, out _)) + { + return state with + { + ProcessorState = state.ProcessorState.WithResult(SkippedProcessing.Instance, evt, DateTimeOffset.UtcNow) + }; + } + + var (processorState, _) = await ProcessEventAndHandleResult(evt, state.ProcessorState, deadlineToken); + state = state with + { + ProcessorState = processorState + }; + + return state; + } + + StreamProcessorState AsPartitioned(IStreamProcessorState state) + { + switch (state) + { + case StreamProcessorState partitionedState: + return partitionedState; + + case Dolittle.Runtime.Events.Processing.Streams.StreamProcessorState nonPartitionedState: + if (!nonPartitionedState.IsFailing) + { + Logger.LogInformation("Converting non-partitioned state to partitioned for {StreamProcessorId}", Identifier); + return new StreamProcessorState(nonPartitionedState.Position, nonPartitionedState.LastSuccessfullyProcessed); + } + + throw new ArgumentException("State is not convertible to partitioned"); + + default: + throw new ArgumentException("State is of invalid type"); + } + } + + async Task CatchUpForPartition( + State state, + PartitionId partition, + CancellationToken cancellationToken, + CancellationToken deadlineToken) + { + var failingPartitionState = state.ProcessorState.FailingPartitions[partition]; + if (!ShouldRetryProcessing(failingPartitionState)) return state; // Should not really happen, since we explicitly wait for each partition + + var startPosition = new StreamPosition(failingPartitionState.Position.EventLogPosition.Value); + var highWatermark = new StreamPosition(state.ProcessorState.Position.EventLogPosition.Value); + + + var (events, hasMoreEvents) = await _fetcher.FetchInPartition(partition, startPosition, highWatermark, _handledTypes, cancellationToken); + foreach (var streamEvent in events) + { + if (cancellationToken.IsCancellationRequested) + { + return state; + } + var (newState, processingResult) = await RetryProcessingEventAndHandleResult( + streamEvent, + state.ProcessorState, + failingPartitionState.Reason, + failingPartitionState.ProcessingAttempts, + deadlineToken).ConfigureAwait(false); + await PersistNewState(newState, deadlineToken); + + state = state with + { + ProcessorState = newState + }; + + if (processingResult.Succeeded) + { + continue; + } + + // Failed, retry later + return state; + } + + if (hasMoreEvents) // No more events before the high water mark for this partition, remove it + { + state = state with { ProcessorState = state.ProcessorState.WithoutFailingPartition(partition) }; + await PersistNewState(state.ProcessorState, deadlineToken); + } + + return state; + } + + static bool ShouldRetryProcessing(FailingPartitionState state) => DateTimeOffset.UtcNow.CompareTo(state.RetryTime) >= 0; +} diff --git a/Source/Events/Processing/EventHandlers/Actors/ProcessorBase.cs b/Source/Events/Processing/EventHandlers/Actors/ProcessorBase.cs new file mode 100644 index 000000000..1b61c6b80 --- /dev/null +++ b/Source/Events/Processing/EventHandlers/Actors/ProcessorBase.cs @@ -0,0 +1,210 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Actors; +using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Events.Store.Streams.Filters; +using Microsoft.Extensions.Logging; +using Proto; +using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; + +namespace Dolittle.Runtime.Events.Processing.EventHandlers.Actors; + +/// +/// Represents the basis of system that can process a stream of events. +/// +public abstract class ProcessorBase where T : IStreamProcessorState +{ + readonly TenantId _tenantId; + readonly IEventProcessor _processor; + readonly ExecutionContext _executionContext; + readonly IStreamProcessorStates _streamProcessorStates; + readonly ScopedStreamProcessorProcessedEvent _onProcessed; + readonly ScopedStreamProcessorFailedToProcessEvent _onFailedToProcess; + + bool waitingForEvent; + + CancellationTokenSource? _stoppingToken; + bool retrying; + + /// + /// Initializes a new instance of the class. + /// + /// The . + /// The . + /// An to process the event. + /// + /// The of the stream processor. + /// + /// An to log messages. + /// + /// + /// + public ProcessorBase( + StreamProcessorId streamProcessorId, + IEventProcessor processor, + IStreamProcessorStates streamProcessorStates, + ExecutionContext executionContext, + ScopedStreamProcessorProcessedEvent onProcessed, + ScopedStreamProcessorFailedToProcessEvent onFailedToProcess, + TenantId tenantId, + ILogger logger) + { + Identifier = streamProcessorId; + _onProcessed = onProcessed; + _onFailedToProcess = onFailedToProcess; + _tenantId = tenantId; + Logger = logger; + _streamProcessorStates = streamProcessorStates; + _processor = processor; + _executionContext = executionContext; + } + + public static CreateTenantScopedStreamProcessorProps CreateFactory(ICreateProps createProps) + => (streamProcessorId, filterDefinition, processor, executionContext, onProcessed, onFailedToProcess, eventHandlerInfo, tenantId) => + PropsFor(createProps, streamProcessorId, filterDefinition, processor, executionContext, onProcessed, onFailedToProcess, eventHandlerInfo, tenantId); + + static Props PropsFor(ICreateProps createProps, + StreamProcessorId streamProcessorId, + TypeFilterWithEventSourcePartitionDefinition filterDefinition, + IEventProcessor processor, + ExecutionContext executionContext, + ScopedStreamProcessorProcessedEvent onProcessed, + ScopedStreamProcessorFailedToProcessEvent onFailedToProcess, + EventHandlerInfo eventHandlerInfo, + TenantId tenantId + ) + { + return createProps.PropsFor(streamProcessorId, filterDefinition, processor, executionContext, onProcessed, + onFailedToProcess, eventHandlerInfo, tenantId); + } + + /// + /// Gets the identifier for the . + /// + public StreamProcessorId Identifier { get; } + + /// + /// Gets the . + /// + protected ILogger Logger { get; } + + /// + /// Process the and get the new . + /// + /// The . + /// The current . + /// The . + /// A that, when returned, returns the new . + protected async Task<(T, IProcessingResult)> ProcessEventAndHandleResult(StreamEvent evt, T currentState, CancellationToken cancellationToken) + { + Logger.LogTrace("Processing event at position {ProcessingPosition}", evt.CurrentProcessingPosition); + var (processingResult, elapsed) = await ProcessEvent(evt, cancellationToken); + return (HandleProcessingResult(processingResult, evt, elapsed, currentState), processingResult); + } + + protected async Task<(IProcessingResult, TimeSpan)> ProcessEvent(StreamEvent evt, CancellationToken cancellationToken) + { + var before = Stopwatch.GetTimestamp(); + + var processingResult = await _processor.Process(evt.Event, evt.Partition, GetExecutionContextForEvent(evt), cancellationToken).ConfigureAwait(false); + var elapsed = Stopwatch.GetElapsedTime(before); + return (processingResult, elapsed); + } + + /// + /// Process the and get the new . + /// + /// The . + /// The current . + /// The . + /// A that, when returned, returns the new . + protected async Task<(T, IProcessingResult)> ProcessEventRetryAndHandleResult(StreamEvent evt, T currentState, CancellationToken cancellationToken) + { + Logger.LogTrace("Processing event at position {ProcessingPosition}", evt.CurrentProcessingPosition); + var (processingResult, elapsed) = await ProcessEvent(evt, cancellationToken); + return (HandleProcessingResult(processingResult, evt, elapsed, currentState), processingResult); + } + + protected async Task<(IProcessingResult, TimeSpan)> RetryProcessingEvent(StreamEvent evt, string failureReason, uint processingAttempts, + CancellationToken cancellationToken) + { + var before = Stopwatch.GetTimestamp(); + var processingResult = await _processor.Process( + evt.Event, evt.Partition, failureReason, processingAttempts - 1, GetExecutionContextForEvent(evt), cancellationToken).ConfigureAwait(false); + var elapsed = Stopwatch.GetElapsedTime(before); + return (processingResult, elapsed); + } + + /// + /// Process the and get the new . + /// + /// The . + /// The reason for why processing failed the last time. + /// The number of times that this event has been processed before. + /// The current . + /// The . + /// A that, when returned, returns the new . + protected async Task<(T, IProcessingResult)> RetryProcessingEventAndHandleResult(StreamEvent evt, T currentState, + string failureReason, + uint processingAttempts, + CancellationToken deadlineToken) + { + Logger.LogTrace("ReProcessing event at position {ProcessingPosition}", evt.CurrentProcessingPosition); + var (processingResult, elapsed) = await RetryProcessingEvent(evt, failureReason, processingAttempts, deadlineToken); + return (HandleProcessingResult(processingResult, evt, elapsed, currentState), processingResult); + } + + protected Task PersistNewState(T newState, CancellationToken deadlineToken) + { + return _streamProcessorStates.Persist(Identifier, newState, deadlineToken); + } + + /// + /// Handle the from the processing of a .. + /// + /// The . + /// The processed . + /// The time it took to process the event. + /// The current . + /// A that, when resolved, returns the new . + protected T HandleProcessingResult(IProcessingResult processingResult, StreamEvent processedEvent, TimeSpan processingTime, T currentState) + { + Logger.LogTrace("Result of {ProcessingPosition} in partition {Partition} is {ProcessingResult}", processedEvent.CurrentProcessingPosition, + processedEvent.Partition, + processingResult.GetType().Name); + var newState = currentState.WithResult(processingResult, processedEvent, DateTimeOffset.UtcNow); + OnProcessingResult(processingResult, processedEvent, processingTime); + return newState; + } + + void OnProcessingResult(IProcessingResult processingResult, StreamEvent processedEvent, TimeSpan processingTime) + { + if (processingResult.Succeeded) + { + _onProcessed.Invoke(processedEvent, processingTime); + } + else + { + _onFailedToProcess.Invoke(processedEvent, processingTime); + } + } + + /// + /// Gets the to use while processing the specified . + /// + /// The event to create the processing execution context for. + /// The to use while processing the event. + protected ExecutionContext GetExecutionContextForEvent(StreamEvent eventToProcess) + => _executionContext with + { + Tenant = _tenantId, + CorrelationId = eventToProcess.Event.ExecutionContext.CorrelationId, + }; +} diff --git a/Source/Events/Processing/EventHandlers/Actors/TenantScopedStreamProcessorActor.cs b/Source/Events/Processing/EventHandlers/Actors/TenantScopedStreamProcessorActor.cs new file mode 100644 index 000000000..514988e8a --- /dev/null +++ b/Source/Events/Processing/EventHandlers/Actors/TenantScopedStreamProcessorActor.cs @@ -0,0 +1,343 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Channels; +using System.Threading.Tasks; +using Dolittle.Runtime.Actors; +using Dolittle.Runtime.Actors.Hosting; +using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Events.Store.Streams.Filters; +using Dolittle.Runtime.Events.Store.Streams.Legacy; +using Dolittle.Runtime.Rudimentary; +using Microsoft.Extensions.Logging; +using Proto; +using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; +using StreamProcessorState = Dolittle.Runtime.Events.Processing.Streams.StreamProcessorState; + +namespace Dolittle.Runtime.Events.Processing.EventHandlers.Actors; + +public delegate Props CreateTenantScopedStreamProcessorProps(StreamProcessorId streamProcessorId, + TypeFilterWithEventSourcePartitionDefinition filterDefinition, + IEventProcessor processor, + ExecutionContext executionContext, + ScopedStreamProcessorProcessedEvent onProcessed, + ScopedStreamProcessorFailedToProcessEvent onFailedToProcess, + EventHandlerInfo eventHandlerInfo, + TenantId tenantId); + +/// +/// Represents the basis of system that can process a stream of events. +/// +public sealed class TenantScopedStreamProcessorActor : IActor, IDisposable +{ + readonly TenantId _tenantId; + readonly TypeFilterWithEventSourcePartitionDefinition _filterDefinition; + readonly IEventProcessor _processor; + readonly IStreamEventSubscriber _eventSubscriber; + readonly ExecutionContext _executionContext; + readonly IStreamProcessorStates _streamProcessorStates; + readonly IMapStreamPositionToEventLogPosition _eventLogPositionEnricher; + readonly ScopedStreamProcessorProcessedEvent _onProcessed; + readonly ScopedStreamProcessorFailedToProcessEvent _onFailedToProcess; + readonly IEventFetchers _eventFetchers; + readonly IApplicationLifecycleHooks _lifecycleHooks; + readonly List _cleanup = new(); + + readonly bool _partitioned; + readonly int _concurrency; + + static readonly TimeSpan _runtimeShutdownTimeout = TimeSpan.FromSeconds(30); + + /// + /// Initializes a new instance of the class. + /// + /// + /// The . + /// The . + /// + /// An to process the event. + /// + /// The of the stream processor. + /// + /// An to log messages. + /// + /// + /// + /// + /// + public TenantScopedStreamProcessorActor( + StreamProcessorId streamProcessorId, + TypeFilterWithEventSourcePartitionDefinition filterDefinition, + IEventProcessor processor, + IStreamEventSubscriber eventSubscriber, + IStreamProcessorStates streamProcessorStates, + ExecutionContext executionContext, + IMapStreamPositionToEventLogPosition eventLogPositionEnricher, + ILogger logger, + ScopedStreamProcessorProcessedEvent onProcessed, + ScopedStreamProcessorFailedToProcessEvent onFailedToProcess, + IEventFetchers eventFetchers, + EventHandlerInfo eventHandlerInfo, + TenantId tenantId, + IApplicationLifecycleHooks lifecycleHooks) + { + Identifier = streamProcessorId; + Logger = logger; + _onProcessed = onProcessed; + _onFailedToProcess = onFailedToProcess; + _tenantId = tenantId; + _lifecycleHooks = lifecycleHooks; + _eventFetchers = eventFetchers; + _eventLogPositionEnricher = eventLogPositionEnricher; + _eventSubscriber = eventSubscriber; + _streamProcessorStates = streamProcessorStates; + _filterDefinition = filterDefinition; + _processor = processor; + _executionContext = executionContext; + _partitioned = filterDefinition.Partitioned; + _concurrency = eventHandlerInfo.Concurrency; + } + + public static CreateTenantScopedStreamProcessorProps CreateFactory(ICreateProps createProps) + => (streamProcessorId, filterDefinition, processor, executionContext, onProcessed, onFailedToProcess, eventHandlerInfo, tenantId) => + PropsFor(createProps, streamProcessorId, filterDefinition, processor, executionContext, onProcessed, onFailedToProcess, eventHandlerInfo, tenantId); + + static Props PropsFor(ICreateProps createProps, + StreamProcessorId streamProcessorId, + TypeFilterWithEventSourcePartitionDefinition filterDefinition, + IEventProcessor processor, + ExecutionContext executionContext, + ScopedStreamProcessorProcessedEvent onProcessed, + ScopedStreamProcessorFailedToProcessEvent onFailedToProcess, + EventHandlerInfo eventHandlerInfo, + TenantId tenantId + ) + { + return createProps.PropsFor( + streamProcessorId, + filterDefinition, + processor, + executionContext, + onProcessed, + onFailedToProcess, + eventHandlerInfo, + tenantId); + } + + public async Task ReceiveAsync(IContext context) + { + try + { + switch (context.Message) + { + case Started: + await Init(context); + break; + } + } + catch (OperationCanceledException) + { + Logger.LogDebug("Cancelled processing of {Message}", context.Message); + } + catch (Exception e) + { + Logger.LogError(e, "Failed to process message {Message}", context.Message); + throw; + } + } + + + async Task Init(IContext context) + { + var processingPosition = await LoadProcessingPosition(context); + if (!processingPosition.Success) + { + Logger.LogError(processingPosition.Exception, "Failed to load processing position for {StreamProcessorId}", Identifier); + throw processingPosition.Exception; + } + + var initialState = processingPosition.Result; + + var from = initialState.Position; + + var (shutdownToken, deadlineToken) = GetCancellationTokens(context); + + var events = StartSubscription(from, shutdownToken); + var firstEventReady = events.WaitToReadAsync(shutdownToken).AsTask(); + context.ReenterAfter(firstEventReady, + _ => StartProcessing(initialState, events, context, shutdownToken, deadlineToken)); + } + + (CancellationToken shutdownToken, CancellationToken deadlineToken) GetCancellationTokens(IContext context) + { + var systemShutdownHook = _lifecycleHooks.RegisterShutdownHook(); + var shutdownAffectingTokens = new List + { + context.CancellationToken, + systemShutdownHook.SystemStoppingToken + }; + if (_processor.ShutdownToken is not null) + { + shutdownAffectingTokens.Add(_processor.ShutdownToken!.Value); + } + + var shutdownTokenSource = CancellationTokenSource.CreateLinkedTokenSource(shutdownAffectingTokens.ToArray()); + var deadlineTokenSource = _processor.DeadlineToken is not null + ? CancellationTokenSource.CreateLinkedTokenSource(_processor.DeadlineToken!.Value) + : new CancellationTokenSource(); + + var cancellationTokenRegistration = shutdownTokenSource.Token.Register(() => + { + if (_processor.ShutdownToken is null || !_processor.ShutdownToken.Value.IsCancellationRequested) + { + // If the source of the shutdown is not the processor itself, then we need to cancel the deadline token after a set delay + deadlineTokenSource.CancelAfter(_runtimeShutdownTimeout); + } + }); + + _cleanup.Add(systemShutdownHook); // Important to dispose this, otherwise the system will not shut down cleanly + _cleanup.Add(shutdownTokenSource); + _cleanup.Add(deadlineTokenSource); + _cleanup.Add(cancellationTokenRegistration); + + return (shutdownTokenSource.Token, deadlineTokenSource.Token); + } + + async Task StartProcessing(IStreamProcessorState streamProcessorState, ChannelReader events, IContext context, CancellationToken stoppingToken, + CancellationToken deadlineToken) + { + try + { + if (_concurrency > 1 && _partitioned) + { + var streamDefinition = new StreamDefinition(new FilterDefinition(SourceStream: StreamId.EventLog, StreamId.EventLog, Partitioned: true)); + var fetcher = await _eventFetchers.GetFetcherFor(Identifier.ScopeId, streamDefinition, stoppingToken); + + var processor = new ConcurrentPartitionedProcessor( + Identifier, + _filterDefinition.Types, + _processor, + _streamProcessorStates, + _executionContext, + _onProcessed, + _onFailedToProcess, + _tenantId, + (ICanFetchEventsFromPartitionedStream)fetcher, + _concurrency, + Logger); + + await processor.Process(events, streamProcessorState, stoppingToken, deadlineToken); + } + else if (_partitioned) + { + var streamDefinition = new StreamDefinition(new FilterDefinition(SourceStream: StreamId.EventLog, StreamId.EventLog, Partitioned: true)); + var fetcher = await _eventFetchers.GetFetcherFor(Identifier.ScopeId, streamDefinition, stoppingToken); + + var processor = new PartitionedProcessor( + Identifier, + _filterDefinition.Types, + _processor, + _streamProcessorStates, + _executionContext, + _onProcessed, + _onFailedToProcess, + _tenantId, + (ICanFetchEventsFromPartitionedStream)fetcher, + Logger); + + await processor.Process(events, streamProcessorState, stoppingToken, deadlineToken); + } + else + { + var processor = new NonPartitionedProcessor( + Identifier, + _filterDefinition, + _processor, + _streamProcessorStates, + _executionContext, + _onProcessed, + _onFailedToProcess, + _tenantId, + Logger); + + await processor.Process(events, streamProcessorState, stoppingToken, deadlineToken); + } + + Logger.EventHandlerDisconnectedForTenant(Identifier.EventProcessorId, Identifier.ScopeId, _tenantId); + } + catch (OperationCanceledException e) + { + Logger.CancelledRunningEventHandler(e, Identifier.EventProcessorId, Identifier.ScopeId); + } + catch (Exception e) + { + Logger.ErrorWhileRunningEventHandler(e, Identifier.EventProcessorId, Identifier.ScopeId); + } + finally + { + // ReSharper disable once MethodHasAsyncOverload + context.Stop(context.Self); + } + } + + ChannelReader StartSubscription(ProcessingPosition from, CancellationToken token) + { + return _eventSubscriber.Subscribe( + Identifier.ScopeId, + _filterDefinition.Types.ToList(), + from, + _filterDefinition.Partitioned, + $"sp:{Identifier.EventProcessorId}", + token); + } + + + /// + /// Loads processing position from storage, optionally enriching it with the event log position. + /// If no processing position is found, it will return a new with the initial position. + /// + /// + /// + async Task> LoadProcessingPosition(IContext context) + { + var position = await _streamProcessorStates.TryGetFor(Identifier, context.CancellationToken); + if (position is { Success: false, Exception: StreamProcessorStateDoesNotExist }) + { + return Try.Succeeded(new StreamProcessorState(ProcessingPosition.Initial, DateTimeOffset.UtcNow)); + } + + return await position.ReduceAsync(WithEventLogPosition); + + Task> WithEventLogPosition(IStreamProcessorState state) + { + return _eventLogPositionEnricher + .WithEventLogSequence(new StreamProcessorStateWithId(Identifier, state), context.CancellationToken); + } + } + + /// + /// Gets the identifier for the . + /// + public StreamProcessorId Identifier { get; } + + /// + /// Gets the . + /// + protected ILogger Logger { get; } + + public void Dispose() + { + foreach (var disposable in _cleanup) + { + disposable.Dispose(); + } + _cleanup.Clear(); + } +} diff --git a/Source/Events/Processing/EventHandlers/EventHandler.cs b/Source/Events/Processing/EventHandlers/EventHandler.cs new file mode 100644 index 000000000..50b9db4e7 --- /dev/null +++ b/Source/Events/Processing/EventHandlers/EventHandler.cs @@ -0,0 +1,352 @@ +// // Copyright (c) Dolittle. All rights reserved. +// // Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// using System; +// using System.Collections.Generic; +// using System.Linq; +// using System.Runtime.ExceptionServices; +// using System.Threading; +// using System.Threading.Tasks; +// using Dolittle.Runtime.Artifacts; +// using Dolittle.Runtime.Domain.Tenancy; +// using Dolittle.Runtime.Events.Processing.Filters; +// using Dolittle.Runtime.Events.Processing.Streams; +// using Dolittle.Runtime.Events.Store; +// using Dolittle.Runtime.Events.Store.Streams; +// using Dolittle.Runtime.Events.Store.Streams.Filters; +// using Dolittle.Runtime.Protobuf; +// using Dolittle.Runtime.Rudimentary; +// using Microsoft.Extensions.Logging; +// using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; +// +// namespace Dolittle.Runtime.Events.Processing.EventHandlers; +// +// /// +// /// Represents an event handler in the system. +// /// +// /// +// /// An event handler is a formalized type that consists of a filter and an event processor. +// /// The filter filters off of an event log based on the types of events the handler is interested in +// /// and puts these into a stream for the filter. From this new stream, the event processor will handle +// /// the forwarding to the client for it to handle the event. +// /// What sets an event handler apart is that it has a formalization around the stream definition that +// /// consists of the events it is interested in, which is defined from the client. +// /// +// public class EventHandler : IEventHandler +// { +// readonly IStreamProcessors _streamProcessors; +// readonly IValidateFilterForAllTenants _filterValidator; +// readonly IStreamDefinitions _streamDefinitions; +// readonly EventHandlerRegistrationArguments _arguments; +// readonly Func> _filterProcessorForTenant; +// readonly Func _eventProcessorForTenant; +// readonly Func _acceptRegistration; +// readonly Func _rejectRegistration; +// readonly IMetricsCollector _metrics; +// readonly ILogger _logger; +// readonly ExecutionContext _executionContext; +// readonly CancellationTokenSource _cancellationTokenSource; +// +// bool _disposed; +// +// /// +// /// Initializes a new instance of . +// /// +// /// The . +// /// The for validating the filter definition. +// /// The. +// /// Connecting arguments. +// /// +// /// The event processor. +// /// Accepts the event handler registration. +// /// Rejects the event handler registration. +// /// The collector to use for metrics. +// /// Logger for logging. +// /// The execution context for the event handler. +// /// Cancellation token that can cancel the hierarchy. +// public EventHandler( +// IStreamProcessors streamProcessors, +// IValidateFilterForAllTenants filterValidationForAllTenants, +// IStreamDefinitions streamDefinitions, +// EventHandlerRegistrationArguments arguments, +// Func> filterProcessorForTenant, +// Func eventProcessorForTenant, +// Func acceptRegistration, +// Func rejectRegistration, +// IMetricsCollector metrics, +// ILogger logger, +// ExecutionContext executionContext, +// CancellationToken cancellationToken) +// { +// _logger = logger; +// _streamProcessors = streamProcessors; +// _filterValidator = filterValidationForAllTenants; +// _streamDefinitions = streamDefinitions; +// _arguments = arguments; +// _filterProcessorForTenant = filterProcessorForTenant; +// _executionContext = executionContext; +// _eventProcessorForTenant = eventProcessorForTenant; +// _acceptRegistration = acceptRegistration; +// _rejectRegistration = rejectRegistration; +// _metrics = metrics; +// _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); +// } +// +// StreamId TargetStream => _arguments.EventHandler.Value; +// +// /// +// public EventHandlerInfo Info => new( +// new EventHandlerId(_arguments.Scope, _arguments.EventHandler), +// _arguments.HasAlias, +// _arguments.Alias, +// _arguments.EventTypes, +// _arguments.Partitioned); +// +// public ScopeId Scope => _arguments.Scope.Value; +// +// public EventProcessorId EventProcessor => _arguments.EventHandler.Value; +// +// public IEnumerable EventTypes => _arguments.EventTypes; +// +// public bool Partitioned => _arguments.Partitioned; +// +// public StreamDefinition FilteredStreamDefinition => new( +// new TypeFilterWithEventSourcePartitionDefinition( +// TargetStream, +// TargetStream, +// EventTypes, +// Partitioned)); +// +// public TypeFilterWithEventSourcePartitionDefinition FilterDefinition => new( +// StreamId.EventLog, +// TargetStream, +// EventTypes, +// Partitioned); +// +// StreamProcessor FilterStreamProcessor { get; set; } +// +// StreamProcessor EventProcessorStreamProcessor { get; set; } +// +// +// /// +// public Task> ReprocessEventsFrom(TenantId tenant, ProcessingPosition position) +// => EventProcessorStreamProcessor.SetToPosition(tenant, position); +// +// /// +// public async Task>>> ReprocessAllEvents() +// { +// try +// { +// return Try>>.Succeeded(await EventProcessorStreamProcessor.SetToInitialPositionForAllTenants().ConfigureAwait(false)); +// } +// catch (Exception ex) +// { +// return ex; +// } +// } +// +// /// +// public void Dispose() +// { +// Dispose(true); +// GC.SuppressFinalize(this); +// } +// +// /// +// /// Dispose managed and unmanaged resources. +// /// +// /// Whether to dispose managed resources. +// protected virtual void Dispose(bool disposing) +// { +// if (_disposed) +// { +// return; +// } +// if (disposing) +// { +// FilterStreamProcessor?.Dispose(); +// EventProcessorStreamProcessor?.Dispose(); +// _cancellationTokenSource.Dispose(); +// } +// +// _disposed = true; +// } +// +// /// +// public async Task RegisterAndStart() +// { +// _logger.ConnectingEventHandlerWithId(EventProcessor); +// if (await RejectIfNonWriteableStream().ConfigureAwait(false) +// || !await RegisterFilterStreamProcessor().ConfigureAwait(false) +// || !await RegisterEventProcessorStreamProcessor().ConfigureAwait(false)) +// { +// return; +// } +// +// await Start().ConfigureAwait(false); +// } +// +// /// +// public event EventHandlerRegistrationFailed? OnRegistrationFailed; +// +// async Task RejectIfNonWriteableStream() +// { +// if (!TargetStream.IsNonWriteable) +// { +// return false; +// } +// _logger.EventHandlerIsInvalid(EventProcessor); +// await Fail( +// EventHandlersFailures.CannotRegisterEventHandlerOnNonWriteableStream, +// $"Cannot register Event Handler: '{EventProcessor.Value}' because it is an invalid Stream Id").ConfigureAwait(false); +// +// return true; +// } +// +// async Task RegisterFilterStreamProcessor() +// { +// _logger.RegisteringStreamProcessorForFilter(EventProcessor); +// return await RegisterStreamProcessor( +// "EventHandler-Filter", +// new EventLogStreamDefinition(), +// _filterProcessorForTenant, +// HandleFailedToRegisterFilter, +// (streamProcessor) => FilterStreamProcessor = streamProcessor +// ).ConfigureAwait(false); +// } +// +// Failure HandleFailedToRegisterFilter(Exception exception) +// { +// _logger.ErrorWhileRegisteringStreamProcessorForFilter(exception, EventProcessor); +// +// if (exception is StreamProcessorAlreadyRegistered) +// { +// _logger.EventHandlerAlreadyRegistered(EventProcessor); +// return new Failure( +// EventHandlersFailures.FailedToRegisterEventHandler, +// $"Failed to register Event Handler: {EventProcessor.Value}. Filter already registered"); +// } +// return new Failure( +// EventHandlersFailures.FailedToRegisterEventHandler, +// $"Failed to register Event Handler: {EventProcessor.Value}. An error occurred. {exception.Message}"); +// } +// +// async Task RegisterEventProcessorStreamProcessor() +// { +// _logger.RegisteringStreamProcessorForEventProcessor(EventProcessor, TargetStream); +// return await RegisterStreamProcessor( +// "EventHandler-EventProcessor", +// FilteredStreamDefinition, +// _eventProcessorForTenant, +// HandleFailedToRegisterEventProcessor, +// (streamProcessor) => +// { +// EventProcessorStreamProcessor = streamProcessor; +// streamProcessor.OnProcessedEvent += (tenant, @event, time) => +// { +// _metrics.IncrementEventsProcessedTotal(Info, tenant, @event, time); +// }; +// streamProcessor.OnFailedToProcessedEvent += (tenant, @event, time) => +// { +// _metrics.IncrementEventsProcessedTotal(Info, tenant, @event, time); +// _metrics.IncrementEventProcessingFailuresTotal(Info, tenant, @event); +// }; +// }).ConfigureAwait(false); +// } +// +// Failure HandleFailedToRegisterEventProcessor(Exception exception) +// { +// _logger.ErrorWhileRegisteringStreamProcessorForEventProcessor(exception, EventProcessor); +// +// if (exception is not StreamProcessorAlreadyRegistered) +// { +// return new Failure( +// EventHandlersFailures.FailedToRegisterEventHandler, +// $"Failed to register Event Handler: {EventProcessor.Value}. An error occurred. {exception.Message}"); +// } +// +// _logger.EventHandlerAlreadyRegisteredOnSourceStream(EventProcessor); +// return new Failure( +// EventHandlersFailures.FailedToRegisterEventHandler, +// $"Failed to register Event Handler: {EventProcessor.Value}. Event Processor already registered on Source Stream: '{EventProcessor.Value}'"); +// } +// +// async Task RegisterStreamProcessor( +// EventProcessorKind kind, +// IStreamDefinition streamDefinition, +// Func getProcessor, +// Func onException, +// Action onStreamProcessor) +// { +// var streamProcessor = _streamProcessors.TryCreateAndRegister( +// Scope, +// EventProcessor, +// kind, +// streamDefinition, +// getProcessor, +// _executionContext, +// _cancellationTokenSource.Token); +// +// onStreamProcessor(streamProcessor); +// +// if (!streamProcessor.Success) +// { +// await Fail(onException(streamProcessor.Exception)).ConfigureAwait(false); +// } +// +// return streamProcessor.Success; +// } +// +// async Task Start() +// { +// _logger.StartingEventHandler(FilterDefinition.TargetStream); +// try +// { +// var runningDispatcher = _acceptRegistration(_cancellationTokenSource.Token); +// await FilterStreamProcessor.Initialize().ConfigureAwait(false); +// await EventProcessorStreamProcessor.Initialize().ConfigureAwait(false); +// await ValidateFilter().ConfigureAwait(false); +// +// var tasks = new TaskGroup(FilterStreamProcessor.Start(), EventProcessorStreamProcessor.Start(), runningDispatcher); +// +// tasks.OnFirstTaskFailure += (_, ex) => _logger.ErrorWhileRunningEventHandler(ex, EventProcessor, Scope); +// tasks.OnAllTasksCompleted += () => _logger.EventHandlerDisconnected(EventProcessor, Scope); +// +// await tasks.WaitForAllCancellingOnFirst(_cancellationTokenSource).ConfigureAwait(false); +// } +// catch (Exception ex) +// { +// if (!_cancellationTokenSource.Token.IsCancellationRequested) +// { +// _logger.ErrorWhileStartingEventHandler(ex, EventProcessor, Scope); +// } +// ExceptionDispatchInfo.Capture(ex).Throw(); +// } +// } +// +// async Task ValidateFilter() +// { +// _logger.ValidatingFilter(FilterDefinition.TargetStream); +// var filterValidationResults = await _filterValidator.Validate(_filterProcessorForTenant, _cancellationTokenSource.Token).ConfigureAwait(false); +// +// if (filterValidationResults.Any(_ => !_.Value.Success)) +// { +// var firstFailedValidation = filterValidationResults.First(_ => !_.Value.Success).Value; +// _logger.FilterValidationFailed(FilterDefinition.TargetStream, firstFailedValidation.FailureReason); +// throw new FilterValidationFailed(FilterDefinition.TargetStream, firstFailedValidation.FailureReason); +// } +// +// var filteredStreamDefinition = new StreamDefinition(FilterDefinition); +// _logger.PersistingStreamDefinition(filteredStreamDefinition.StreamId); +// await _streamDefinitions.Persist(Scope, filteredStreamDefinition, _cancellationTokenSource.Token).ConfigureAwait(false); +// } +// +// Task Fail(FailureId failureId, string message) +// => Fail(new Failure(failureId, message)); +// +// Task Fail(Failure failure) +// { +// OnRegistrationFailed?.Invoke(); +// return _rejectRegistration(failure, _cancellationTokenSource.Token); +// } +// } diff --git a/Source/Events.Processing/EventHandlers/EventHandlerAlias.cs b/Source/Events/Processing/EventHandlers/EventHandlerAlias.cs similarity index 100% rename from Source/Events.Processing/EventHandlers/EventHandlerAlias.cs rename to Source/Events/Processing/EventHandlers/EventHandlerAlias.cs diff --git a/Source/Events.Processing/EventHandlers/EventHandlerAlreadyRegistered.cs b/Source/Events/Processing/EventHandlers/EventHandlerAlreadyRegistered.cs similarity index 100% rename from Source/Events.Processing/EventHandlers/EventHandlerAlreadyRegistered.cs rename to Source/Events/Processing/EventHandlers/EventHandlerAlreadyRegistered.cs diff --git a/Source/Events/Processing/EventHandlers/EventHandlerFactory.cs b/Source/Events/Processing/EventHandlers/EventHandlerFactory.cs new file mode 100644 index 000000000..5a629a801 --- /dev/null +++ b/Source/Events/Processing/EventHandlers/EventHandlerFactory.cs @@ -0,0 +1,81 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using Dolittle.Runtime.Actors.Hosting; +using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Processing.Contracts; +using Dolittle.Runtime.Events.Processing.EventHandlers.Actors; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Protobuf; +using Dolittle.Runtime.Tenancy; +using Microsoft.Extensions.Logging; +using Proto; +using ReverseCallDispatcher = Dolittle.Runtime.Services.IReverseCallDispatcher< + Dolittle.Runtime.Events.Processing.Contracts.EventHandlerClientToRuntimeMessage, + Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRuntimeToClientMessage, + Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRegistrationRequest, + Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRegistrationResponse, + Dolittle.Runtime.Events.Processing.Contracts.HandleEventRequest, + Dolittle.Runtime.Events.Processing.Contracts.EventHandlerResponse>; + + +namespace Dolittle.Runtime.Events.Processing.EventHandlers; + +/// +/// Represents an implementation of . +/// +public class EventHandlerFactory : IEventHandlerFactory +{ + readonly CreateStreamProcessorActorProps _createStreamProcessorActorProps; + readonly IStreamDefinitions _streamDefinitions; + readonly IMetricsCollector _metrics; + readonly ILoggerFactory _loggerFactory; + readonly ITenants _tenants; + readonly ActorSystem _actorSystem; + + /// + /// Initializes a new instance of the class. + /// + /// The . + /// The collector to use for metrics. + /// The . + /// The . + /// + /// Create Actor props for stream processor actor + public EventHandlerFactory( + IStreamDefinitions streamDefinitions, + IMetricsCollector metrics, + ILoggerFactory loggerFactory, + ITenants tenants, + ActorSystem actorSystem, CreateStreamProcessorActorProps createStreamProcessorActorProps, IApplicationLifecycleHooks lifecycleHooks) + { + _streamDefinitions = streamDefinitions; + _metrics = metrics; + _loggerFactory = loggerFactory; + _tenants = tenants; + _actorSystem = actorSystem; + _createStreamProcessorActorProps = createStreamProcessorActorProps; + } + + /// + public IEventHandler Create(EventHandlerRegistrationArguments arguments, ReverseCallDispatcher dispatcher, CancellationToken cancellationToken) + { + EventProcessor Converter(TenantId _) => new(arguments.Scope, arguments.EventHandler, dispatcher, _loggerFactory.CreateLogger()); + return new ActorEventHandler(_streamDefinitions, + arguments, + Converter, + cancellation => dispatcher.Accept(new EventHandlerRegistrationResponse(), cancellation), + (failure, cancellation) => dispatcher.Reject(new EventHandlerRegistrationResponse { Failure = failure.ToProtobuf() }, cancellation), + _metrics, + _loggerFactory.CreateLogger(), + arguments.ExecutionContext, + _actorSystem, + _tenants, + _createStreamProcessorActorProps, + cancellationToken + ); + } + +} diff --git a/Source/Events.Processing/EventHandlers/EventHandlerId.cs b/Source/Events/Processing/EventHandlers/EventHandlerId.cs similarity index 100% rename from Source/Events.Processing/EventHandlers/EventHandlerId.cs rename to Source/Events/Processing/EventHandlers/EventHandlerId.cs diff --git a/Source/Events.Processing/EventHandlers/EventHandlerInfo.cs b/Source/Events/Processing/EventHandlers/EventHandlerInfo.cs similarity index 87% rename from Source/Events.Processing/EventHandlers/EventHandlerInfo.cs rename to Source/Events/Processing/EventHandlers/EventHandlerInfo.cs index aaa034ae1..2ae3cbde4 100644 --- a/Source/Events.Processing/EventHandlers/EventHandlerInfo.cs +++ b/Source/Events/Processing/EventHandlers/EventHandlerInfo.cs @@ -14,4 +14,5 @@ namespace Dolittle.Runtime.Events.Processing.EventHandlers; /// The alias of the Event Handler. /// The Event types that the Event Handler handles.. /// Whether the Event Handler is partitioned. -public record EventHandlerInfo(EventHandlerId Id, bool HasAlias, EventHandlerAlias Alias, IEnumerable EventTypes, bool Partitioned); \ No newline at end of file +/// How many events the handler can process simultaneously. +public record EventHandlerInfo(EventHandlerId Id, bool HasAlias, EventHandlerAlias Alias, IEnumerable EventTypes, bool Partitioned, int Concurrency); \ No newline at end of file diff --git a/Source/Events.Processing/EventHandlers/EventHandlerNotRegistered.cs b/Source/Events/Processing/EventHandlers/EventHandlerNotRegistered.cs similarity index 100% rename from Source/Events.Processing/EventHandlers/EventHandlerNotRegistered.cs rename to Source/Events/Processing/EventHandlers/EventHandlerNotRegistered.cs diff --git a/Source/Events.Processing/EventHandlers/EventHandlerRegistrationArguments.cs b/Source/Events/Processing/EventHandlers/EventHandlerRegistrationArguments.cs similarity index 84% rename from Source/Events.Processing/EventHandlers/EventHandlerRegistrationArguments.cs rename to Source/Events/Processing/EventHandlers/EventHandlerRegistrationArguments.cs index 477b6650f..c87751327 100644 --- a/Source/Events.Processing/EventHandlers/EventHandlerRegistrationArguments.cs +++ b/Source/Events/Processing/EventHandlers/EventHandlerRegistrationArguments.cs @@ -21,7 +21,9 @@ public record EventHandlerRegistrationArguments /// The Event types that the Event Handler handles. /// Whether the Event Handler is partitioned or unpartitioned. /// The Scope the Event Handler will be handling events in. - public EventHandlerRegistrationArguments(ExecutionContext executionContext, EventProcessorId eventHandler, IEnumerable eventTypes, bool partitioned, ScopeId scope) + /// How many concurrent calls the Event Handler can process simultaneously + public EventHandlerRegistrationArguments(ExecutionContext executionContext, EventProcessorId eventHandler, IEnumerable eventTypes, + bool partitioned, ScopeId scope, int concurrency) { ExecutionContext = executionContext; EventHandler = eventHandler; @@ -30,6 +32,7 @@ public EventHandlerRegistrationArguments(ExecutionContext executionContext, Even Scope = scope; Alias = EventHandlerAlias.NotSet; HasAlias = false; + Concurrency = concurrency > 0 ? concurrency : 1; } /// @@ -41,7 +44,9 @@ public EventHandlerRegistrationArguments(ExecutionContext executionContext, Even /// Whether the Event Handler is partitioned or unpartitioned. /// The Scope the Event Handler will be handling events in. /// The alias of the Event Handler. - public EventHandlerRegistrationArguments(ExecutionContext executionContext, EventProcessorId eventHandler, IEnumerable eventTypes, bool partitioned, ScopeId scope, EventHandlerAlias alias) + /// How many concurrent calls the Event Handler can process simultaneously + public EventHandlerRegistrationArguments(ExecutionContext executionContext, EventProcessorId eventHandler, IEnumerable eventTypes, + bool partitioned, ScopeId scope, EventHandlerAlias alias, int concurrency = 1) { ExecutionContext = executionContext; EventHandler = eventHandler; @@ -49,41 +54,47 @@ public EventHandlerRegistrationArguments(ExecutionContext executionContext, Even Partitioned = partitioned; Scope = scope; Alias = alias; + Concurrency = concurrency > 0 ? concurrency : 1; HasAlias = true; } + /// + /// How many concurrent calls the Event Handler can process simultaneously. + /// + public int Concurrency { get; set; } + /// /// Gets the ExecutionContext of the Client while registering. /// public ExecutionContext ExecutionContext { get; } - + /// /// Gets the identifier of the Event Handler. /// public EventProcessorId EventHandler { get; } - + /// /// Gets the Event types that the Event Handler handles. /// public IEnumerable EventTypes { get; } - + /// /// Gets a value indicating whether the Event Handler is partitioned or unpartitioned. /// public bool Partitioned { get; } - + /// /// Gets the Scope the Event Handler will be handling events in. /// public ScopeId Scope { get; } - + /// /// Gets the alias of the Event Handler if set, or if not passed from the Client. /// public EventHandlerAlias Alias { get; } - + /// /// Gets a value indicating whether or not the Client passed along an alias for the Event Handler. /// public bool HasAlias { get; } -} \ No newline at end of file +} diff --git a/Source/Events.Processing/EventHandlers/EventHandlerRegistrationFailed.cs b/Source/Events/Processing/EventHandlers/EventHandlerRegistrationFailed.cs similarity index 100% rename from Source/Events.Processing/EventHandlers/EventHandlerRegistrationFailed.cs rename to Source/Events/Processing/EventHandlers/EventHandlerRegistrationFailed.cs diff --git a/Source/Events.Processing/EventHandlers/EventHandlers.cs b/Source/Events/Processing/EventHandlers/EventHandlers.cs similarity index 78% rename from Source/Events.Processing/EventHandlers/EventHandlers.cs rename to Source/Events/Processing/EventHandlers/EventHandlers.cs index ba5d4d7ef..4f6f2b9b1 100644 --- a/Source/Events.Processing/EventHandlers/EventHandlers.cs +++ b/Source/Events/Processing/EventHandlers/EventHandlers.cs @@ -42,9 +42,9 @@ public EventHandlers(IMetricsCollector metrics, ILogger logger) public IEnumerable All => _eventHandlers.Select(_ => _.Value.Info); /// - public Try> CurrentStateFor(EventHandlerId eventHandlerId) + public async Task>> CurrentStateFor(EventHandlerId eventHandlerId) => _eventHandlers.TryGetValue(eventHandlerId, out var eventHandler) - ? eventHandler.GetEventHandlerCurrentState() + ? await eventHandler.GetEventHandlerCurrentState() : new EventHandlerNotRegistered(eventHandlerId); /// @@ -64,25 +64,25 @@ public async Task RegisterAndStart(IEventHandler eventHandler, Func - public Task> ReprocessEventsFrom(EventHandlerId eventHandlerId, TenantId tenant, StreamPosition position) + public Task> ReprocessEventsFrom(EventHandlerId eventHandlerId, TenantId tenant, ProcessingPosition position) => _eventHandlers.TryGetValue(eventHandlerId, out var eventHandler) ? eventHandler.ReprocessEventsFrom(tenant, position) - : Task.FromResult>(new EventHandlerNotRegistered(eventHandlerId)); + : Task.FromResult>(new EventHandlerNotRegistered(eventHandlerId)); /// - public Task>>> ReprocessAllEvents(EventHandlerId eventHandlerId) + public Task>>> ReprocessAllEvents(EventHandlerId eventHandlerId) => _eventHandlers.TryGetValue(eventHandlerId, out var eventHandler) ? eventHandler.ReprocessAllEvents() - : Task.FromResult>>>(new EventHandlerNotRegistered(eventHandlerId)); + : Task.FromResult>>>(new EventHandlerNotRegistered(eventHandlerId)); } diff --git a/Source/Events.Processing/EventHandlers/EventHandlersConfiguration.cs b/Source/Events/Processing/EventHandlers/EventHandlersConfiguration.cs similarity index 100% rename from Source/Events.Processing/EventHandlers/EventHandlersConfiguration.cs rename to Source/Events/Processing/EventHandlers/EventHandlersConfiguration.cs diff --git a/Source/Events.Processing/EventHandlers/EventHandlersFailures.cs b/Source/Events/Processing/EventHandlers/EventHandlersFailures.cs similarity index 100% rename from Source/Events.Processing/EventHandlers/EventHandlersFailures.cs rename to Source/Events/Processing/EventHandlers/EventHandlersFailures.cs diff --git a/Source/Events.Processing/EventHandlers/EventHandlersProtocol.cs b/Source/Events/Processing/EventHandlers/EventHandlersProtocol.cs similarity index 76% rename from Source/Events.Processing/EventHandlers/EventHandlersProtocol.cs rename to Source/Events/Processing/EventHandlers/EventHandlersProtocol.cs index 1ad3a38e6..36b4d3a1e 100644 --- a/Source/Events.Processing/EventHandlers/EventHandlersProtocol.cs +++ b/Source/Events/Processing/EventHandlers/EventHandlersProtocol.cs @@ -7,6 +7,7 @@ using Dolittle.Runtime.Protobuf; using Dolittle.Runtime.Services; using Dolittle.Services.Contracts; +using InitiateDisconnect = Dolittle.Runtime.Services.InitiateDisconnect; namespace Dolittle.Runtime.Events.Processing.EventHandlers; @@ -25,18 +26,24 @@ public EventHandlerRegistrationArguments ConvertConnectArguments(EventHandlerReg arguments.EventTypes.Select(_ => new ArtifactId(_.Id.ToGuid())), arguments.Partitioned, arguments.ScopeId.ToGuid(), - arguments.Alias), + arguments.Alias, + arguments.Concurrency), false => new EventHandlerRegistrationArguments( arguments.CallContext.ExecutionContext.ToExecutionContext(), arguments.EventHandlerId.ToGuid(), arguments.EventTypes.Select(_ => new ArtifactId(_.Id.ToGuid())), arguments.Partitioned, - arguments.ScopeId.ToGuid()), + arguments.ScopeId.ToGuid(), + arguments.Concurrency), }; /// public EventHandlerRegistrationResponse CreateFailedConnectResponse(FailureReason failureMessage) - => new() { Failure = new Dolittle.Protobuf.Contracts.Failure { Id = EventHandlersFailures.FailedToRegisterEventHandler.Value.ToProtobuf(), Reason = failureMessage } }; + => new() + { + Failure = new Dolittle.Protobuf.Contracts.Failure + { Id = EventHandlersFailures.FailedToRegisterEventHandler.Value.ToProtobuf(), Reason = failureMessage } + }; /// public ReverseCallArgumentsContext GetArgumentsContext(EventHandlerRegistrationRequest message) @@ -74,7 +81,24 @@ public void SetRequest(HandleEventRequest request, EventHandlerRuntimeToClientMe public void SetRequestContext(ReverseCallRequestContext context, HandleEventRequest request) => request.CallContext = context; + public bool SupportsGracefulShutdown => true; + + public InitiateDisconnect? GetInitiateDisconnect(EventHandlerClientToRuntimeMessage message) + { + if (message.MessageCase != EventHandlerClientToRuntimeMessage.MessageOneofCase.InitiateDisconnect) + { + return null; + } + + var gracePeriod = message.InitiateDisconnect.GracePeriod?.ToTimeSpan(); + + return new InitiateDisconnect + { + GracePeriod = gracePeriod + }; + } + /// public ConnectArgumentsValidationResult ValidateConnectArguments(EventHandlerRegistrationArguments arguments) => ConnectArgumentsValidationResult.Ok; -} \ No newline at end of file +} diff --git a/Source/Events.Processing/EventHandlers/EventHandlersService.cs b/Source/Events/Processing/EventHandlers/EventHandlersService.cs similarity index 92% rename from Source/Events.Processing/EventHandlers/EventHandlersService.cs rename to Source/Events/Processing/EventHandlers/EventHandlersService.cs index 978066857..8196b191d 100644 --- a/Source/Events.Processing/EventHandlers/EventHandlersService.cs +++ b/Source/Events/Processing/EventHandlers/EventHandlersService.cs @@ -76,9 +76,7 @@ public override async Task Connect( using var dispatcher = connectResult.Result.dispatcher; var arguments = connectResult.Result.arguments; - using var eventHandler = _configuration.Value.Fast - ? _eventHandlerFactory.CreateFast(arguments, _configuration.Value.ImplicitFilter, dispatcher, context.CancellationToken) - : _eventHandlerFactory.Create(arguments, dispatcher, context.CancellationToken); + using var eventHandler = _eventHandlerFactory.Create(arguments, dispatcher, context.CancellationToken); await _eventHandlers.RegisterAndStart( eventHandler, diff --git a/Source/Events.Processing/EventHandlers/EventProcessor.cs b/Source/Events/Processing/EventHandlers/EventProcessor.cs similarity index 95% rename from Source/Events.Processing/EventHandlers/EventProcessor.cs rename to Source/Events/Processing/EventHandlers/EventProcessor.cs index f1326fac4..41f5182d8 100644 --- a/Source/Events.Processing/EventHandlers/EventProcessor.cs +++ b/Source/Events/Processing/EventHandlers/EventProcessor.cs @@ -49,6 +49,10 @@ public EventProcessor(ScopeId scope, EventProcessorId id, ReverseCallDispatcherT /// public EventProcessorId Identifier { get; } + public CancellationToken? ShutdownToken => _dispatcher.ShutdownToken; + + public CancellationToken? DeadlineToken => _dispatcher.DeadlineToken; + /// public Task Process(CommittedEvent @event, PartitionId partitionId, ExecutionContext executionContext, CancellationToken cancellationToken) { @@ -79,7 +83,7 @@ async Task Process(HandleEventRequest request, ExecutionConte return response switch { - { Failure: null } => new SuccessfulProcessing(), + { Failure: null } => SuccessfulProcessing.Instance, _ => new FailedProcessing(response.Failure.Reason, response.Failure.Retry, response.Failure.RetryTimeout?.ToTimeSpan() ?? TimeSpan.MaxValue) }; } diff --git a/Source/Events.Processing/EventHandlers/IEventHandler.cs b/Source/Events/Processing/EventHandlers/IEventHandler.cs similarity index 84% rename from Source/Events.Processing/EventHandlers/IEventHandler.cs rename to Source/Events/Processing/EventHandlers/IEventHandler.cs index 9ae20a748..fe069113b 100644 --- a/Source/Events.Processing/EventHandlers/IEventHandler.cs +++ b/Source/Events/Processing/EventHandlers/IEventHandler.cs @@ -21,7 +21,7 @@ public interface IEventHandler : IDisposable /// Gets the current state of the Event Handler. /// /// The per . - Try> GetEventHandlerCurrentState(); + Task>> GetEventHandlerCurrentState(); /// /// Reprocesses all events from a for a tenant. @@ -29,13 +29,13 @@ public interface IEventHandler : IDisposable /// The . /// The . /// The that, when resolved, returns a with the it was set to. - Task> ReprocessEventsFrom(TenantId tenant, StreamPosition position); + Task> ReprocessEventsFrom(TenantId tenant, ProcessingPosition position); /// /// Reprocesses all the events for all tenants. /// /// The that, when resolved, returns a with a with the it was set to for each . - Task>>> ReprocessAllEvents(); + Task>>> ReprocessAllEvents(); /// /// Register and start the event handler for filtering and processing. @@ -46,5 +46,5 @@ public interface IEventHandler : IDisposable /// /// Event that occurs if the EventHandler registration fails. /// - event EventHandlerRegistrationFailed OnRegistrationFailed; + // event EventHandlerRegistrationFailed OnRegistrationFailed; } diff --git a/Source/Events.Processing/EventHandlers/IEventHandlerFactory.cs b/Source/Events/Processing/EventHandlers/IEventHandlerFactory.cs similarity index 69% rename from Source/Events.Processing/EventHandlers/IEventHandlerFactory.cs rename to Source/Events/Processing/EventHandlers/IEventHandlerFactory.cs index 537a0286b..0b1646077 100644 --- a/Source/Events.Processing/EventHandlers/IEventHandlerFactory.cs +++ b/Source/Events/Processing/EventHandlers/IEventHandlerFactory.cs @@ -25,14 +25,4 @@ public interface IEventHandlerFactory /// The . /// The . IEventHandler Create(EventHandlerRegistrationArguments arguments, ReverseCallDispatcher dispatcher, CancellationToken cancellationToken); - - /// - /// Creates an . - /// - /// The . - /// Whether filtering is implicit. - /// The . - /// The . - /// The . - FastEventHandler CreateFast(EventHandlerRegistrationArguments arguments, bool implicitFilter, ReverseCallDispatcher dispatcher, CancellationToken cancellationToken); } diff --git a/Source/Events.Processing/EventHandlers/IEventHandlers.cs b/Source/Events/Processing/EventHandlers/IEventHandlers.cs similarity index 88% rename from Source/Events.Processing/EventHandlers/IEventHandlers.cs rename to Source/Events/Processing/EventHandlers/IEventHandlers.cs index eee42f318..103071b81 100644 --- a/Source/Events.Processing/EventHandlers/IEventHandlers.cs +++ b/Source/Events/Processing/EventHandlers/IEventHandlers.cs @@ -26,7 +26,7 @@ public interface IEventHandlers /// /// The . /// The current states of the Event Handler. - Try> CurrentStateFor(EventHandlerId eventHandlerId); + Task>> CurrentStateFor(EventHandlerId eventHandlerId); /// /// Registers and starts an Event Handler for all tenants. @@ -44,13 +44,13 @@ public interface IEventHandlers /// The . /// The . /// The that, when resolved, returns a with the it was set to. - Task> ReprocessEventsFrom(EventHandlerId eventHandlerId, TenantId tenant, StreamPosition position); + Task> ReprocessEventsFrom(EventHandlerId eventHandlerId, TenantId tenant, ProcessingPosition position); /// /// Reprocesses all the events for an event handler for all tenants. /// /// The of the identifying the event handler. /// The that, when resolved, returns a with a with the it was set to for each . - Task>>> ReprocessAllEvents(EventHandlerId eventHandlerId); + Task>>> ReprocessAllEvents(EventHandlerId eventHandlerId); } diff --git a/Source/Events.Processing/EventHandlers/IEventHandlersProtocol.cs b/Source/Events/Processing/EventHandlers/IEventHandlersProtocol.cs similarity index 100% rename from Source/Events.Processing/EventHandlers/IEventHandlersProtocol.cs rename to Source/Events/Processing/EventHandlers/IEventHandlersProtocol.cs diff --git a/Source/Events.Processing/EventHandlers/IMetricsCollector.cs b/Source/Events/Processing/EventHandlers/IMetricsCollector.cs similarity index 100% rename from Source/Events.Processing/EventHandlers/IMetricsCollector.cs rename to Source/Events/Processing/EventHandlers/IMetricsCollector.cs diff --git a/Source/Events.Processing/EventHandlers/Log.cs b/Source/Events/Processing/EventHandlers/Log.cs similarity index 100% rename from Source/Events.Processing/EventHandlers/Log.cs rename to Source/Events/Processing/EventHandlers/Log.cs diff --git a/Source/Events.Processing/EventHandlers/LoggerExtensions.cs b/Source/Events/Processing/EventHandlers/LoggerExtensions.cs similarity index 81% rename from Source/Events.Processing/EventHandlers/LoggerExtensions.cs rename to Source/Events/Processing/EventHandlers/LoggerExtensions.cs index b9eb2e799..84e8569c3 100644 --- a/Source/Events.Processing/EventHandlers/LoggerExtensions.cs +++ b/Source/Events/Processing/EventHandlers/LoggerExtensions.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using Dolittle.Runtime.Artifacts; +using Dolittle.Runtime.Domain.Tenancy; using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; using Microsoft.Extensions.Logging; @@ -14,7 +15,7 @@ namespace Dolittle.Runtime.Events.Processing.EventHandlers; /// /// Represents a extensions for . /// -static class LoggerExtensions +static partial class LoggerExtensions { static readonly Action _receivedEventHandler = LoggerMessage .Define( @@ -64,16 +65,10 @@ static class LoggerExtensions new EventId(860866540, nameof(CouldNotStartEventHandler)), "Could not start event handler: {EventHandler} in scope: {Scope}"); - static readonly Action _errorWhileRunningEventHandler = LoggerMessage - .Define( - LogLevel.Warning, - new EventId(331030466, nameof(ErrorWhileRunningEventHandler)), - "An error occurred while running event handler: {EventHandler} in scope: {Scope}"); - static readonly Action _eventHandlerDisconnected = LoggerMessage .Define( - LogLevel.Debug, - new EventId(414482081, nameof(EventHandlerDisconnected)), + LogLevel.Information, + new EventId(414482081, nameof(EventHandlerDisconnectedForTenant)), "Event handler: {EventHandler} in scope: {Scope} disconnected"); static readonly Action _startingEventHandler = LoggerMessage @@ -118,7 +113,8 @@ static class LoggerExtensions new EventId(250914604, nameof(EventProcessorIsProcessingAgain)), "Event processor: {EventProcessor} is processing event type: {EventTypeId} for partition: {PartitionId} again for the {RetryCount} time, because of: {FailureReason}"); - internal static void ReceivedEventHandler(this ILogger logger, StreamId sourceStream, EventProcessorId handler, ScopeId scope, IEnumerable types, bool partitioned) + internal static void ReceivedEventHandler(this ILogger logger, StreamId sourceStream, EventProcessorId handler, ScopeId scope, + IEnumerable types, bool partitioned) => _receivedEventHandler(logger, sourceStream, handler, scope, string.Join(", ", types.Select(_ => $"'{_.Value}'")), partitioned, null); internal static void EventHandlerIsInvalid(this ILogger logger, EventProcessorId handler) @@ -145,9 +141,28 @@ internal static void ErrorWhileStartingEventHandler(this ILogger logger, Excepti internal static void CouldNotStartEventHandler(this ILogger logger, EventProcessorId handlerId, ScopeId scopeId) => _couldNotStartEventHandler(logger, handlerId, scopeId, null); - internal static void ErrorWhileRunningEventHandler(this ILogger logger, Exception ex, EventProcessorId handlerId, ScopeId scopeId) - => _errorWhileRunningEventHandler(logger, handlerId, scopeId, ex); + [LoggerMessage(0, LogLevel.Warning, "An error occurred while running event handler: {EventHandler} in scope: {Scope}")] + internal static partial void ErrorWhileRunningEventHandler(this ILogger logger, Exception ex, EventProcessorId eventHandler, ScopeId scope); + + [LoggerMessage(0, LogLevel.Information, "Waiting for completions: {EventHandler} in scope: {Scope}, {RequestsInFlight} requests in flight")] + internal static partial void WaitingForCompletions(this ILogger logger, EventProcessorId eventHandler, ScopeId scope, int requestsInFlight); + + [LoggerMessage(0, LogLevel.Information, "All handlers complete: {EventHandler} in scope: {Scope}")] + internal static partial void FinishedWaitingForCompletions(this ILogger logger, EventProcessorId eventHandler, ScopeId scope); + + [LoggerMessage(0, LogLevel.Error, "Failed while waiting for completions: {EventHandler} in scope: {Scope}, with {RequestsInFlight} requests in flight")] + internal static partial void FailedWaitingForCompletions(this ILogger logger, Exception ex, EventProcessorId eventHandler, ScopeId scope, int requestsInFlight); + + [LoggerMessage(0, LogLevel.Information, "EventHandler was cancelled: {EventHandler} in scope: {Scope}")] + internal static partial void CancelledRunningEventHandler(this ILogger logger, Exception ex, EventProcessorId eventHandler, ScopeId scope); + + [LoggerMessage(0, LogLevel.Information, "Failing eventHandler was cancelled, no retries scheduled: {EventHandler} in scope: {Scope}. Error: {Reason}")] + internal static partial void StoppedFailingEventHandler(this ILogger logger, EventProcessorId eventHandler, ScopeId scope, string reason); + + [LoggerMessage(0, LogLevel.Information, "Event handler: {EventHandler} in scope: {Scope} disconnected for tenant {TenantId}")] + internal static partial void EventHandlerDisconnectedForTenant(this ILogger logger, EventProcessorId eventHandler, ScopeId scope, TenantId tenantId); + internal static void EventHandlerDisconnected(this ILogger logger, EventProcessorId handlerId, ScopeId scopeId) => _eventHandlerDisconnected(logger, handlerId, scopeId, null); @@ -169,6 +184,7 @@ internal static void ErrorWhileRegisteringStreamProcessorForEventProcessor(this internal static void EventProcessorIsProcessing(this ILogger logger, EventProcessorId handlerId, ArtifactId eventType, PartitionId partition) => _eventProcessorIsProcessing(logger, handlerId, eventType, partition, null); - internal static void EventProcessorIsProcessingAgain(this ILogger logger, EventProcessorId handlerId, ArtifactId eventType, PartitionId partition, uint retryCount, string failureReason) + internal static void EventProcessorIsProcessingAgain(this ILogger logger, EventProcessorId handlerId, ArtifactId eventType, PartitionId partition, + uint retryCount, string failureReason) => _eventProcessorIsProcessingAgain(logger, handlerId, eventType, partition, retryCount, failureReason, null); -} \ No newline at end of file +} diff --git a/Source/Events.Processing/EventHandlers/MetricsCollector.cs b/Source/Events/Processing/EventHandlers/MetricsCollector.cs similarity index 100% rename from Source/Events.Processing/EventHandlers/MetricsCollector.cs rename to Source/Events/Processing/EventHandlers/MetricsCollector.cs diff --git a/Source/Events/Processing/EventHandlers/Services.cs b/Source/Events/Processing/EventHandlers/Services.cs new file mode 100644 index 000000000..43f6af296 --- /dev/null +++ b/Source/Events/Processing/EventHandlers/Services.cs @@ -0,0 +1,18 @@ +// // Copyright (c) Dolittle. All rights reserved. +// // Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// using Dolittle.Runtime.DependencyInversion; +// using Microsoft.Extensions.DependencyInjection; +// +// namespace Dolittle.Runtime.Events.Processing.EventHandlers; +// +// // TODO: Is bindings maybe a better word for these things? +// public class Services : ICanAddServices +// { +// public void AddTo(IServiceCollection services) +// { +// // TODO: Maybe we want to make an interface for these? +// services.AddTransient(); +// services.AddTransient(); +// } +// } diff --git a/Source/Events.Processing/EventProcessorKind.cs b/Source/Events/Processing/EventProcessorKind.cs similarity index 91% rename from Source/Events.Processing/EventProcessorKind.cs rename to Source/Events/Processing/EventProcessorKind.cs index 409518cd5..11ede31a0 100644 --- a/Source/Events.Processing/EventProcessorKind.cs +++ b/Source/Events/Processing/EventProcessorKind.cs @@ -15,4 +15,6 @@ public record EventProcessorKind(string Value) : ConceptAs(Value) /// /// representation. public static implicit operator EventProcessorKind(string identifier) => new(identifier); + + public static readonly EventProcessorKind Actor = "Actor"; } diff --git a/Source/Events.Processing/EventProcessorRegistrationResult.cs b/Source/Events/Processing/EventProcessorRegistrationResult.cs similarity index 100% rename from Source/Events.Processing/EventProcessorRegistrationResult.cs rename to Source/Events/Processing/EventProcessorRegistrationResult.cs diff --git a/Source/Events.Processing/FailedProcessing.cs b/Source/Events/Processing/FailedProcessing.cs similarity index 100% rename from Source/Events.Processing/FailedProcessing.cs rename to Source/Events/Processing/FailedProcessing.cs diff --git a/Source/Events.Processing/Filters/AbstractFilterProcessor.cs b/Source/Events/Processing/Filters/AbstractFilterProcessor.cs similarity index 97% rename from Source/Events.Processing/Filters/AbstractFilterProcessor.cs rename to Source/Events/Processing/Filters/AbstractFilterProcessor.cs index fa5650886..ff92b6aaf 100644 --- a/Source/Events.Processing/Filters/AbstractFilterProcessor.cs +++ b/Source/Events/Processing/Filters/AbstractFilterProcessor.cs @@ -50,6 +50,9 @@ protected AbstractFilterProcessor( /// public EventProcessorId Identifier => Definition.TargetStream.Value; + public CancellationToken? ShutdownToken { get; } = null; + public CancellationToken? DeadlineToken { get; } = null; + /// public abstract Task Filter(CommittedEvent @event, PartitionId partitionId, EventProcessorId eventProcessorId, ExecutionContext executionContext, CancellationToken cancellationToken); diff --git a/Source/Events.Processing/Filters/CompareFilterDefinitions.cs b/Source/Events/Processing/Filters/CompareFilterDefinitions.cs similarity index 100% rename from Source/Events.Processing/Filters/CompareFilterDefinitions.cs rename to Source/Events/Processing/Filters/CompareFilterDefinitions.cs diff --git a/Source/Events.Processing/Filters/EventHorizon/IPublicFiltersProtocol.cs b/Source/Events/Processing/Filters/EventHorizon/IPublicFiltersProtocol.cs similarity index 100% rename from Source/Events.Processing/Filters/EventHorizon/IPublicFiltersProtocol.cs rename to Source/Events/Processing/Filters/EventHorizon/IPublicFiltersProtocol.cs diff --git a/Source/Events.Processing/Filters/EventHorizon/PublicFilterProcessor.cs b/Source/Events/Processing/Filters/EventHorizon/PublicFilterProcessor.cs similarity index 100% rename from Source/Events.Processing/Filters/EventHorizon/PublicFilterProcessor.cs rename to Source/Events/Processing/Filters/EventHorizon/PublicFilterProcessor.cs diff --git a/Source/Events.Processing/Filters/EventHorizon/PublicFilterRegistrationArguments.cs b/Source/Events/Processing/Filters/EventHorizon/PublicFilterRegistrationArguments.cs similarity index 100% rename from Source/Events.Processing/Filters/EventHorizon/PublicFilterRegistrationArguments.cs rename to Source/Events/Processing/Filters/EventHorizon/PublicFilterRegistrationArguments.cs diff --git a/Source/Events.Processing/Filters/EventHorizon/PublicFiltersProtocol.cs b/Source/Events/Processing/Filters/EventHorizon/PublicFiltersProtocol.cs similarity index 100% rename from Source/Events.Processing/Filters/EventHorizon/PublicFiltersProtocol.cs rename to Source/Events/Processing/Filters/EventHorizon/PublicFiltersProtocol.cs diff --git a/Source/Events.Processing/Filters/FailedFilterValidationReason.cs b/Source/Events/Processing/Filters/FailedFilterValidationReason.cs similarity index 100% rename from Source/Events.Processing/Filters/FailedFilterValidationReason.cs rename to Source/Events/Processing/Filters/FailedFilterValidationReason.cs diff --git a/Source/Events.Processing/Filters/FailedFiltering.cs b/Source/Events/Processing/Filters/FailedFiltering.cs similarity index 100% rename from Source/Events.Processing/Filters/FailedFiltering.cs rename to Source/Events/Processing/Filters/FailedFiltering.cs diff --git a/Source/Events.Processing/Filters/FilterRegistrationResult.cs b/Source/Events/Processing/Filters/FilterRegistrationResult.cs similarity index 100% rename from Source/Events.Processing/Filters/FilterRegistrationResult.cs rename to Source/Events/Processing/Filters/FilterRegistrationResult.cs diff --git a/Source/Events.Processing/Filters/FilterValidationFailed.cs b/Source/Events/Processing/Filters/FilterValidationFailed.cs similarity index 100% rename from Source/Events.Processing/Filters/FilterValidationFailed.cs rename to Source/Events/Processing/Filters/FilterValidationFailed.cs diff --git a/Source/Events.Processing/Filters/FilterValidationResult.cs b/Source/Events/Processing/Filters/FilterValidationResult.cs similarity index 100% rename from Source/Events.Processing/Filters/FilterValidationResult.cs rename to Source/Events/Processing/Filters/FilterValidationResult.cs diff --git a/Source/Events.Processing/Filters/FilterValidators.cs b/Source/Events/Processing/Filters/FilterValidators.cs similarity index 91% rename from Source/Events.Processing/Filters/FilterValidators.cs rename to Source/Events/Processing/Filters/FilterValidators.cs index 781190ff7..c5a283efe 100644 --- a/Source/Events.Processing/Filters/FilterValidators.cs +++ b/Source/Events/Processing/Filters/FilterValidators.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -25,7 +26,7 @@ namespace Dolittle.Runtime.Events.Processing.Filters; public class FilterValidators : IFilterValidators { readonly TenantId _tenant; - readonly IStreamProcessorStateRepository _streamProcessorStates; + readonly IStreamProcessorStates _streamProcessorStates; readonly IFilterDefinitions _filterDefinitions; readonly ICompareFilterDefinitions _definitionComparer; readonly IServiceProvider _serviceProvider; @@ -42,7 +43,7 @@ public class FilterValidators : IFilterValidators /// The logger to use for logging. public FilterValidators( TenantId tenant, - IStreamProcessorStateRepository streamProcessorStates, + IStreamProcessorStates streamProcessorStates, IFilterDefinitions filterDefinitions, ICompareFilterDefinitions definitionComparer, IServiceProvider serviceProvider, @@ -60,6 +61,11 @@ public FilterValidators( public async Task Validate(IFilterProcessor filter, CancellationToken cancellationToken) where TDefinition : IFilterDefinition { + if (!filter.Definition.CanBeValidated) + { + return FilterValidationResult.Succeeded(); + } + var tryGetProcessorState = await _streamProcessorStates .TryGetFor(new StreamProcessorId(filter.Scope, filter.Definition.TargetStream.Value, filter.Definition.SourceStream), cancellationToken) .ConfigureAwait(false); @@ -99,7 +105,7 @@ public async Task Validate(IFilterProcessor return await validator.Validate((TDefinition)persistedDefinition, filter, lastUnprocessedEvent, cancellationToken).ConfigureAwait(false); } - bool TryGetValidatorFor(out ICanValidateFilterFor validator) + bool TryGetValidatorFor([NotNullWhen(true)] out ICanValidateFilterFor? validator) where TDefinition : IFilterDefinition { validator = default; @@ -119,7 +125,7 @@ bool TryGetValidatorFor(out ICanValidateFilterFor vali } } - static bool StreamProcessorHasProcessedEvents(Try tryGetState, out FilterValidationResult validationResult, out StreamPosition lastUnprocessedEvent) + static bool StreamProcessorHasProcessedEvents(Try tryGetState, [NotNullWhen(false)] out FilterValidationResult? validationResult, [NotNullWhen(true)] out ProcessingPosition? lastUnprocessedEvent) { if (!tryGetState.Success) { @@ -132,7 +138,7 @@ static bool StreamProcessorHasProcessedEvents(Try tryGetS lastUnprocessedEvent = tryGetState.Result.Position; - if (lastUnprocessedEvent == StreamPosition.Start) + if (lastUnprocessedEvent == ProcessingPosition.Initial) { validationResult = FilterValidationResult.Succeeded(); return false; diff --git a/Source/Events.Processing/Filters/FiltersFailures.cs b/Source/Events/Processing/Filters/FiltersFailures.cs similarity index 100% rename from Source/Events.Processing/Filters/FiltersFailures.cs rename to Source/Events/Processing/Filters/FiltersFailures.cs diff --git a/Source/Events.Processing/Filters/FiltersProtocol.cs b/Source/Events/Processing/Filters/FiltersProtocol.cs similarity index 100% rename from Source/Events.Processing/Filters/FiltersProtocol.cs rename to Source/Events/Processing/Filters/FiltersProtocol.cs diff --git a/Source/Events.Processing/Filters/FiltersService.cs b/Source/Events/Processing/Filters/FiltersService.cs similarity index 95% rename from Source/Events.Processing/Filters/FiltersService.cs rename to Source/Events/Processing/Filters/FiltersService.cs index 27b4df171..32602f93a 100644 --- a/Source/Events.Processing/Filters/FiltersService.cs +++ b/Source/Events/Processing/Filters/FiltersService.cs @@ -138,6 +138,7 @@ public override async Task Connect( { return; } + using var dispatcher = tryConnect.Result.dispatcher; var arguments = tryConnect.Result.arguments; var createExecutionContext = await CreateExecutionContextOrReject(dispatcher, arguments.ExecutionContext, cts.Token).ConfigureAwait(false); @@ -186,6 +187,7 @@ public override async Task ConnectPartitioned( { return; } + using var dispatcher = tryConnect.Result.dispatcher; var arguments = tryConnect.Result.arguments; var createExecutionContext = await CreateExecutionContextOrReject(dispatcher, arguments.ExecutionContext, cts.Token).ConfigureAwait(false); @@ -206,7 +208,7 @@ public override async Task ConnectPartitioned( await RegisterFilter( dispatcher, arguments.Scope, - filterDefinition, + filterDefinition, tenant => _createPartitionedFilterProcessorFor( tenant, arguments.Scope, @@ -235,6 +237,7 @@ public override async Task ConnectPublic( { return; } + using var dispatcher = tryConnect.Result.dispatcher; var arguments = tryConnect.Result.arguments; var createExecutionContext = await CreateExecutionContextOrReject(dispatcher, arguments.ExecutionContext, cts.Token).ConfigureAwait(false); @@ -256,15 +259,16 @@ await RegisterFilter( ScopeId.Default, filterDefinition, tenant => _createPublicFilterProcessorFor( - tenant, - filterDefinition, - dispatcher), + tenant, + filterDefinition, + dispatcher), executionContext, cts.Token).ConfigureAwait(false); } Task> CreateExecutionContextOrReject( - IReverseCallDispatcher dispatcher, + IReverseCallDispatcher + dispatcher, ExecutionContext requestExecutionContext, CancellationToken cancellationToken) where TClientMessage : IMessage, new() @@ -278,10 +282,11 @@ Task> CreateExecutionContextOrReject RejectIfInvalidFilterId( - IReverseCallDispatcher dispatcher, + IReverseCallDispatcher + dispatcher, EventProcessorId filterId, CancellationToken cancellationToken) where TClientMessage : IMessage, new() @@ -301,7 +306,8 @@ async Task RejectIfInvalidFilterId( - IReverseCallDispatcher dispatcher, + IReverseCallDispatcher + dispatcher, ScopeId scopeId, TFilterDefinition filterDefinition, Func> getFilterProcessor, @@ -357,7 +363,7 @@ async Task RegisterFilter _logger.ErrorWhileRunningFilter(ex, filterDefinition.TargetStream, scopeId); tasks.OnAllTasksCompleted += () => _logger.FilterStopped(filterDefinition.TargetStream, scopeId); @@ -365,7 +371,8 @@ async Task RegisterFilter>> TryStartFilter( - IReverseCallDispatcher dispatcher, + IReverseCallDispatcher + dispatcher, StreamProcessor streamProcessor, ScopeId scopeId, TFilterDefinition filterDefinition, @@ -414,7 +421,7 @@ Try TryRegisterStreamProcessor( scopeId, filterDefinition.TargetStream.Value, _kind, - new EventLogStreamDefinition(), + EventLogStreamDefinition.Instance, getFilterProcessor, executionContext, cancellationToken); @@ -437,14 +444,17 @@ async Task ValidateFilter( CancellationToken cancellationToken) where TFilterDefinition : IFilterDefinition { - _logger.ValidatingFilter(filterDefinition.TargetStream); - var filterValidationResults = await _filterForAllTenants.Validate(getFilterProcessor, cancellationToken).ConfigureAwait(false); - - if (filterValidationResults.Any(_ => !_.Value.Success)) + if (filterDefinition.CanBeValidated) { - var firstFailedValidation = filterValidationResults.Select(_ => _.Value).First(_ => !_.Success); - _logger.FilterValidationFailed(filterDefinition.TargetStream, firstFailedValidation.FailureReason); - throw new FilterValidationFailed(filterDefinition.TargetStream, firstFailedValidation.FailureReason); + _logger.ValidatingFilter(filterDefinition.TargetStream); + var filterValidationResults = await _filterForAllTenants.Validate(getFilterProcessor, cancellationToken).ConfigureAwait(false); + + if (filterValidationResults.Any(_ => !_.Value.Success)) + { + var firstFailedValidation = filterValidationResults.Select(_ => _.Value).First(_ => !_.Success); + _logger.FilterValidationFailed(filterDefinition.TargetStream, firstFailedValidation.FailureReason); + throw new FilterValidationFailed(filterDefinition.TargetStream, firstFailedValidation.FailureReason); + } } var filteredStreamDefinition = new StreamDefinition(filterDefinition); @@ -453,7 +463,8 @@ async Task ValidateFilter( } Task WriteFailedRegistrationResponse( - IReverseCallDispatcher dispatcher, + IReverseCallDispatcher + dispatcher, Failure failure, CancellationToken cancellationToken) where TClientMessage : IMessage, new() diff --git a/Source/Events.Processing/Filters/ICanValidateFilterFor.cs b/Source/Events/Processing/Filters/ICanValidateFilterFor.cs similarity index 91% rename from Source/Events.Processing/Filters/ICanValidateFilterFor.cs rename to Source/Events/Processing/Filters/ICanValidateFilterFor.cs index 1d2e38d35..d3dab2f3a 100644 --- a/Source/Events.Processing/Filters/ICanValidateFilterFor.cs +++ b/Source/Events/Processing/Filters/ICanValidateFilterFor.cs @@ -23,5 +23,5 @@ public interface ICanValidateFilterFor /// The of the last unprocessed event. /// The . /// . - Task Validate(TDefinition persistedDefinition, IFilterProcessor filter, StreamPosition lastUnprocessedEvent, CancellationToken cancellationToken); -} \ No newline at end of file + Task Validate(TDefinition persistedDefinition, IFilterProcessor filter, ProcessingPosition lastUnprocessedEvent, CancellationToken cancellationToken); +} diff --git a/Source/Events.Processing/Filters/ICompareFilterDefinitions.cs b/Source/Events/Processing/Filters/ICompareFilterDefinitions.cs similarity index 100% rename from Source/Events.Processing/Filters/ICompareFilterDefinitions.cs rename to Source/Events/Processing/Filters/ICompareFilterDefinitions.cs diff --git a/Source/Events.Processing/Filters/IFilterProcessor.cs b/Source/Events/Processing/Filters/IFilterProcessor.cs similarity index 100% rename from Source/Events.Processing/Filters/IFilterProcessor.cs rename to Source/Events/Processing/Filters/IFilterProcessor.cs diff --git a/Source/Events.Processing/Filters/IFilterResult.cs b/Source/Events/Processing/Filters/IFilterResult.cs similarity index 100% rename from Source/Events.Processing/Filters/IFilterResult.cs rename to Source/Events/Processing/Filters/IFilterResult.cs diff --git a/Source/Events.Processing/Filters/IFilterValidators.cs b/Source/Events/Processing/Filters/IFilterValidators.cs similarity index 100% rename from Source/Events.Processing/Filters/IFilterValidators.cs rename to Source/Events/Processing/Filters/IFilterValidators.cs diff --git a/Source/Events.Processing/Filters/IFiltersProtocol.cs b/Source/Events/Processing/Filters/IFiltersProtocol.cs similarity index 100% rename from Source/Events.Processing/Filters/IFiltersProtocol.cs rename to Source/Events/Processing/Filters/IFiltersProtocol.cs diff --git a/Source/Events.Processing/Filters/IValidateFilterForAllTenants.cs b/Source/Events/Processing/Filters/IValidateFilterForAllTenants.cs similarity index 100% rename from Source/Events.Processing/Filters/IValidateFilterForAllTenants.cs rename to Source/Events/Processing/Filters/IValidateFilterForAllTenants.cs diff --git a/Source/Events.Processing/Filters/Log.cs b/Source/Events/Processing/Filters/Log.cs similarity index 100% rename from Source/Events.Processing/Filters/Log.cs rename to Source/Events/Processing/Filters/Log.cs diff --git a/Source/Events.Processing/Filters/Partitioned/FilterProcessor.cs b/Source/Events/Processing/Filters/Partitioned/FilterProcessor.cs similarity index 100% rename from Source/Events.Processing/Filters/Partitioned/FilterProcessor.cs rename to Source/Events/Processing/Filters/Partitioned/FilterProcessor.cs diff --git a/Source/Events.Processing/Filters/Partitioned/IPartitionedFiltersProtocol.cs b/Source/Events/Processing/Filters/Partitioned/IPartitionedFiltersProtocol.cs similarity index 100% rename from Source/Events.Processing/Filters/Partitioned/IPartitionedFiltersProtocol.cs rename to Source/Events/Processing/Filters/Partitioned/IPartitionedFiltersProtocol.cs diff --git a/Source/Events.Processing/Filters/Partitioned/PartitionedFilterRegistrationArguments.cs b/Source/Events/Processing/Filters/Partitioned/PartitionedFilterRegistrationArguments.cs similarity index 100% rename from Source/Events.Processing/Filters/Partitioned/PartitionedFilterRegistrationArguments.cs rename to Source/Events/Processing/Filters/Partitioned/PartitionedFilterRegistrationArguments.cs diff --git a/Source/Events.Processing/Filters/Partitioned/PartitionedFiltersProtocol.cs b/Source/Events/Processing/Filters/Partitioned/PartitionedFiltersProtocol.cs similarity index 100% rename from Source/Events.Processing/Filters/Partitioned/PartitionedFiltersProtocol.cs rename to Source/Events/Processing/Filters/Partitioned/PartitionedFiltersProtocol.cs diff --git a/Source/Events.Processing/Filters/Services.cs b/Source/Events/Processing/Filters/Services.cs similarity index 100% rename from Source/Events.Processing/Filters/Services.cs rename to Source/Events/Processing/Filters/Services.cs diff --git a/Source/Events.Processing/Filters/SuccessfulFiltering.cs b/Source/Events/Processing/Filters/SuccessfulFiltering.cs similarity index 100% rename from Source/Events.Processing/Filters/SuccessfulFiltering.cs rename to Source/Events/Processing/Filters/SuccessfulFiltering.cs diff --git a/Source/Events.Processing/Filters/TypeFilterWithEventSourcePartition.cs b/Source/Events/Processing/Filters/TypeFilterWithEventSourcePartition.cs similarity index 100% rename from Source/Events.Processing/Filters/TypeFilterWithEventSourcePartition.cs rename to Source/Events/Processing/Filters/TypeFilterWithEventSourcePartition.cs diff --git a/Source/Events.Processing/Filters/Unpartitioned/FilterProcessor.cs b/Source/Events/Processing/Filters/Unpartitioned/FilterProcessor.cs similarity index 100% rename from Source/Events.Processing/Filters/Unpartitioned/FilterProcessor.cs rename to Source/Events/Processing/Filters/Unpartitioned/FilterProcessor.cs diff --git a/Source/Events.Processing/Filters/Unpartitioned/IUnpartitionedFiltersProtocol.cs b/Source/Events/Processing/Filters/Unpartitioned/IUnpartitionedFiltersProtocol.cs similarity index 100% rename from Source/Events.Processing/Filters/Unpartitioned/IUnpartitionedFiltersProtocol.cs rename to Source/Events/Processing/Filters/Unpartitioned/IUnpartitionedFiltersProtocol.cs diff --git a/Source/Events.Processing/Filters/Unpartitioned/UnpartitionedFilterRegistrationArguments.cs b/Source/Events/Processing/Filters/Unpartitioned/UnpartitionedFilterRegistrationArguments.cs similarity index 100% rename from Source/Events.Processing/Filters/Unpartitioned/UnpartitionedFilterRegistrationArguments.cs rename to Source/Events/Processing/Filters/Unpartitioned/UnpartitionedFilterRegistrationArguments.cs diff --git a/Source/Events.Processing/Filters/Unpartitioned/UnpartitionedFiltersProtocol.cs b/Source/Events/Processing/Filters/Unpartitioned/UnpartitionedFiltersProtocol.cs similarity index 100% rename from Source/Events.Processing/Filters/Unpartitioned/UnpartitionedFiltersProtocol.cs rename to Source/Events/Processing/Filters/Unpartitioned/UnpartitionedFiltersProtocol.cs diff --git a/Source/Events.Processing/Filters/ValidateFilterByComparingEventTypes.cs b/Source/Events/Processing/Filters/ValidateFilterByComparingEventTypes.cs similarity index 96% rename from Source/Events.Processing/Filters/ValidateFilterByComparingEventTypes.cs rename to Source/Events/Processing/Filters/ValidateFilterByComparingEventTypes.cs index e281c1610..be7590c1c 100644 --- a/Source/Events.Processing/Filters/ValidateFilterByComparingEventTypes.cs +++ b/Source/Events/Processing/Filters/ValidateFilterByComparingEventTypes.cs @@ -34,7 +34,7 @@ public ValidateFilterByComparingEventTypes( } /// - public async Task Validate(TypeFilterWithEventSourcePartitionDefinition persistedDefinition, IFilterProcessor filter, StreamPosition lastUnprocessedEvent, CancellationToken cancellationToken) + public async Task Validate(TypeFilterWithEventSourcePartitionDefinition persistedDefinition, IFilterProcessor filter, ProcessingPosition lastUnprocessedEvent, CancellationToken cancellationToken) { try { @@ -51,7 +51,7 @@ public async Task Validate(TypeFilterWithEventSourcePart cancellationToken).ConfigureAwait(false); var typesInSourceStream = await streamTypesFetcher.FetchInRange( - new StreamPositionRange(StreamPosition.Start, lastUnprocessedEvent), + new StreamPositionRange(StreamPosition.Start, lastUnprocessedEvent.StreamPosition), cancellationToken).ConfigureAwait(false); return SourceStreamContainsChangedEventTypes(typesInSourceStream, changedEventTypes) diff --git a/Source/Events.Processing/Filters/ValidateFilterForAllTenants.cs b/Source/Events/Processing/Filters/ValidateFilterForAllTenants.cs similarity index 100% rename from Source/Events.Processing/Filters/ValidateFilterForAllTenants.cs rename to Source/Events/Processing/Filters/ValidateFilterForAllTenants.cs diff --git a/Source/Events.Processing/IEventProcessor.cs b/Source/Events/Processing/IEventProcessor.cs similarity index 85% rename from Source/Events.Processing/IEventProcessor.cs rename to Source/Events/Processing/IEventProcessor.cs index 6ca7f53f2..734df8c57 100644 --- a/Source/Events.Processing/IEventProcessor.cs +++ b/Source/Events/Processing/IEventProcessor.cs @@ -24,6 +24,16 @@ public interface IEventProcessor /// EventProcessorId Identifier { get; } + /// + /// Let the processor know that it should shut down. + /// + CancellationToken? ShutdownToken => null; + + /// + /// Do not wait for graceful shutdown after this has been cancelled + /// + CancellationToken? DeadlineToken => null; + /// /// Processes an for a partition . /// @@ -44,5 +54,6 @@ public interface IEventProcessor /// The execution context to process the event in. /// The . /// . - Task Process(CommittedEvent @event, PartitionId partitionId, string failureReason, uint retryCount, ExecutionContext executionContext, CancellationToken cancellationToken); + Task Process(CommittedEvent @event, PartitionId partitionId, string failureReason, uint retryCount, ExecutionContext executionContext, + CancellationToken cancellationToken); } diff --git a/Source/Events.Processing/IProcessingResult.cs b/Source/Events/Processing/IProcessingResult.cs similarity index 100% rename from Source/Events.Processing/IProcessingResult.cs rename to Source/Events/Processing/IProcessingResult.cs diff --git a/Source/Events.Processing/LoggerExtensions.cs b/Source/Events/Processing/LoggerExtensions.cs similarity index 100% rename from Source/Events.Processing/LoggerExtensions.cs rename to Source/Events/Processing/LoggerExtensions.cs diff --git a/Source/Events.Processing.Management/EventHandlers/EventHandlersFailures.cs b/Source/Events/Processing/Management/EventHandlers/EventHandlersFailures.cs similarity index 100% rename from Source/Events.Processing.Management/EventHandlers/EventHandlersFailures.cs rename to Source/Events/Processing/Management/EventHandlers/EventHandlersFailures.cs diff --git a/Source/Events.Processing.Management/EventHandlers/EventHandlersService.cs b/Source/Events/Processing/Management/EventHandlers/EventHandlersService.cs similarity index 73% rename from Source/Events.Processing.Management/EventHandlers/EventHandlersService.cs rename to Source/Events/Processing/Management/EventHandlers/EventHandlersService.cs index 89dfbc83f..83ff54246 100644 --- a/Source/Events.Processing.Management/EventHandlers/EventHandlersService.cs +++ b/Source/Events/Processing/Management/EventHandlers/EventHandlersService.cs @@ -11,6 +11,9 @@ using Dolittle.Runtime.Events.Processing.EventHandlers; using Dolittle.Runtime.Events.Processing.Management.Contracts; using Dolittle.Runtime.Events.Processing.Management.StreamProcessors; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Events.Store.Streams.Legacy; using Dolittle.Runtime.Protobuf; using Dolittle.Runtime.Rudimentary; using Dolittle.Runtime.Services.Hosting; @@ -43,7 +46,7 @@ public EventHandlersService( IEventHandlers eventHandlers, IExceptionToFailureConverter exceptionToFailureConverter, IConvertStreamProcessorStatuses streamProcessorStatusConverter, - ILogger logger) + ILogger logger, IGetEventLogSequenceFromStreamPosition streamPositionToEventLogSequenceService) { _eventHandlers = eventHandlers; _exceptionToFailureConverter = exceptionToFailureConverter; @@ -52,25 +55,32 @@ public EventHandlersService( } /// - public override Task GetAll(GetAllRequest request, ServerCallContext context) + public override async Task GetAll(GetAllRequest request, ServerCallContext context) { Log.GetAll(_logger); var response = new GetAllResponse(); - response.EventHandlers.AddRange(_eventHandlers.All.Select(_ => CreateStatusFromInfo(_, request.TenantId?.ToGuid()))); - return Task.FromResult(response); + foreach (var eventHandlerInfo in _eventHandlers.All) + { + var result = await CreateStatusFromInfo(eventHandlerInfo, request.TenantId?.ToGuid()); + response.EventHandlers.Add(result); + } + + return response; } /// - public override Task GetOne(GetOneRequest request, ServerCallContext context) + public override async Task GetOne(GetOneRequest request, ServerCallContext context) { var response = new GetOneResponse(); - var getIds = GetEventHandlerId(request.ScopeId, request.EventHandlerId, out var eventHandler); + var getIds = GetEventHandlerId(request.ScopeId, request.EventHandlerId); if (!getIds.Success) { response.Failure = _exceptionToFailureConverter.ToFailure(getIds.Exception); - return Task.FromResult(response); + return response; } + + var eventHandler = getIds.Result; Log.GetOne(_logger, eventHandler.EventHandler, eventHandler.Scope); @@ -79,11 +89,11 @@ public override Task GetOne(GetOneRequest request, ServerCallCon { Log.EventHandlerNotRegistered(_logger, eventHandler.EventHandler, eventHandler.Scope); response.Failure = _exceptionToFailureConverter.ToFailure(new EventHandlerNotRegistered(eventHandler)); - return Task.FromResult(response); + return response; } - response.EventHandlers = CreateStatusFromInfo(info, request.TenantId?.ToGuid()); - return Task.FromResult(response); + response.EventHandlers = await CreateStatusFromInfo(info, request.TenantId?.ToGuid()); + return response; } @@ -92,17 +102,22 @@ public override async Task ReprocessEventsFrom(Repr { var response = new ReprocessEventsFromResponse(); - var getIds = GetEventHandlerId(request.ScopeId, request.EventHandlerId, out var eventHandler); + var getIds = GetEventHandlerId(request.ScopeId, request.EventHandlerId); if (!getIds.Success) { response.Failure = _exceptionToFailureConverter.ToFailure(getIds.Exception); return response; } + + var eventHandler = getIds.Result; TenantId tenant = request.TenantId.ToGuid(); Log.ReprocessEventsFrom(_logger, eventHandler.EventHandler, eventHandler.Scope, tenant, request.StreamPosition); - - var reprocessing = await _eventHandlers.ReprocessEventsFrom(eventHandler, tenant, request.StreamPosition).ConfigureAwait(false); + + var eventLogPosition = new EventLogSequenceNumber(request.StreamPosition); + var processingPosition = new ProcessingPosition(StreamPosition.Start, eventLogPosition); + + var reprocessing = await _eventHandlers.ReprocessEventsFrom(eventHandler, tenant, processingPosition).ConfigureAwait(false); if (!reprocessing.Success) { Log.FailedDuringReprocessing(_logger, reprocessing.Exception); @@ -117,12 +132,14 @@ public override async Task ReprocessAllEvents(Reproc { var response = new ReprocessAllEventsResponse(); - var getIds = GetEventHandlerId(request.ScopeId, request.EventHandlerId, out var eventHandler); + var getIds = GetEventHandlerId(request.ScopeId, request.EventHandlerId); if (!getIds.Success) { response.Failure = _exceptionToFailureConverter.ToFailure(getIds.Exception); return response; } + + var eventHandler = getIds.Result; Log.ReprocessAllEvents(_logger, eventHandler.EventHandler, eventHandler.Scope); var reprocessing = await _eventHandlers.ReprocessAllEvents(eventHandler).ConfigureAwait(false); @@ -135,7 +152,7 @@ public override async Task ReprocessAllEvents(Reproc return response; } - EventHandlerStatus CreateStatusFromInfo(EventHandlerInfo info, TenantId tenant = null) + async Task CreateStatusFromInfo(EventHandlerInfo info, TenantId tenant) { var status = new EventHandlerStatus { @@ -145,13 +162,13 @@ EventHandlerStatus CreateStatusFromInfo(EventHandlerInfo info, TenantId tenant = EventHandlerId = info.Id.EventHandler.ToProtobuf() }; status.EventTypes.AddRange(info.EventTypes.Select(CreateEventType)); - status.Tenants.AddRange(CreateScopedStreamProcessorStatus(info, tenant)); + status.Tenants.AddRange(await CreateScopedStreamProcessorStatus(info, tenant)); return status; } - - IEnumerable CreateScopedStreamProcessorStatus(EventHandlerInfo info, TenantId tenant = null) + + async Task> CreateScopedStreamProcessorStatus(EventHandlerInfo info, TenantId tenant = null) { - var state = _eventHandlers.CurrentStateFor(info.Id); + var state = await _eventHandlers.CurrentStateFor(info.Id); if (!state.Success) { throw state.Exception; @@ -169,20 +186,17 @@ static Artifact CreateEventType(ArtifactId id) Generation = ArtifactGeneration.First, }; - static Try GetEventHandlerId(Uuid scope, Uuid eventHandler, out EventHandlerId eventHandlerId) + static Try GetEventHandlerId(Uuid? scope, Uuid? eventHandler) { - eventHandlerId = default; - if (scope == default) { - return Try.Failed(new ArgumentNullException(nameof(scope), "Scope id is missing in request")); + return Try.Failed(new ArgumentNullException(nameof(scope), "Scope id is missing in request")); } if (eventHandler == default) { - return Try.Failed(new ArgumentNullException(nameof(eventHandler), "EventHandler id is missing in request")); + return Try.Failed(new ArgumentNullException(nameof(eventHandler), "EventHandler id is missing in request")); } - eventHandlerId = new EventHandlerId(scope.ToGuid(), eventHandler.ToGuid()); - return Try.Succeeded(); + return Try.Succeeded(new EventHandlerId(scope.ToGuid(), eventHandler.ToGuid())); } } diff --git a/Source/Events.Processing.Management/EventHandlers/ExceptionToFailureConverter.cs b/Source/Events/Processing/Management/EventHandlers/ExceptionToFailureConverter.cs similarity index 100% rename from Source/Events.Processing.Management/EventHandlers/ExceptionToFailureConverter.cs rename to Source/Events/Processing/Management/EventHandlers/ExceptionToFailureConverter.cs diff --git a/Source/Events.Processing.Management/EventHandlers/IExceptionToFailureConverter.cs b/Source/Events/Processing/Management/EventHandlers/IExceptionToFailureConverter.cs similarity index 100% rename from Source/Events.Processing.Management/EventHandlers/IExceptionToFailureConverter.cs rename to Source/Events/Processing/Management/EventHandlers/IExceptionToFailureConverter.cs diff --git a/Source/Events.Processing.Management/EventHandlers/Log.cs b/Source/Events/Processing/Management/EventHandlers/Log.cs similarity index 100% rename from Source/Events.Processing.Management/EventHandlers/Log.cs rename to Source/Events/Processing/Management/EventHandlers/Log.cs diff --git a/Source/Events.Processing.Management/Projections/ExceptionToFailureConverter.cs b/Source/Events/Processing/Management/Projections/ExceptionToFailureConverter.cs similarity index 100% rename from Source/Events.Processing.Management/Projections/ExceptionToFailureConverter.cs rename to Source/Events/Processing/Management/Projections/ExceptionToFailureConverter.cs diff --git a/Source/Events.Processing.Management/Projections/IExceptionToFailureConverter.cs b/Source/Events/Processing/Management/Projections/IExceptionToFailureConverter.cs similarity index 100% rename from Source/Events.Processing.Management/Projections/IExceptionToFailureConverter.cs rename to Source/Events/Processing/Management/Projections/IExceptionToFailureConverter.cs diff --git a/Source/Events.Processing.Management/Projections/Log.cs b/Source/Events/Processing/Management/Projections/Log.cs similarity index 100% rename from Source/Events.Processing.Management/Projections/Log.cs rename to Source/Events/Processing/Management/Projections/Log.cs diff --git a/Source/Events.Processing.Management/Projections/ProjectionsFailures.cs b/Source/Events/Processing/Management/Projections/ProjectionsFailures.cs similarity index 100% rename from Source/Events.Processing.Management/Projections/ProjectionsFailures.cs rename to Source/Events/Processing/Management/Projections/ProjectionsFailures.cs diff --git a/Source/Events.Processing.Management/Projections/ProjectionsService.cs b/Source/Events/Processing/Management/Projections/ProjectionsService.cs similarity index 90% rename from Source/Events.Processing.Management/Projections/ProjectionsService.cs rename to Source/Events/Processing/Management/Projections/ProjectionsService.cs index 0f8a1643b..bd04efd6f 100644 --- a/Source/Events.Processing.Management/Projections/ProjectionsService.cs +++ b/Source/Events/Processing/Management/Projections/ProjectionsService.cs @@ -69,12 +69,13 @@ public override Task GetOne(GetOneProjectionRequest re { var response = new GetOneProjectionResponse(); - var getIds = GetScopeAndProjectionIds(request.ScopeId, request.ProjectionId, out var scope, out var projection); + var getIds = GetScopeAndProjectionIds(request.ScopeId, request.ProjectionId); if (!getIds.Success) { response.Failure = _exceptionToFailureConverter.ToFailure(getIds.Exception); return Task.FromResult(response); } + var (scope, projection) = getIds.Result; Log.GetOne(_logger, projection, scope); @@ -95,13 +96,15 @@ public override async Task Replay(ReplayProjectionRequ { var response = new ReplayProjectionResponse(); - var getIds = GetScopeAndProjectionIds(request.ScopeId, request.ProjectionId, out var scope, out var projection); + var getIds = GetScopeAndProjectionIds(request.ScopeId, request.ProjectionId); if (!getIds.Success) { response.Failure = _exceptionToFailureConverter.ToFailure(getIds.Exception); return response; } + var (scope, projection) = getIds.Result; + Log.Replay(_logger, projection, scope); var result = request.TenantId == null @@ -132,7 +135,7 @@ ProjectionStatus CreateStatusFromInfo(ProjectionInfo info, TenantId tenant = nul return status; } - IEnumerable CreateScopedStreamProcessorStatus(ProjectionInfo info, TenantId tenant = null) + IEnumerable CreateScopedStreamProcessorStatus(ProjectionInfo info, TenantId? tenant = null) { var state = _projections.CurrentStateFor(info.Definition.Scope, info.Definition.Projection); if (!state.Success) @@ -150,23 +153,19 @@ IEnumerable CreateScopedStreamProcessorStatus return _streamProcessorStatusConverter.ConvertForTenant(state.Result, tenant); } - static Try GetScopeAndProjectionIds(Uuid scope, Uuid projection, out ScopeId scopeId, out ProjectionId projectionId) + static Try<(ScopeId scopeId,ProjectionId projectionId)> GetScopeAndProjectionIds(Uuid? scope, Uuid? projection) { - scopeId = default; - projectionId = default; - if (scope == default) { - return Try.Failed(new ArgumentNullException(nameof(scope), "Scope id is missing in request")); + return Try<(ScopeId,ProjectionId)>.Failed(new ArgumentNullException(nameof(scope), "Scope id is missing in request")); } if (projection == default) { - return Try.Failed(new ArgumentNullException(nameof(projection), "Projection id is missing in request")); + return Try<(ScopeId,ProjectionId)>.Failed(new ArgumentNullException(nameof(projection), "Projection id is missing in request")); } - scopeId = scope.ToGuid(); - projectionId = projection.ToGuid(); + (ScopeId,ProjectionId) result = (scope.ToGuid(), projection.ToGuid()); - return Try.Succeeded(); + return Try<(ScopeId,ProjectionId)>.Succeeded(result); } } diff --git a/Source/Events.Processing.Management/StreamProcessors/ConvertStreamProcessorStatuses.cs b/Source/Events/Processing/Management/StreamProcessors/ConvertStreamProcessorStatuses.cs similarity index 97% rename from Source/Events.Processing.Management/StreamProcessors/ConvertStreamProcessorStatuses.cs rename to Source/Events/Processing/Management/StreamProcessors/ConvertStreamProcessorStatuses.cs index 2864efd21..513d87bf6 100644 --- a/Source/Events.Processing.Management/StreamProcessors/ConvertStreamProcessorStatuses.cs +++ b/Source/Events/Processing/Management/StreamProcessors/ConvertStreamProcessorStatuses.cs @@ -30,7 +30,7 @@ public class ConvertStreamProcessorStatuses : IConvertStreamProcessorStatuses { var status = new Contracts.TenantScopedStreamProcessorStatus { - StreamPosition = state.Position, + StreamPosition = state.Position.StreamPosition, TenantId = tenant.ToProtobuf(), }; @@ -50,7 +50,7 @@ public class ConvertStreamProcessorStatuses : IConvertStreamProcessorStatuses LastFailed = failure.LastFailed.ToTimestamp(), RetryCount = failure.ProcessingAttempts, RetryTime = failure.RetryTime.ToTimestamp(), - StreamPosition = failure.Position + StreamPosition = failure.Position.StreamPosition }); } diff --git a/Source/Events.Processing.Management/StreamProcessors/IConvertStreamProcessorStatuses.cs b/Source/Events/Processing/Management/StreamProcessors/IConvertStreamProcessorStatuses.cs similarity index 100% rename from Source/Events.Processing.Management/StreamProcessors/IConvertStreamProcessorStatuses.cs rename to Source/Events/Processing/Management/StreamProcessors/IConvertStreamProcessorStatuses.cs diff --git a/Source/Events.Processing/Projections/CompareProjectionDefinitionsForAllTenants.cs b/Source/Events/Processing/Projections/CompareProjectionDefinitionsForAllTenants.cs similarity index 100% rename from Source/Events.Processing/Projections/CompareProjectionDefinitionsForAllTenants.cs rename to Source/Events/Processing/Projections/CompareProjectionDefinitionsForAllTenants.cs diff --git a/Source/Events.Processing/Projections/ConvertProjectionDefinitions.cs b/Source/Events/Processing/Projections/ConvertProjectionDefinitions.cs similarity index 100% rename from Source/Events.Processing/Projections/ConvertProjectionDefinitions.cs rename to Source/Events/Processing/Projections/ConvertProjectionDefinitions.cs diff --git a/Source/Events.Processing/Projections/CouldNotGetProjectionKey.cs b/Source/Events/Processing/Projections/CouldNotGetProjectionKey.cs similarity index 100% rename from Source/Events.Processing/Projections/CouldNotGetProjectionKey.cs rename to Source/Events/Processing/Projections/CouldNotGetProjectionKey.cs diff --git a/Source/Events.Processing/Projections/CouldNotPersistProjectionDefinition.cs b/Source/Events/Processing/Projections/CouldNotPersistProjectionDefinition.cs similarity index 100% rename from Source/Events.Processing/Projections/CouldNotPersistProjectionDefinition.cs rename to Source/Events/Processing/Projections/CouldNotPersistProjectionDefinition.cs diff --git a/Source/Events.Processing/Projections/CouldNotResetProjectionStates.cs b/Source/Events/Processing/Projections/CouldNotResetProjectionStates.cs similarity index 100% rename from Source/Events.Processing/Projections/CouldNotResetProjectionStates.cs rename to Source/Events/Processing/Projections/CouldNotResetProjectionStates.cs diff --git a/Source/Events.Processing/Projections/EventProcessor.cs b/Source/Events/Processing/Projections/EventProcessor.cs similarity index 96% rename from Source/Events.Processing/Projections/EventProcessor.cs rename to Source/Events/Processing/Projections/EventProcessor.cs index 47550ef77..fcd0b1474 100644 --- a/Source/Events.Processing/Projections/EventProcessor.cs +++ b/Source/Events/Processing/Projections/EventProcessor.cs @@ -66,7 +66,7 @@ public async Task Process(CommittedEvent @event, PartitionId Log.EventProcessorIsProcessing(_logger, Identifier, @event.Type.Id, partitionId); if (!ShouldProcessEvent(@event)) { - return new SuccessfulProcessing(); + return SuccessfulProcessing.Instance; } var tryGetCurrentState = await TryGetCurrentState(@event, partitionId, cancellationToken).ConfigureAwait(false); @@ -86,7 +86,7 @@ public async Task Process(CommittedEvent @event, PartitionId Log.EventProcessorIsProcessingAgain(_logger, Identifier, @event.Type.Id, partitionId, retryCount, failureReason); if (!ShouldProcessEvent(@event)) { - return new SuccessfulProcessing(); + return SuccessfulProcessing.Instance; } @@ -119,12 +119,12 @@ async Task HandleResult(ProjectionKey key, IProjectionResult { ProjectionReplaceResult replace => await _projectionPersister.TryReplace(_projectionDefinition, key, replace.State, CancellationToken.None).ConfigureAwait(false) switch { - true => new SuccessfulProcessing(), + true => SuccessfulProcessing.Instance, false => new FailedProcessing($"Failed to replace state for projection {_projectionDefinition.Projection.Value} with key {key.Value}"), }, ProjectionDeleteResult => await _projectionPersister.TryRemove(_projectionDefinition, key, CancellationToken.None).ConfigureAwait(false) switch { - true => new SuccessfulProcessing(), + true => SuccessfulProcessing.Instance, false => new FailedProcessing($"Failed to remove state for projection {_projectionDefinition.Projection.Value} with key {key.Value}"), }, _ => result diff --git a/Source/Events.Processing/Projections/FailedProjectionDefinitionComparisonReason.cs b/Source/Events/Processing/Projections/FailedProjectionDefinitionComparisonReason.cs similarity index 100% rename from Source/Events.Processing/Projections/FailedProjectionDefinitionComparisonReason.cs rename to Source/Events/Processing/Projections/FailedProjectionDefinitionComparisonReason.cs diff --git a/Source/Events.Processing/Projections/ICompareProjectionDefinitionsForAllTenants.cs b/Source/Events/Processing/Projections/ICompareProjectionDefinitionsForAllTenants.cs similarity index 100% rename from Source/Events.Processing/Projections/ICompareProjectionDefinitionsForAllTenants.cs rename to Source/Events/Processing/Projections/ICompareProjectionDefinitionsForAllTenants.cs diff --git a/Source/Events.Processing/Projections/IConvertProjectionDefinitions.cs b/Source/Events/Processing/Projections/IConvertProjectionDefinitions.cs similarity index 100% rename from Source/Events.Processing/Projections/IConvertProjectionDefinitions.cs rename to Source/Events/Processing/Projections/IConvertProjectionDefinitions.cs diff --git a/Source/Events.Processing/Projections/IProjection.cs b/Source/Events/Processing/Projections/IProjection.cs similarity index 100% rename from Source/Events.Processing/Projections/IProjection.cs rename to Source/Events/Processing/Projections/IProjection.cs diff --git a/Source/Events.Processing/Projections/IProjectionKeyPropertyExtractor.cs b/Source/Events/Processing/Projections/IProjectionKeyPropertyExtractor.cs similarity index 100% rename from Source/Events.Processing/Projections/IProjectionKeyPropertyExtractor.cs rename to Source/Events/Processing/Projections/IProjectionKeyPropertyExtractor.cs diff --git a/Source/Events.Processing/Projections/IProjectionKeys.cs b/Source/Events/Processing/Projections/IProjectionKeys.cs similarity index 100% rename from Source/Events.Processing/Projections/IProjectionKeys.cs rename to Source/Events/Processing/Projections/IProjectionKeys.cs diff --git a/Source/Events.Processing/Projections/IProjectionResult.cs b/Source/Events/Processing/Projections/IProjectionResult.cs similarity index 100% rename from Source/Events.Processing/Projections/IProjectionResult.cs rename to Source/Events/Processing/Projections/IProjectionResult.cs diff --git a/Source/Events.Processing/Projections/IProjections.cs b/Source/Events/Processing/Projections/IProjections.cs similarity index 100% rename from Source/Events.Processing/Projections/IProjections.cs rename to Source/Events/Processing/Projections/IProjections.cs diff --git a/Source/Events.Processing/Projections/IProjectionsProtocol.cs b/Source/Events/Processing/Projections/IProjectionsProtocol.cs similarity index 100% rename from Source/Events.Processing/Projections/IProjectionsProtocol.cs rename to Source/Events/Processing/Projections/IProjectionsProtocol.cs diff --git a/Source/Events.Processing/Projections/IValidateOccurredFormat.cs b/Source/Events/Processing/Projections/IValidateOccurredFormat.cs similarity index 87% rename from Source/Events.Processing/Projections/IValidateOccurredFormat.cs rename to Source/Events/Processing/Projections/IValidateOccurredFormat.cs index 3b36d8ab4..a1eb01012 100644 --- a/Source/Events.Processing/Projections/IValidateOccurredFormat.cs +++ b/Source/Events/Processing/Projections/IValidateOccurredFormat.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Diagnostics.CodeAnalysis; using Dolittle.Runtime.Projections.Store.Definition; namespace Dolittle.Runtime.Events.Processing.Projections; @@ -17,5 +18,5 @@ public interface IValidateOccurredFormat /// The to check /// The outputted that occurs when the is not valid. /// True if the format is valid, false if not. - bool IsValid(OccurredFormat format, out Exception error); + bool IsValid(OccurredFormat format, [NotNullWhen(false)] out Exception? error); } diff --git a/Source/Events.Processing/Projections/InvalidProjectionEventSelector.cs b/Source/Events/Processing/Projections/InvalidProjectionEventSelector.cs similarity index 100% rename from Source/Events.Processing/Projections/InvalidProjectionEventSelector.cs rename to Source/Events/Processing/Projections/InvalidProjectionEventSelector.cs diff --git a/Source/Events.Processing/Projections/Log.cs b/Source/Events/Processing/Projections/Log.cs similarity index 100% rename from Source/Events.Processing/Projections/Log.cs rename to Source/Events/Processing/Projections/Log.cs diff --git a/Source/Events.Processing/Projections/OccurredFormatCannotBeNullOrEmpty.cs b/Source/Events/Processing/Projections/OccurredFormatCannotBeNullOrEmpty.cs similarity index 100% rename from Source/Events.Processing/Projections/OccurredFormatCannotBeNullOrEmpty.cs rename to Source/Events/Processing/Projections/OccurredFormatCannotBeNullOrEmpty.cs diff --git a/Source/Events.Processing/Projections/Projection.cs b/Source/Events/Processing/Projections/Projection.cs similarity index 100% rename from Source/Events.Processing/Projections/Projection.cs rename to Source/Events/Processing/Projections/Projection.cs diff --git a/Source/Events.Processing/Projections/ProjectionAlias.cs b/Source/Events/Processing/Projections/ProjectionAlias.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionAlias.cs rename to Source/Events/Processing/Projections/ProjectionAlias.cs diff --git a/Source/Events.Processing/Projections/ProjectionAlreadyRegistered.cs b/Source/Events/Processing/Projections/ProjectionAlreadyRegistered.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionAlreadyRegistered.cs rename to Source/Events/Processing/Projections/ProjectionAlreadyRegistered.cs diff --git a/Source/Events.Processing/Projections/ProjectionCurrentStateExtensions.cs b/Source/Events/Processing/Projections/ProjectionCurrentStateExtensions.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionCurrentStateExtensions.cs rename to Source/Events/Processing/Projections/ProjectionCurrentStateExtensions.cs diff --git a/Source/Events.Processing/Projections/ProjectionCurrentStateTypeExtensions.cs b/Source/Events/Processing/Projections/ProjectionCurrentStateTypeExtensions.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionCurrentStateTypeExtensions.cs rename to Source/Events/Processing/Projections/ProjectionCurrentStateTypeExtensions.cs diff --git a/Source/Events.Processing/Projections/ProjectionDefinitionComparisonResult.cs b/Source/Events/Processing/Projections/ProjectionDefinitionComparisonResult.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionDefinitionComparisonResult.cs rename to Source/Events/Processing/Projections/ProjectionDefinitionComparisonResult.cs diff --git a/Source/Events.Processing/Projections/ProjectionDeleteResult.cs b/Source/Events/Processing/Projections/ProjectionDeleteResult.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionDeleteResult.cs rename to Source/Events/Processing/Projections/ProjectionDeleteResult.cs diff --git a/Source/Events.Processing/Projections/ProjectionFailed.cs b/Source/Events/Processing/Projections/ProjectionFailed.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionFailed.cs rename to Source/Events/Processing/Projections/ProjectionFailed.cs diff --git a/Source/Events.Processing/Projections/ProjectionFailedResult.cs b/Source/Events/Processing/Projections/ProjectionFailedResult.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionFailedResult.cs rename to Source/Events/Processing/Projections/ProjectionFailedResult.cs diff --git a/Source/Events.Processing/Projections/ProjectionFailures.cs b/Source/Events/Processing/Projections/ProjectionFailures.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionFailures.cs rename to Source/Events/Processing/Projections/ProjectionFailures.cs diff --git a/Source/Events.Processing/Projections/ProjectionInfo.cs b/Source/Events/Processing/Projections/ProjectionInfo.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionInfo.cs rename to Source/Events/Processing/Projections/ProjectionInfo.cs diff --git a/Source/Events.Processing/Projections/ProjectionKeyPropertyExtractor.cs b/Source/Events/Processing/Projections/ProjectionKeyPropertyExtractor.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionKeyPropertyExtractor.cs rename to Source/Events/Processing/Projections/ProjectionKeyPropertyExtractor.cs diff --git a/Source/Events.Processing/Projections/ProjectionKeys.cs b/Source/Events/Processing/Projections/ProjectionKeys.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionKeys.cs rename to Source/Events/Processing/Projections/ProjectionKeys.cs diff --git a/Source/Events.Processing/Projections/ProjectionNotRegistered.cs b/Source/Events/Processing/Projections/ProjectionNotRegistered.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionNotRegistered.cs rename to Source/Events/Processing/Projections/ProjectionNotRegistered.cs diff --git a/Source/Events.Processing/Projections/ProjectionProcessor.cs b/Source/Events/Processing/Projections/ProjectionProcessor.cs similarity index 98% rename from Source/Events.Processing/Projections/ProjectionProcessor.cs rename to Source/Events/Processing/Projections/ProjectionProcessor.cs index b571b9447..ec402c8e4 100644 --- a/Source/Events.Processing/Projections/ProjectionProcessor.cs +++ b/Source/Events/Processing/Projections/ProjectionProcessor.cs @@ -93,7 +93,7 @@ public Try> GetCurrentStates() public async Task ReplayEventsForTenant(TenantId tenant, Func> dropStates) { Log.ReplayingEventsForTenant(_logger, Definition.Scope, Definition.Projection, tenant); - return await _streamProcessor.PerformActionAndSetToPosition(tenant, StreamPosition.Start, dropStates); + return await _streamProcessor.PerformActionAndSetToPosition(tenant, ProcessingPosition.Initial, dropStates); } /// diff --git a/Source/Events.Processing/Projections/ProjectionRegistrationArguments.cs b/Source/Events/Processing/Projections/ProjectionRegistrationArguments.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionRegistrationArguments.cs rename to Source/Events/Processing/Projections/ProjectionRegistrationArguments.cs diff --git a/Source/Events.Processing/Projections/ProjectionReplaceResult.cs b/Source/Events/Processing/Projections/ProjectionReplaceResult.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionReplaceResult.cs rename to Source/Events/Processing/Projections/ProjectionReplaceResult.cs diff --git a/Source/Events.Processing/Projections/Projections.cs b/Source/Events/Processing/Projections/Projections.cs similarity index 98% rename from Source/Events.Processing/Projections/Projections.cs rename to Source/Events/Processing/Projections/Projections.cs index 82659b1cd..dfc491b73 100644 --- a/Source/Events.Processing/Projections/Projections.cs +++ b/Source/Events/Processing/Projections/Projections.cs @@ -154,7 +154,7 @@ public async Task ReplayEventsForAllTenants(ScopeId scopeId, ProjectionId p } } - return Try.Succeeded(); + return Try.Succeeded; } async Task ResetProjectionIfDefinitionHasChanged(ProjectionIdentifier identifier, ProjectionDefinition definition, CancellationToken cancellationToken) @@ -173,7 +173,7 @@ async Task ResetProjectionIfDefinitionHasChanged(ProjectionIdentifier ident return persistence.Exception; } - return Try.Succeeded(); + return Try.Succeeded; } async Task> GetTenantsWhereDefinitionHasChanged(ProjectionIdentifier identifier, ProjectionDefinition definition, CancellationToken cancellationToken) @@ -201,7 +201,7 @@ Task DropStatesAndResetStreamProcessorsFor(IEnumerable tenants, P { if (!tenants.Contains(tenant)) { - return Try.Succeeded(); + return Try.Succeeded; } Log.ResettingStreamProcessorForTenant(_logger, newDefinition.Scope, newDefinition.Projection, tenant); @@ -216,7 +216,7 @@ Task DropStatesAndResetStreamProcessorsFor(IEnumerable tenants, P try { - var streamProcessorStates = services.GetRequiredService(); + var streamProcessorStates = services.GetRequiredService(); await streamProcessorStates.Persist( new StreamProcessorId(definition.Scope, definition.Projection.Value, StreamId.EventLog), StreamProcessorState.New, @@ -235,7 +235,7 @@ await streamProcessorStates.Persist( return new CouldNotResetProjectionStates(newDefinition, tenant); } - return Try.Succeeded(); + return Try.Succeeded; }); Task PersistDefinitionForAllTenants(ProjectionDefinition definition, CancellationToken cancellationToken) @@ -247,7 +247,7 @@ Task PersistDefinitionForAllTenants(ProjectionDefinition definition, Cancel { return new CouldNotPersistProjectionDefinition(definition, tenant); } - return Try.Succeeded(); + return Try.Succeeded; }); Func> DropStateAndResetStreamProcessorForTenantCallback(ProjectionProcessor processor) diff --git a/Source/Events.Processing/Projections/ProjectionsProtocol.cs b/Source/Events/Processing/Projections/ProjectionsProtocol.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionsProtocol.cs rename to Source/Events/Processing/Projections/ProjectionsProtocol.cs diff --git a/Source/Events.Processing/Projections/ProjectionsService.cs b/Source/Events/Processing/Projections/ProjectionsService.cs similarity index 100% rename from Source/Events.Processing/Projections/ProjectionsService.cs rename to Source/Events/Processing/Projections/ProjectionsService.cs diff --git a/Source/Events.Processing/Projections/Services.cs b/Source/Events/Processing/Projections/Services.cs similarity index 100% rename from Source/Events.Processing/Projections/Services.cs rename to Source/Events/Processing/Projections/Services.cs diff --git a/Source/Events.Processing/Projections/SuccessfulProjectionResult.cs b/Source/Events/Processing/Projections/SuccessfulProjectionResult.cs similarity index 100% rename from Source/Events.Processing/Projections/SuccessfulProjectionResult.cs rename to Source/Events/Processing/Projections/SuccessfulProjectionResult.cs diff --git a/Source/Events.Processing/Projections/UnknownProjectionCurrentStateType.cs b/Source/Events/Processing/Projections/UnknownProjectionCurrentStateType.cs similarity index 100% rename from Source/Events.Processing/Projections/UnknownProjectionCurrentStateType.cs rename to Source/Events/Processing/Projections/UnknownProjectionCurrentStateType.cs diff --git a/Source/Events.Processing/Projections/UnknownProjectionResultType.cs b/Source/Events/Processing/Projections/UnknownProjectionResultType.cs similarity index 100% rename from Source/Events.Processing/Projections/UnknownProjectionResultType.cs rename to Source/Events/Processing/Projections/UnknownProjectionResultType.cs diff --git a/Source/Events.Processing/Projections/ValidateOccurredFormat.cs b/Source/Events/Processing/Projections/ValidateOccurredFormat.cs similarity index 87% rename from Source/Events.Processing/Projections/ValidateOccurredFormat.cs rename to Source/Events/Processing/Projections/ValidateOccurredFormat.cs index dc7fdec31..d43ff5808 100644 --- a/Source/Events.Processing/Projections/ValidateOccurredFormat.cs +++ b/Source/Events/Processing/Projections/ValidateOccurredFormat.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using Dolittle.Runtime.Projections.Store.Definition; @@ -12,7 +13,7 @@ namespace Dolittle.Runtime.Events.Processing.Projections; /// public class ValidateOccurredFormat : IValidateOccurredFormat { - public bool IsValid(OccurredFormat format, out Exception error) + public bool IsValid(OccurredFormat format, [NotNullWhen(false)] out Exception? error) { try { diff --git a/Source/Events/Processing/SkippedProcessing.cs b/Source/Events/Processing/SkippedProcessing.cs new file mode 100644 index 000000000..94207c57d --- /dev/null +++ b/Source/Events/Processing/SkippedProcessing.cs @@ -0,0 +1,27 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Dolittle.Runtime.Events.Processing; + +/// +/// Represents a skipped event in the stream, used if the event partition is failing . +/// +public class SkippedProcessing : IProcessingResult +{ + public static readonly SkippedProcessing Instance = new(); + + /// + public bool Succeeded => true; + public bool Skipped => true; + + /// + public string FailureReason => string.Empty; + + /// + public bool Retry => false; + + /// + public TimeSpan RetryTimeout => TimeSpan.Zero; +} diff --git a/Source/Events.Processing/Streams/AbstractScopedStreamProcessor.cs b/Source/Events/Processing/Streams/AbstractScopedStreamProcessor.cs similarity index 92% rename from Source/Events.Processing/Streams/AbstractScopedStreamProcessor.cs rename to Source/Events/Processing/Streams/AbstractScopedStreamProcessor.cs index e2fdd6da4..9d563b8f9 100644 --- a/Source/Events.Processing/Streams/AbstractScopedStreamProcessor.cs +++ b/Source/Events/Processing/Streams/AbstractScopedStreamProcessor.cs @@ -30,11 +30,11 @@ public abstract class AbstractScopedStreamProcessor readonly IStreamEventWatcher _eventWaiter; readonly object _setPositionLock = new(); CancellationTokenSource? _resetStreamProcessor; - TaskCompletionSource>? _resetStreamProcessorCompletionSource; + TaskCompletionSource>? _resetStreamProcessorCompletionSource; Func> _resetStreamProcessorAction; IStreamProcessorState _currentState; bool _started; - StreamPosition _newPosition; + ProcessingPosition _newPosition; /// /// Initializes a new instance of the class. @@ -124,20 +124,20 @@ public Task Start(CancellationToken cancellationToken) /// The to start processing events from. /// The action to perform before setting the position. /// A that, when resolved, returns a with a . - public Task> PerformActionAndReprocessEventsFrom(StreamPosition position, Func> action) + public Task> PerformActionAndReprocessEventsFrom(ProcessingPosition position, Func> action) { try { if (_resetStreamProcessorCompletionSource != default) { - return Task.FromResult>(new AlreadySettingNewStreamProcessorPosition(Identifier)); + return Task.FromResult>(new AlreadySettingNewStreamProcessorPosition(Identifier)); } - var tcs = new TaskCompletionSource>(TaskCreationOptions.RunContinuationsAsynchronously); + var tcs = new TaskCompletionSource>(TaskCreationOptions.RunContinuationsAsynchronously); lock (_setPositionLock) { if (_resetStreamProcessorCompletionSource != default) { - return Task.FromResult>(new AlreadySettingNewStreamProcessorPosition(Identifier)); + return Task.FromResult>(new AlreadySettingNewStreamProcessorPosition(Identifier)); } _newPosition = position; _resetStreamProcessorAction = action; @@ -149,7 +149,7 @@ public Task> PerformActionAndReprocessEventsFrom(StreamPosit } catch (Exception ex) { - return Task.FromResult>(ex); + return Task.FromResult>(ex); } } @@ -188,14 +188,6 @@ public Task> PerformActionAndReprocessEventsFrom(StreamPosit /// A that, when resolved, returns the new . protected abstract Task OnFailedProcessingResult(FailedProcessing failedProcessing, StreamEvent processedEvent, IStreamProcessorState currentState); - /// - /// Tries to get the for when to retry processing. Outputs the maximum value if there is no retry time. - /// - /// The current .. - /// The for when to retry processsing a stream processor. - /// A value indicating whether there is a retry time. - protected abstract bool TryGetTimeToRetry(IStreamProcessorState state, out TimeSpan timeToRetry); - /// /// Creates a new with the given . /// @@ -247,7 +239,7 @@ protected virtual async Task ProcessEvents(IEnumerable<(S /// The . /// A that, when resolved, returns the . protected Task>> FetchNextEventsToProcess(IStreamProcessorState currentState, CancellationToken cancellationToken) - => _eventFetcherPolicies.Fetching.ExecuteAsync(_ => _eventsFetcher.Fetch(currentState.Position, _), cancellationToken); + => _eventFetcherPolicies.Fetching.ExecuteAsync(_ => _eventsFetcher.Fetch(currentState.Position.StreamPosition, _), cancellationToken); // TODO: Shouldn't this policy rather be used in the actual fetcher? /// @@ -259,7 +251,7 @@ protected TimeSpan GetTimeToRetryProcessing(IStreamProcessorState state) { var result = _eventWaiterTimeout; - if (TryGetTimeToRetry(state, out var timeToRetry)) + if (state.TryGetTimespanToRetry(out var timeToRetry)) { if (timeToRetry < result) { @@ -338,9 +330,9 @@ async Task BeginProcessing(CancellationToken cancellationToken) _resetStreamProcessor = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); if (_resetStreamProcessorCompletionSource != default) { - if (_newPosition > _currentState.Position) + if (_newPosition.StreamPosition > _currentState.Position.StreamPosition) { - _resetStreamProcessorCompletionSource.SetResult(Try.Failed(new CannotSetStreamProcessorPositionHigherThanCurrentPosition(Identifier, _currentState, _newPosition))); + _resetStreamProcessorCompletionSource.SetResult(Try.Failed(new CannotSetStreamProcessorPositionHigherThanCurrentPosition(Identifier, _currentState, _newPosition))); } else { @@ -348,14 +340,14 @@ async Task BeginProcessing(CancellationToken cancellationToken) var result = await _resetStreamProcessorAction(_tenantId, cancellationToken).ConfigureAwait(false); if (result.Success) { - Log.ScopedStreamProcessorSetToPosition(Logger, Identifier, _newPosition); - _currentState = await SetNewStateWithPosition(_currentState, _newPosition).ConfigureAwait(false); + Log.ScopedStreamProcessorSetToPosition(Logger, Identifier, _newPosition.StreamPosition); + _currentState = await SetNewStateWithPosition(_currentState, _newPosition.StreamPosition).ConfigureAwait(false); _resetStreamProcessorCompletionSource.SetResult(_currentState.Position); } else { Log.ScopedStreamProcessorPerformingSetToPositionActionFailed(Logger, Identifier, result.Exception); - _resetStreamProcessorCompletionSource.SetResult(Try.Failed(result.Exception)); + _resetStreamProcessorCompletionSource.SetResult(Try.Failed(result.Exception)); } } @@ -373,7 +365,7 @@ async Task BeginProcessing(CancellationToken cancellationToken) await _eventWaiter.WaitForEvent( Identifier.ScopeId, _sourceStreamDefinition.StreamId, - _currentState.Position, + _currentState.Position.StreamPosition, GetTimeToRetryProcessing(_currentState), _resetStreamProcessor.Token).ConfigureAwait(false); } diff --git a/Source/Events.Processing/Streams/AlreadySettingNewStreamProcessorPosition.cs b/Source/Events/Processing/Streams/AlreadySettingNewStreamProcessorPosition.cs similarity index 100% rename from Source/Events.Processing/Streams/AlreadySettingNewStreamProcessorPosition.cs rename to Source/Events/Processing/Streams/AlreadySettingNewStreamProcessorPosition.cs diff --git a/Source/Events.Processing/Streams/CannotCreateStreamProcessorOnUndefinedStream.cs b/Source/Events/Processing/Streams/CannotCreateStreamProcessorOnUndefinedStream.cs similarity index 100% rename from Source/Events.Processing/Streams/CannotCreateStreamProcessorOnUndefinedStream.cs rename to Source/Events/Processing/Streams/CannotCreateStreamProcessorOnUndefinedStream.cs diff --git a/Source/Events.Processing/Streams/CannotSetStreamProcessorPositionHigherThanCurrentPosition.cs b/Source/Events/Processing/Streams/CannotSetStreamProcessorPositionHigherThanCurrentPosition.cs similarity index 96% rename from Source/Events.Processing/Streams/CannotSetStreamProcessorPositionHigherThanCurrentPosition.cs rename to Source/Events/Processing/Streams/CannotSetStreamProcessorPositionHigherThanCurrentPosition.cs index d45bc4b51..9b2aa28f2 100644 --- a/Source/Events.Processing/Streams/CannotSetStreamProcessorPositionHigherThanCurrentPosition.cs +++ b/Source/Events/Processing/Streams/CannotSetStreamProcessorPositionHigherThanCurrentPosition.cs @@ -16,8 +16,8 @@ public class CannotSetStreamProcessorPositionHigherThanCurrentPosition : Excepti /// The . /// The current . /// The new . - public CannotSetStreamProcessorPositionHigherThanCurrentPosition(IStreamProcessorId streamProcessorId, IStreamProcessorState currentState, StreamPosition position) + public CannotSetStreamProcessorPositionHigherThanCurrentPosition(IStreamProcessorId streamProcessorId, IStreamProcessorState currentState, ProcessingPosition position) : base($"Stream Processor: '{streamProcessorId}' cannot be set to new position {position} because it is already at position {currentState.Position}") { } -} \ No newline at end of file +} diff --git a/Source/Events.Processing/Streams/CannotUnregisterRunningStreamProcessor.cs b/Source/Events/Processing/Streams/CannotUnregisterRunningStreamProcessor.cs similarity index 100% rename from Source/Events.Processing/Streams/CannotUnregisterRunningStreamProcessor.cs rename to Source/Events/Processing/Streams/CannotUnregisterRunningStreamProcessor.cs diff --git a/Source/Events.Processing/Streams/CreateScopedStreamProcessors.cs b/Source/Events/Processing/Streams/CreateScopedStreamProcessors.cs similarity index 85% rename from Source/Events.Processing/Streams/CreateScopedStreamProcessors.cs rename to Source/Events/Processing/Streams/CreateScopedStreamProcessors.cs index 1b386b24f..4da60b68f 100644 --- a/Source/Events.Processing/Streams/CreateScopedStreamProcessors.cs +++ b/Source/Events/Processing/Streams/CreateScopedStreamProcessors.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Dolittle.Runtime.DependencyInversion.Lifecycle; using Dolittle.Runtime.DependencyInversion.Scoping; -using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; @@ -19,8 +18,7 @@ namespace Dolittle.Runtime.Events.Processing.Streams; public class CreateScopedStreamProcessors : ICreateScopedStreamProcessors { readonly IEventFetchers _eventFetchers; - readonly IResilientStreamProcessorStateRepository _streamProcessorStates; - readonly IStreamEventWatcher _streamWatcher; + readonly IStreamProcessorStates _streamProcessorStates; readonly Func _createPartitionedStreamProcessor; readonly Func _createUnpartitionedStreamProcessor; @@ -34,14 +32,12 @@ public class CreateScopedStreamProcessors : ICreateScopedStreamProcessors /// The factory to use to create instances of unpartitioned stream processors. public CreateScopedStreamProcessors( IEventFetchers eventFetchers, - IResilientStreamProcessorStateRepository streamProcessorStates, - IStreamEventWatcher streamWatcher, + IStreamProcessorStates streamProcessorStates, Func createPartitionedStreamProcessor, Func createUnpartitionedStreamProcessor) { _eventFetchers = eventFetchers; _streamProcessorStates = streamProcessorStates; - _streamWatcher = streamWatcher; _createPartitionedStreamProcessor = createPartitionedStreamProcessor; _createUnpartitionedStreamProcessor = createUnpartitionedStreamProcessor; } @@ -85,7 +81,7 @@ public async Task Create( streamProcessor = _createUnpartitionedStreamProcessor(streamDefinition, streamProcessorId, eventFetcher, eventProcessor, unpartitionedProcessorState, executionContext); } - NotifyStream(streamProcessorId.ScopeId, streamDefinition, processorState.Position); + // NotifyStream(streamProcessorId.ScopeId, streamDefinition, processorState.Position); return streamProcessor; } @@ -103,19 +99,19 @@ async Task GetOrCreateStreamProcessorState(IStreamProcess return initialState; } - void NotifyStream(ScopeId scopeId, IStreamDefinition streamDefinition, StreamPosition position) - { - if (position == StreamPosition.Start) - { - return; - } - if (streamDefinition.Public) - { - _streamWatcher.NotifyForEvent(streamDefinition.StreamId, position - 1); - } - else - { - _streamWatcher.NotifyForEvent(scopeId, streamDefinition.StreamId, position - 1); - } - } + // void NotifyStream(ScopeId scopeId, IStreamDefinition streamDefinition, StreamPosition position) + // { + // if (position == StreamPosition.Start) + // { + // return; + // } + // if (streamDefinition.Public) + // { + // _streamWatcher.NotifyForEvent(streamDefinition.StreamId, position - 1); + // } + // else + // { + // _streamWatcher.NotifyForEvent(scopeId, streamDefinition.StreamId, position - 1); + // } + // } } diff --git a/Source/Events.Processing/Streams/EventFetcherPolicies.cs b/Source/Events/Processing/Streams/EventFetcherPolicies.cs similarity index 100% rename from Source/Events.Processing/Streams/EventFetcherPolicies.cs rename to Source/Events/Processing/Streams/EventFetcherPolicies.cs diff --git a/Source/Events.Processing/Streams/ExpectedPartitionedStreamProcessorState.cs b/Source/Events/Processing/Streams/ExpectedPartitionedStreamProcessorState.cs similarity index 100% rename from Source/Events.Processing/Streams/ExpectedPartitionedStreamProcessorState.cs rename to Source/Events/Processing/Streams/ExpectedPartitionedStreamProcessorState.cs diff --git a/Source/Events.Processing/Streams/ExpectedUnpartitionedStreamProcessorState.cs b/Source/Events/Processing/Streams/ExpectedUnpartitionedStreamProcessorState.cs similarity index 100% rename from Source/Events.Processing/Streams/ExpectedUnpartitionedStreamProcessorState.cs rename to Source/Events/Processing/Streams/ExpectedUnpartitionedStreamProcessorState.cs diff --git a/Source/Events.Processing/Streams/ICreateScopedStreamProcessors.cs b/Source/Events/Processing/Streams/ICreateScopedStreamProcessors.cs similarity index 100% rename from Source/Events.Processing/Streams/ICreateScopedStreamProcessors.cs rename to Source/Events/Processing/Streams/ICreateScopedStreamProcessors.cs diff --git a/Source/Events.Processing/Streams/IEventFetcherPolicies.cs b/Source/Events/Processing/Streams/IEventFetcherPolicies.cs similarity index 100% rename from Source/Events.Processing/Streams/IEventFetcherPolicies.cs rename to Source/Events/Processing/Streams/IEventFetcherPolicies.cs diff --git a/Source/Events.Processing/Streams/IMetricsCollector.cs b/Source/Events/Processing/Streams/IMetricsCollector.cs similarity index 100% rename from Source/Events.Processing/Streams/IMetricsCollector.cs rename to Source/Events/Processing/Streams/IMetricsCollector.cs diff --git a/Source/Events.Processing/Streams/IStreamProcessors.cs b/Source/Events/Processing/Streams/IStreamProcessors.cs similarity index 93% rename from Source/Events.Processing/Streams/IStreamProcessors.cs rename to Source/Events/Processing/Streams/IStreamProcessors.cs index 01efa3a10..41bc8613f 100644 --- a/Source/Events.Processing/Streams/IStreamProcessors.cs +++ b/Source/Events/Processing/Streams/IStreamProcessors.cs @@ -42,6 +42,7 @@ Try TryCreateAndRegister( ExecutionContext executionContext, CancellationToken cancellationToken); + /// /// Reprocesses all events for a from a for a tenant. @@ -50,7 +51,7 @@ Try TryCreateAndRegister( /// The . /// The . /// The that, when resolved, returns a with the it was set to. - Task> ReprocessEventsFrom(StreamProcessorId streamProcessorId, TenantId tenant, StreamPosition position); + Task> ReprocessEventsFrom(StreamProcessorId streamProcessorId, TenantId tenant, ProcessingPosition position); /// @@ -58,5 +59,5 @@ Try TryCreateAndRegister( /// /// The of the . /// The that, when resolved, returns a with a with the it was set to for each . - Task>>> ReprocessAllEvents(StreamProcessorId streamProcessorId); + Task>>> ReprocessAllEvents(StreamProcessorId streamProcessorId); } diff --git a/Source/Events.Processing/Streams/Log.cs b/Source/Events/Processing/Streams/Log.cs similarity index 100% rename from Source/Events.Processing/Streams/Log.cs rename to Source/Events/Processing/Streams/Log.cs diff --git a/Source/Events.Processing/Streams/MetricsCollector.cs b/Source/Events/Processing/Streams/MetricsCollector.cs similarity index 100% rename from Source/Events.Processing/Streams/MetricsCollector.cs rename to Source/Events/Processing/Streams/MetricsCollector.cs diff --git a/Source/Events/Processing/Streams/Partitioned/FailingPartitionState.cs b/Source/Events/Processing/Streams/Partitioned/FailingPartitionState.cs new file mode 100644 index 000000000..3f6082c32 --- /dev/null +++ b/Source/Events/Processing/Streams/Partitioned/FailingPartitionState.cs @@ -0,0 +1,55 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; + +namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned; + +/// +/// Represents the state of a failing partition. +/// +/// The . +/// The to retry processing. +/// The reason for failing. +/// The number of times the Event has been processed. +/// The for when this partition last failed. +public record FailingPartitionState(ProcessingPosition Position, DateTimeOffset RetryTime, string Reason, + uint ProcessingAttempts, DateTimeOffset LastFailed) +{ + public FailingPartitionState(StreamPosition position, EventLogSequenceNumber retryTime, DateTimeOffset toDateTimeOffset, string failureReason, + uint processingAttempts, DateTimeOffset dateTimeOffset) + : this(new ProcessingPosition(position, retryTime), toDateTimeOffset, failureReason, processingAttempts, dateTimeOffset) + { + } + + [Obsolete("legacy stream processor state, without event log position")] + public FailingPartitionState(StreamPosition streamPosition, DateTimeOffset retryTime, string reason, + uint processingAttempts, DateTimeOffset lastFailed) : this(new ProcessingPosition(streamPosition, EventLogSequenceNumber.Initial), retryTime, reason, + processingAttempts, lastFailed) + { + } + + public bool CanBeRetried => RetryTime < DateTimeOffset.MaxValue; + + public bool TryGetTimespanToRetry(out TimeSpan timeToRetry) + { + if (!CanBeRetried) + { + timeToRetry = default; + return false; + } + + var now = DateTimeOffset.UtcNow; + + if (RetryTime > now) + { + timeToRetry = RetryTime.Subtract(now); + return true; + } + + timeToRetry = TimeSpan.Zero; + return true; + } +} diff --git a/Source/Events.Processing/Streams/Partitioned/FailingPartitions.cs b/Source/Events/Processing/Streams/Partitioned/FailingPartitions.cs similarity index 86% rename from Source/Events.Processing/Streams/Partitioned/FailingPartitions.cs rename to Source/Events/Processing/Streams/Partitioned/FailingPartitions.cs index eb5123fed..8eac76ea3 100644 --- a/Source/Events.Processing/Streams/Partitioned/FailingPartitions.cs +++ b/Source/Events/Processing/Streams/Partitioned/FailingPartitions.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -17,7 +18,7 @@ namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned; /// public class FailingPartitions : IFailingPartitions { - readonly IResilientStreamProcessorStateRepository _streamProcessorStates; + readonly IStreamProcessorStates _streamProcessorStates; readonly IEventProcessor _eventProcessor; readonly ICanFetchEventsFromPartitionedStream _eventsFromStreamsFetcher; readonly Func _createExecutionContextForEvent; @@ -26,16 +27,16 @@ public class FailingPartitions : IFailingPartitions /// /// Initializes a new instance of the class. /// - /// The . + /// The . /// The . /// The . /// The factory to use to create execution contexts for event processing. /// The policies to use for fetching events. public FailingPartitions( - IResilientStreamProcessorStateRepository streamProcessorStates, + IStreamProcessorStates streamProcessorStates, IEventProcessor eventProcessor, ICanFetchEventsFromPartitionedStream eventsFromStreamsFetcher, - Func createExecutionContextForEvent, //TODO: Oh man, here we go again. + Func createExecutionContextForEvent, IEventFetcherPolicies eventFetcherPolicies) { _streamProcessorStates = streamProcessorStates; @@ -45,6 +46,7 @@ public FailingPartitions( _eventFetcherPolicies = eventFetcherPolicies; } + /// public async Task AddFailingPartitionFor( IStreamProcessorId streamProcessorId, @@ -59,8 +61,9 @@ public async Task AddFailingPartitionFor( var failingPartitions = new Dictionary(oldState.FailingPartitions) { [partition] = failingPartition - }; - var newState = new StreamProcessorState(failedPosition + 1, failingPartitions, oldState.LastSuccessfullyProcessed); + }.ToImmutableDictionary(); + StreamPosition streamPosition = failedPosition + 1; + var newState = new StreamProcessorState(streamPosition, failingPartitions, oldState.LastSuccessfullyProcessed); await PersistNewState(streamProcessorId, newState, cancellationToken).ConfigureAwait(false); return newState; } @@ -71,12 +74,6 @@ public async Task CatchupFor( StreamProcessorState streamProcessorState, CancellationToken cancellationToken) { - if (streamProcessorState.FailingPartitions.Count > 0) - { - streamProcessorState = (await _streamProcessorStates.TryGetFor(streamProcessorId, cancellationToken) - .ConfigureAwait(false)).Result as StreamProcessorState; - } - var failingPartitionsList = streamProcessorState.FailingPartitions.ToList(); foreach (var kvp in failingPartitionsList) @@ -87,16 +84,15 @@ public async Task CatchupFor( return streamProcessorState; } - async Task ProcessPartition(IStreamProcessorId streamProcessorId, StreamProcessorState streamProcessorState, - KeyValuePair kvp, CancellationToken cancellationToken) + async Task ProcessPartition(IStreamProcessorId streamProcessorId, StreamProcessorState streamProcessorState, KeyValuePair kvp, + CancellationToken cancellationToken) { var partition = kvp.Key; var failingPartitionState = kvp.Value; - while (IsBeforeCurrentHighWatermark(failingPartitionState.Position, streamProcessorState.Position) && ShouldRetryProcessing(failingPartitionState)) + while (IsBeforeCurrentHighWatermark(failingPartitionState.Position.StreamPosition, streamProcessorState.Position.StreamPosition) && + ShouldRetryProcessing(failingPartitionState)) { - var tryGetEvents = await _eventFetcherPolicies.Fetching.ExecuteAsync( - _ => _eventsFromStreamsFetcher.FetchInPartition(partition, failingPartitionState.Position, _), - cancellationToken).ConfigureAwait(false); + var tryGetEvents = await _eventsFromStreamsFetcher.FetchInPartition(partition, failingPartitionState.Position.StreamPosition, cancellationToken); if (!tryGetEvents.Success) { break; @@ -109,7 +105,7 @@ async Task ProcessPartition(IStreamProcessorId streamProce throw new StreamEventInWrongPartition(streamEvent, partition); } - if (!IsBeforeCurrentHighWatermark(streamEvent.Position, streamProcessorState.Position)) + if (!IsBeforeCurrentHighWatermark(streamEvent.Position, streamProcessorState.Position.StreamPosition)) { // We have caught up to the current high watermark // Remove the failing state for this partition @@ -184,11 +180,7 @@ async Task ProcessPartition(IStreamProcessorId streamProce async Task RemoveFailingPartition(IStreamProcessorId streamProcessorId, StreamProcessorState oldState, PartitionId partition, CancellationToken cancellationToken) { - var newFailingPartitions = oldState.FailingPartitions; - newFailingPartitions.Remove(partition); - var newState = new StreamProcessorState(oldState.Position, newFailingPartitions, oldState.LastSuccessfullyProcessed); - oldState.FailingPartitions.Remove(partition); - + var newState = oldState with { FailingPartitions = oldState.FailingPartitions.Remove(partition) }; await PersistNewState(streamProcessorId, newState, cancellationToken).ConfigureAwait(false); return newState; } @@ -227,10 +219,9 @@ async Task RemoveFailingPartition(IStreamProcessorId strea CancellationToken cancellationToken) { var newFailingPartitionState = new FailingPartitionState(position, retryTime, reason, processingAttempts, lastFailed); - var newFailingPartitions = oldState.FailingPartitions; - newFailingPartitions[partitionId] = newFailingPartitionState; + var newFailingPartitions = oldState.FailingPartitions.SetItem(partitionId,newFailingPartitionState); - var newState = position > oldState.FailingPartitions[partitionId].Position + var newState = position > oldState.FailingPartitions[partitionId].Position.StreamPosition ? new StreamProcessorState(oldState.Position, newFailingPartitions, DateTimeOffset.UtcNow) : new StreamProcessorState(oldState.Position, newFailingPartitions, oldState.LastSuccessfullyProcessed); diff --git a/Source/Events.Processing/Streams/Partitioned/IFailingPartitions.cs b/Source/Events/Processing/Streams/Partitioned/IFailingPartitions.cs similarity index 100% rename from Source/Events.Processing/Streams/Partitioned/IFailingPartitions.cs rename to Source/Events/Processing/Streams/Partitioned/IFailingPartitions.cs diff --git a/Source/Events.Processing/Streams/Partitioned/ScopedStreamProcessor.cs b/Source/Events/Processing/Streams/Partitioned/ScopedStreamProcessor.cs similarity index 84% rename from Source/Events.Processing/Streams/Partitioned/ScopedStreamProcessor.cs rename to Source/Events/Processing/Streams/Partitioned/ScopedStreamProcessor.cs index efd2ea3b5..f0c1f5ace 100644 --- a/Source/Events.Processing/Streams/Partitioned/ScopedStreamProcessor.cs +++ b/Source/Events/Processing/Streams/Partitioned/ScopedStreamProcessor.cs @@ -3,10 +3,12 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; using Microsoft.Extensions.Logging; using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; @@ -18,9 +20,8 @@ namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned; /// public class ScopedStreamProcessor : AbstractScopedStreamProcessor { - readonly IResilientStreamProcessorStateRepository _streamProcessorStates; + readonly IStreamProcessorStates _streamProcessorStates; readonly IFailingPartitions _failingPartitions; - readonly ICanGetTimeToRetryFor _timeToRetryGetter; /// /// Initializes a new instance of the class. @@ -30,7 +31,7 @@ public class ScopedStreamProcessor : AbstractScopedStreamProcessor /// The source stream . /// The . /// An to process the event. - /// The . + /// The . /// The. /// The of the stream processor. /// The factory to use to create the . @@ -44,33 +45,32 @@ public ScopedStreamProcessor( IStreamDefinition sourceStreamDefinition, StreamProcessorState initialState, IEventProcessor processor, - IResilientStreamProcessorStateRepository streamProcessorStates, + IStreamProcessorStates streamProcessorStates, ICanFetchEventsFromPartitionedStream eventsFromStreamsFetcher, ExecutionContext executionContext, Func, IFailingPartitions> failingPartitionsFactory, IEventFetcherPolicies eventFetcherPolicies, IStreamEventWatcher streamWatcher, - ICanGetTimeToRetryFor timeToRetryGetter, ILogger logger) : base(tenantId, streamProcessorId, sourceStreamDefinition, initialState, processor, eventsFromStreamsFetcher, executionContext, eventFetcherPolicies, streamWatcher, logger) { _streamProcessorStates = streamProcessorStates; _failingPartitions = failingPartitionsFactory(processor, eventsFromStreamsFetcher, GetExecutionContextForEvent); - _timeToRetryGetter = timeToRetryGetter; } /// - protected override async Task ProcessEvents(IEnumerable<(StreamEvent, ExecutionContext)> events, IStreamProcessorState currentState, CancellationToken cancellationToken) + protected override async Task ProcessEvents(IEnumerable<(StreamEvent, ExecutionContext)> events, IStreamProcessorState currentState, + CancellationToken cancellationToken) { var streamProcessorState = currentState as StreamProcessorState; - + foreach (var (@event, executionContext) in events) { if (streamProcessorState.FailingPartitions.ContainsKey(@event.Partition)) { var newState = streamProcessorState with { - Position = @event.Position + 1 + Position = new ProcessingPosition(@event.Position.Increment(), EventLogSequenceNumber.Initial) }; await _streamProcessorStates.Persist(Identifier, newState, CancellationToken.None).ConfigureAwait(false); streamProcessorState = newState; @@ -81,7 +81,7 @@ protected override async Task ProcessEvents(IEnumerable<( streamProcessorState = newState as StreamProcessorState; } } - + return streamProcessorState; } @@ -112,7 +112,8 @@ protected override Task OnRetryProcessingResult(FailedPro CancellationToken.None); /// - protected override async Task OnSuccessfulProcessingResult(SuccessfulProcessing successfulProcessing, StreamEvent processedEvent, IStreamProcessorState currentState) + protected override async Task OnSuccessfulProcessingResult(SuccessfulProcessing successfulProcessing, StreamEvent processedEvent, + IStreamProcessorState currentState) { var oldState = currentState as StreamProcessorState; var newState = new StreamProcessorState(processedEvent.Position + 1, oldState.FailingPartitions, DateTimeOffset.UtcNow); @@ -120,24 +121,24 @@ protected override async Task OnSuccessfulProcessingResul return newState; } - /// - protected override bool TryGetTimeToRetry(IStreamProcessorState state, out TimeSpan timeToRetry) - => _timeToRetryGetter.TryGetTimespanToRetry(state as StreamProcessorState, out timeToRetry); + /// + protected bool TryGetTimeToRetry(IStreamProcessorState state, out TimeSpan timeToRetry) + => state.TryGetTimespanToRetry(out timeToRetry); /// protected override async Task SetNewStateWithPosition(IStreamProcessorState currentState, StreamPosition position) { var state = currentState as StreamProcessorState; var newState = new StreamProcessorState( - position, + position, FailingPartitionsIgnoringPartitionsToReprocess(state, position), state.LastSuccessfullyProcessed); await _streamProcessorStates.Persist(Identifier, newState, CancellationToken.None).ConfigureAwait(false); return newState; } - - static IDictionary FailingPartitionsIgnoringPartitionsToReprocess(StreamProcessorState state, StreamPosition position) + + static ImmutableDictionary FailingPartitionsIgnoringPartitionsToReprocess(StreamProcessorState state, StreamPosition position) => state.FailingPartitions - .Where(_ => _.Value.Position < position) - .ToDictionary(_ => _.Key, _ => _.Value); + .Where(_ => _.Value.Position.StreamPosition < position) + .ToImmutableDictionary(_ => _.Key, _ => _.Value); } diff --git a/Source/Events.Processing/Streams/Partitioned/StreamEventInWrongPartition.cs b/Source/Events/Processing/Streams/Partitioned/StreamEventInWrongPartition.cs similarity index 100% rename from Source/Events.Processing/Streams/Partitioned/StreamEventInWrongPartition.cs rename to Source/Events/Processing/Streams/Partitioned/StreamEventInWrongPartition.cs diff --git a/Source/Events/Processing/Streams/Partitioned/StreamProcessorState.cs b/Source/Events/Processing/Streams/Partitioned/StreamProcessorState.cs new file mode 100644 index 000000000..2e3182334 --- /dev/null +++ b/Source/Events/Processing/Streams/Partitioned/StreamProcessorState.cs @@ -0,0 +1,248 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Actors; +using Dolittle.Runtime.Events.Store.Streams; +using Google.Protobuf.WellKnownTypes; + +namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned; + +/// +/// Represents the state of an . +/// +/// The position of the stream. +/// The position of the stream. +/// The states of the failing partitions. +/// The for the last time when an Event in the Stream that the processes was processed successfully. +public record StreamProcessorState(ProcessingPosition Position, ImmutableDictionary FailingPartitions, + DateTimeOffset LastSuccessfullyProcessed) : IStreamProcessorState +{ + public StreamProcessorState(ProcessingPosition position, DateTimeOffset lastSuccessfullyProcessed) : this(position, + ImmutableDictionary.Empty, lastSuccessfullyProcessed) + { + } + + [Obsolete("legacy stream processor state, without event log position")] + public StreamProcessorState(StreamPosition streamPosition, ImmutableDictionary failingPartitions, + DateTimeOffset lastSuccessfullyProcessed) : + this(new ProcessingPosition(streamPosition, EventLogSequenceNumber.Initial), failingPartitions, lastSuccessfullyProcessed) + { + } + + /// + /// Gets a new, initial, . + /// + public static StreamProcessorState New => + new(ProcessingPosition.Initial, ImmutableDictionary.Empty, DateTimeOffset.MinValue); + + /// + public bool Partitioned => true; + + public Bucket ToProtobuf() => new() + { + BucketId = 0, + CurrentOffset = Position.StreamPosition.Value, + CurrentEventLogOffset = Position.EventLogPosition.Value, + LastSuccessfullyProcessed = Timestamp.FromDateTimeOffset(LastSuccessfullyProcessed), + Failures = + { + FailingPartitions.Select(_ => + { + var (eventSourceId, failingPartitionState) = _; + return new ProcessingFailure + { + EventSourceId = eventSourceId, + Offset = _.Value.Position.StreamPosition.Value, + EventLogOffset = _.Value.Position.EventLogPosition.Value, + FailureReason = failingPartitionState.Reason, + ProcessingAttempts = failingPartitionState.ProcessingAttempts, + RetryTime = Timestamp.FromDateTimeOffset(failingPartitionState.RetryTime), + LastFailed = Timestamp.FromDateTimeOffset(failingPartitionState.LastFailed) + }; + }) + }, + Partitioned = true + }; + + /// + /// Returns earliest processable position. + /// Will Skip over failing partitions without a retry time. + /// + public ProcessingPosition EarliestProcessingPosition => + FailingPartitions.Any() ? FailingPartitions.Where(_ => _.Value.CanBeRetried).Min(_ => _.Value.Position)! : Position; + + public bool TryGetTimespanToRetry(out TimeSpan timeToRetry) + { + timeToRetry = TimeSpan.MaxValue; + var failingStates = FailingPartitions; + if (failingStates.Count > 0) + { + var earliestRetryTime = failingStates.Min(_ => _.Value.RetryTime); + timeToRetry = RetryTimeIsInThePast(earliestRetryTime) ? TimeSpan.Zero : earliestRetryTime.Subtract(DateTimeOffset.UtcNow); + return true; + } + + return false; + } + + + public StreamProcessorState WithResult(IProcessingResult result, StreamEvent processedEvent, DateTimeOffset timestamp) + { + VerifyEventHasValidProcessingPosition(processedEvent); + + if (result.Retry) + { + return WithFailure(result, processedEvent, timestamp.Add(result.RetryTimeout), timestamp); + } + + if (result is SkippedProcessing) + { + return this with { Position = Position.IncrementWithStream() }; + } + + return result.Succeeded + ? WithSuccessfullyProcessed(processedEvent, timestamp) + : WithFailure(result, processedEvent, DateTimeOffset.MaxValue, timestamp); + } + + public StreamProcessorState WithFailure(IProcessingResult failedProcessing, StreamEvent processedEvent, DateTimeOffset retryAt, + DateTimeOffset lastProcessingAttempt = default) + { + if (failedProcessing.Succeeded) + { + throw new ArgumentException("Processing result cannot be successful when adding a failing partition", nameof(failedProcessing)); + } + + if (FailingPartitions.TryGetValue(processedEvent.Partition, out var failingPartitionState)) + { + return UpdateFailingPartition(failedProcessing, processedEvent, lastProcessingAttempt, failingPartitionState); + } + + return AddFailingPartitionFor( + this, + processedEvent.CurrentProcessingPosition, + processedEvent.Partition, + retryAt == default ? DateTimeOffset.MaxValue : retryAt, + failedProcessing.FailureReason, + lastProcessingAttempt == default ? DateTimeOffset.UtcNow : lastProcessingAttempt); + } + + void VerifyEventHasValidProcessingPosition(StreamEvent processedEvent) + { + if (processedEvent.CurrentProcessingPosition.StreamPosition == Position.StreamPosition) + { + return; + } + + if (!FailingPartitions.TryGetValue(processedEvent.Partition, out var failingPartitionState)) + { + throw new ArgumentException( + $"The processed event does not match the current position of the stream processor. Expected {Position}, got {processedEvent.CurrentProcessingPosition}", + nameof(processedEvent)); + } + + if (failingPartitionState.Position.StreamPosition <= processedEvent.CurrentProcessingPosition.StreamPosition) + { + return; + } + + throw new ArgumentException( + $"The processed event does not match the current position of the partition. Expected {failingPartitionState.Position}, got {processedEvent.CurrentProcessingPosition}", + nameof(processedEvent)); + } + + StreamProcessorState UpdateFailingPartition(IProcessingResult failedProcessing, StreamEvent processedEvent, DateTimeOffset retriedAt, + FailingPartitionState failingPartitionState) + { + var failingPartition = new FailingPartitionState( + Position: processedEvent.CurrentProcessingPosition, + RetryTime: failedProcessing.Retry ? retriedAt.Add(failedProcessing.RetryTimeout) : DateTimeOffset.MaxValue, + ProcessingAttempts: processedEvent.CurrentProcessingPosition.EventLogPosition == failingPartitionState.Position.EventLogPosition + ? failingPartitionState.ProcessingAttempts + 1 + : 1, + Reason: failedProcessing.FailureReason, + LastFailed: retriedAt); + return this with + { + FailingPartitions = FailingPartitions.SetItem(processedEvent.Partition, failingPartition) + }; + } + + public StreamProcessorState WithSuccessfullyProcessed(StreamEvent processedEvent, DateTimeOffset timestamp) + { + if (FailingPartitions.TryGetValue(processedEvent.Partition, out var failingPartitionState)) + { + if (Position.EventLogPosition <= processedEvent.CurrentProcessingPosition.EventLogPosition) + { + // Since the event log position is the same or higher than the failing partition state, we can remove the failing partition state + return new StreamProcessorState(Position: processedEvent.NextProcessingPosition, + FailingPartitions: FailingPartitions.Remove(processedEvent.Partition), LastSuccessfullyProcessed: timestamp); + } + + // There might be more events between this event and the current high watermark of processed events. + var failingPartition = failingPartitionState with + { + Position = processedEvent.NextProcessingPosition, + RetryTime = timestamp, + ProcessingAttempts = 0, + Reason = "behind" + }; + return this with + { + FailingPartitions = FailingPartitions.SetItem(processedEvent.Partition, failingPartition), LastSuccessfullyProcessed = timestamp + }; + } + + return this with + { + Position = processedEvent.NextProcessingPosition, + LastSuccessfullyProcessed = timestamp + }; + } + + static StreamProcessorState AddFailingPartitionFor( + StreamProcessorState oldState, + ProcessingPosition failedPosition, + PartitionId partition, + DateTimeOffset retryTime, + string reason, + DateTimeOffset lastFailed) + { + var failingPartition = new FailingPartitionState(failedPosition, retryTime, reason, 1, lastFailed); + var newState = new StreamProcessorState(failedPosition.IncrementWithStream(), oldState.FailingPartitions.SetItem(partition, failingPartition), + oldState.LastSuccessfullyProcessed); + return newState; + } + + bool RetryTimeIsInThePast(DateTimeOffset retryTime) + => DateTimeOffset.UtcNow.CompareTo(retryTime) >= 0; + + /// + /// Remove the previously failing partitions that are no longer failing. + /// + /// + /// + /// + public StreamProcessorState WithoutFailingPartitions(IEnumerable noLongerFailingPartitions) => + this with + { + FailingPartitions = FailingPartitions.RemoveRange(noLongerFailingPartitions) + }; + + public StreamProcessorState WithoutFailingPartition(PartitionId noLongerFailingPartition) => + this with + { + FailingPartitions = FailingPartitions.Remove(noLongerFailingPartition) + }; + + public StreamProcessorState WithFailingPartition(PartitionId partitionId, FailingPartitionState partitionState) => + this with + { + FailingPartitions = FailingPartitions.SetItem(partitionId, partitionState) + }; +} diff --git a/Source/Events/Processing/Streams/Partitioned/TimeToRetryForPartitionedStreamProcessor.cs b/Source/Events/Processing/Streams/Partitioned/TimeToRetryForPartitionedStreamProcessor.cs new file mode 100644 index 000000000..cc290f4ca --- /dev/null +++ b/Source/Events/Processing/Streams/Partitioned/TimeToRetryForPartitionedStreamProcessor.cs @@ -0,0 +1,31 @@ +// // Copyright (c) Dolittle. All rights reserved. +// // Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// using System; +// using System.Linq; +// +// namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned; +// +// /// +// /// Represents an implementation of . +// /// +// public class TimeToRetryForPartitionedStreamProcessor : ICanGetTimeToRetryFor +// { +// /// +// public bool TryGetTimespanToRetry(StreamProcessorState streamProcessorState, out TimeSpan timeToRetry) +// { +// timeToRetry = TimeSpan.MaxValue; +// var failingStates = streamProcessorState.FailingPartitions; +// if (failingStates.Count > 0) +// { +// var earliestRetryTime = failingStates.Min(_ => _.Value.RetryTime); +// timeToRetry = RetryTimeIsInThePast(earliestRetryTime) ? TimeSpan.Zero : earliestRetryTime.Subtract(DateTimeOffset.UtcNow); +// return true; +// } +// +// return false; +// } +// +// bool RetryTimeIsInThePast(DateTimeOffset retryTime) +// => DateTimeOffset.UtcNow.CompareTo(retryTime) >= 0; +// } diff --git a/Source/Events.Processing/Streams/ScopedStreamProcessor.cs b/Source/Events/Processing/Streams/ScopedStreamProcessor.cs similarity index 76% rename from Source/Events.Processing/Streams/ScopedStreamProcessor.cs rename to Source/Events/Processing/Streams/ScopedStreamProcessor.cs index 4c97a414c..d86ffae4e 100644 --- a/Source/Events.Processing/Streams/ScopedStreamProcessor.cs +++ b/Source/Events/Processing/Streams/ScopedStreamProcessor.cs @@ -17,8 +17,7 @@ namespace Dolittle.Runtime.Events.Processing.Streams; /// public class ScopedStreamProcessor : AbstractScopedStreamProcessor { - readonly IResilientStreamProcessorStateRepository _streamProcessorStates; - readonly ICanGetTimeToRetryFor _timeToRetryGetter; + readonly IStreamProcessorStates _streamProcessorStates; /// /// Initializes a new instance of the class. @@ -28,7 +27,7 @@ public class ScopedStreamProcessor : AbstractScopedStreamProcessor /// The source stream . /// The . /// An to process the event. - /// The . + /// The . /// The. /// The of the stream processor. /// The policies to use while fetching events. @@ -41,17 +40,15 @@ public ScopedStreamProcessor( IStreamDefinition sourceStreamDefinition, StreamProcessorState initialState, IEventProcessor processor, - IResilientStreamProcessorStateRepository streamProcessorStates, + IStreamProcessorStates streamProcessorStates, ICanFetchEventsFromStream eventsFromStreamsFetcher, ExecutionContext executionContext, IEventFetcherPolicies eventFetcherPolicies, IStreamEventWatcher eventWatcher, - ICanGetTimeToRetryFor timeToRetryGetter, ILogger logger) : base(tenantId, streamProcessorId, sourceStreamDefinition, initialState, processor, eventsFromStreamsFetcher, executionContext, eventFetcherPolicies, eventWatcher, logger) { _streamProcessorStates = streamProcessorStates; - _timeToRetryGetter = timeToRetryGetter; } /// @@ -78,7 +75,7 @@ protected override async Task Catchup(IStreamProcessorSta } var eventToRetry = getNextEvents.Result.First(); - + var executionContext = GetExecutionContextForEvent(eventToRetry); streamProcessorState = await RetryProcessingEvent( eventToRetry, @@ -92,7 +89,9 @@ protected override async Task Catchup(IStreamProcessorSta { continue; } - var newStreamProcessorState = await ProcessEvents(getNextEvents.Result.Skip(1).Select(_ => (_, GetExecutionContextForEvent(_))), streamProcessorState, cancellationToken).ConfigureAwait(false); + + var newStreamProcessorState = await ProcessEvents(getNextEvents.Result.Skip(1).Select(_ => (_, GetExecutionContextForEvent(_))), + streamProcessorState, cancellationToken).ConfigureAwait(false); streamProcessorState = newStreamProcessorState as StreamProcessorState; } } @@ -101,52 +100,38 @@ protected override async Task Catchup(IStreamProcessorSta } /// - protected override async Task OnFailedProcessingResult(FailedProcessing failedProcessing, StreamEvent processedEvent, IStreamProcessorState currentState) + protected override async Task OnFailedProcessingResult(FailedProcessing failedProcessing, StreamEvent processedEvent, + IStreamProcessorState currentState) { - var oldState = currentState as StreamProcessorState; - var newState = new StreamProcessorState( - oldState.Position, - failedProcessing.FailureReason, - DateTimeOffset.MaxValue, - oldState.ProcessingAttempts + 1, - oldState.LastSuccessfullyProcessed, - true); + var newState = currentState.WithFailure(failedProcessing, processedEvent, DateTimeOffset.MaxValue, DateTimeOffset.UtcNow); await _streamProcessorStates.Persist(Identifier, newState, CancellationToken.None).ConfigureAwait(false); return newState; } /// - protected override async Task OnRetryProcessingResult(FailedProcessing failedProcessing, StreamEvent processedEvent, IStreamProcessorState currentState) + protected override async Task OnRetryProcessingResult(FailedProcessing failedProcessing, StreamEvent processedEvent, + IStreamProcessorState currentState) { - var oldState = currentState as StreamProcessorState; - var newState = new StreamProcessorState( - oldState.Position, - failedProcessing.FailureReason, - DateTimeOffset.UtcNow.Add(failedProcessing.RetryTimeout), - oldState.ProcessingAttempts + 1, - oldState.LastSuccessfullyProcessed, - true); + var newState = currentState.WithFailure(failedProcessing, processedEvent, DateTimeOffset.UtcNow.Add(failedProcessing.RetryTimeout), DateTimeOffset.UtcNow); await _streamProcessorStates.Persist(Identifier, newState, CancellationToken.None).ConfigureAwait(false); return newState; } /// - protected override async Task OnSuccessfulProcessingResult(SuccessfulProcessing successfulProcessing, StreamEvent processedEvent, IStreamProcessorState currentState) + protected override async Task OnSuccessfulProcessingResult(SuccessfulProcessing successfulProcessing, StreamEvent processedEvent, + IStreamProcessorState currentState) { - var newState = new StreamProcessorState(processedEvent.Position + 1, DateTimeOffset.UtcNow); + var newState = currentState.WithSuccessfullyProcessed(processedEvent, DateTimeOffset.UtcNow); await _streamProcessorStates.Persist(Identifier, newState, CancellationToken.None).ConfigureAwait(false); return newState; } - /// - protected override bool TryGetTimeToRetry(IStreamProcessorState state, out TimeSpan timeToRetry) - => _timeToRetryGetter.TryGetTimespanToRetry(state as StreamProcessorState, out timeToRetry); - - /// protected override async Task SetNewStateWithPosition(IStreamProcessorState currentState, StreamPosition position) { - var newState = new StreamProcessorState(position, ((StreamProcessorState)currentState).LastSuccessfullyProcessed); + // + var newState = new StreamProcessorState(position, + ((StreamProcessorState)currentState).LastSuccessfullyProcessed); await _streamProcessorStates.Persist(Identifier, newState, CancellationToken.None).ConfigureAwait(false); return newState; } diff --git a/Source/Events.Processing/Streams/ScopedStreamProcessorFailedToProcessEvent.cs b/Source/Events/Processing/Streams/ScopedStreamProcessorFailedToProcessEvent.cs similarity index 100% rename from Source/Events.Processing/Streams/ScopedStreamProcessorFailedToProcessEvent.cs rename to Source/Events/Processing/Streams/ScopedStreamProcessorFailedToProcessEvent.cs diff --git a/Source/Events.Processing/Streams/ScopedStreamProcessorProcessedEvent.cs b/Source/Events/Processing/Streams/ScopedStreamProcessorProcessedEvent.cs similarity index 100% rename from Source/Events.Processing/Streams/ScopedStreamProcessorProcessedEvent.cs rename to Source/Events/Processing/Streams/ScopedStreamProcessorProcessedEvent.cs diff --git a/Source/Events.Processing/Streams/Services.cs b/Source/Events/Processing/Streams/Services.cs similarity index 88% rename from Source/Events.Processing/Streams/Services.cs rename to Source/Events/Processing/Streams/Services.cs index fe08b4432..4e32d49f5 100644 --- a/Source/Events.Processing/Streams/Services.cs +++ b/Source/Events/Processing/Streams/Services.cs @@ -23,6 +23,6 @@ public class TenantServices : ICanAddTenantServices { public void AddFor(TenantId tenant, IServiceCollection services) { - services.AddTransient(); + // services.AddTransient(); } } diff --git a/Source/Events.Processing/Streams/StreamProcessor.cs b/Source/Events/Processing/Streams/StreamProcessor.cs similarity index 82% rename from Source/Events.Processing/Streams/StreamProcessor.cs rename to Source/Events/Processing/Streams/StreamProcessor.cs index 613979bbb..70ee99ddb 100644 --- a/Source/Events.Processing/Streams/StreamProcessor.cs +++ b/Source/Events/Processing/Streams/StreamProcessor.cs @@ -15,10 +15,33 @@ namespace Dolittle.Runtime.Events.Processing.Streams; +public interface IStreamProcessor +{ + /// + /// Gets all current states. + /// + /// The per . + Try> GetCurrentStates(); + + /// + /// Sets the position of the stream processor for a tenant. + /// + /// The . + /// The . + /// The that, when resolved, returns a with the it was set to. + Task> SetToPosition(TenantId tenant, ProcessingPosition position); + + /// + /// Sets the position of the stream processors for all tenant to be the initial . + /// + /// The that, when resolved, returns a with a with the it was set to for each . + Task>> SetToInitialPositionForAllTenants(); +} + /// /// Represents a system for working with all the registered for . /// -public class StreamProcessor : IDisposable +public class StreamProcessor : IDisposable, IStreamProcessor { readonly StreamProcessorId _identifier; readonly EventProcessorKind _eventProcessorKind; @@ -40,12 +63,13 @@ public class StreamProcessor : IDisposable /// Initializes a new instance of the class. /// /// The identifier of the stream processor. - /// The kind of the event processor. + /// The kind of the event processor. /// The definition of the stream the processor should process events from. /// The performer to use to create scoped stream processors for all tenants. /// The factory to use to create an event processor per tenant. /// The factory to us to get the scoped stream processor creator per tenant. /// The callback to call to unregister the stream processor when it completes or fails. + /// /// The logger to use for logging. /// The execution context to run the processor in. /// The cancellation token that is cancelled when the stream processor should stop processing. @@ -181,15 +205,15 @@ public async Task Start() /// The . /// The . /// The that, when resolved, returns a with the it was set to. - public Task> SetToPosition(TenantId tenant, StreamPosition position) - => PerformActionAndSetToPosition(tenant, position, (_, _) => Task.FromResult(Try.Succeeded())); + public Task> SetToPosition(TenantId tenant, ProcessingPosition position) + => PerformActionAndSetToPosition(tenant, position, (_, _) => Task.FromResult(Try.Succeeded)); /// /// Sets the position of the stream processors for all tenant to be the initial . /// /// The that, when resolved, returns a with a with the it was set to for each . - public Task>> SetToInitialPositionForAllTenants() - => PerformActionAndSetToInitialPositionForAllTenants((_, _) => Task.FromResult(Try.Succeeded())); + public Task>> SetToInitialPositionForAllTenants() + => PerformActionAndSetToInitialPositionForAllTenants((_, _) => Task.FromResult(Try.Succeeded)); /// /// Performs an action, then sets the position of the stream processor for a tenant. @@ -198,11 +222,11 @@ public Task>> SetToInitialPositionForA /// The . /// The action to perform before setting the position. /// The that, when resolved, returns a with the it was set to. - public Task> PerformActionAndSetToPosition(TenantId tenant, StreamPosition position, Func> action) + public Task> PerformActionAndSetToPosition(TenantId tenant, ProcessingPosition position, Func> action) { if (!_streamProcessors.TryGetValue(tenant, out var streamProcessor)) { - return Task.FromResult>(new StreamProcessorNotRegisteredForTenant(_identifier, tenant)); + return Task.FromResult>(new StreamProcessorNotRegisteredForTenant(_identifier, tenant)); } _metrics.IncrementPositionSet(_eventProcessorKind); @@ -214,14 +238,14 @@ public Task> PerformActionAndSetToPosition(TenantId tenant, /// /// The action to perform before setting the position. /// The that, when resolved, returns a with a with the it was set to for each . - public async Task>> PerformActionAndSetToInitialPositionForAllTenants(Func> action) + public async Task>> PerformActionAndSetToInitialPositionForAllTenants(Func> action) { _metrics.IncrementInitialPositionSetForAllTenants(_eventProcessorKind); var tasks = _streamProcessors - .ToDictionary(_ => _.Key, _ => _.Value.PerformActionAndReprocessEventsFrom(StreamPosition.Start, action)); + .ToDictionary(_ => _.Key, _ => _.Value.PerformActionAndReprocessEventsFrom(ProcessingPosition.Initial, action)); - var result = new Dictionary>(); + var result = new Dictionary>(); foreach (var (tenant, task) in tasks) { diff --git a/Source/Events.Processing/Streams/StreamProcessorAlreadyInitialized.cs b/Source/Events/Processing/Streams/StreamProcessorAlreadyInitialized.cs similarity index 100% rename from Source/Events.Processing/Streams/StreamProcessorAlreadyInitialized.cs rename to Source/Events/Processing/Streams/StreamProcessorAlreadyInitialized.cs diff --git a/Source/Events.Processing/Streams/StreamProcessorAlreadyProcessingStream.cs b/Source/Events/Processing/Streams/StreamProcessorAlreadyProcessingStream.cs similarity index 100% rename from Source/Events.Processing/Streams/StreamProcessorAlreadyProcessingStream.cs rename to Source/Events/Processing/Streams/StreamProcessorAlreadyProcessingStream.cs diff --git a/Source/Events.Processing/Streams/StreamProcessorAlreadyRegistered.cs b/Source/Events/Processing/Streams/StreamProcessorAlreadyRegistered.cs similarity index 100% rename from Source/Events.Processing/Streams/StreamProcessorAlreadyRegistered.cs rename to Source/Events/Processing/Streams/StreamProcessorAlreadyRegistered.cs diff --git a/Source/Events.Processing/Streams/StreamProcessorFailedToProcessEvent.cs b/Source/Events/Processing/Streams/StreamProcessorFailedToProcessEvent.cs similarity index 100% rename from Source/Events.Processing/Streams/StreamProcessorFailedToProcessEvent.cs rename to Source/Events/Processing/Streams/StreamProcessorFailedToProcessEvent.cs diff --git a/Source/Events.Processing/Streams/StreamProcessorNotInitialized.cs b/Source/Events/Processing/Streams/StreamProcessorNotInitialized.cs similarity index 100% rename from Source/Events.Processing/Streams/StreamProcessorNotInitialized.cs rename to Source/Events/Processing/Streams/StreamProcessorNotInitialized.cs diff --git a/Source/Events.Processing/Streams/StreamProcessorNotRegistered.cs b/Source/Events/Processing/Streams/StreamProcessorNotRegistered.cs similarity index 100% rename from Source/Events.Processing/Streams/StreamProcessorNotRegistered.cs rename to Source/Events/Processing/Streams/StreamProcessorNotRegistered.cs diff --git a/Source/Events.Processing/Streams/StreamProcessorNotRegisteredForTenant.cs b/Source/Events/Processing/Streams/StreamProcessorNotRegisteredForTenant.cs similarity index 100% rename from Source/Events.Processing/Streams/StreamProcessorNotRegisteredForTenant.cs rename to Source/Events/Processing/Streams/StreamProcessorNotRegisteredForTenant.cs diff --git a/Source/Events.Processing/Streams/StreamProcessorProcessedEvent.cs b/Source/Events/Processing/Streams/StreamProcessorProcessedEvent.cs similarity index 100% rename from Source/Events.Processing/Streams/StreamProcessorProcessedEvent.cs rename to Source/Events/Processing/Streams/StreamProcessorProcessedEvent.cs diff --git a/Source/Events/Processing/Streams/StreamProcessorState.cs b/Source/Events/Processing/Streams/StreamProcessorState.cs new file mode 100644 index 000000000..9cf568c78 --- /dev/null +++ b/Source/Events/Processing/Streams/StreamProcessorState.cs @@ -0,0 +1,178 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Actors; +using Dolittle.Runtime.Events.Store.Streams; +using Google.Protobuf.WellKnownTypes; + +namespace Dolittle.Runtime.Events.Processing.Streams; + +/// +/// Represents the state of an . +/// +/// The position of the stream. +/// The reason for failing. +/// The for when to retry processing. +/// The number of times it has processed the Event at . +/// Timestamp of last successful Stream process. +/// Whether the stream processor is failing. +public record StreamProcessorState(ProcessingPosition Position, string FailureReason, DateTimeOffset RetryTime, + uint ProcessingAttempts, + DateTimeOffset LastSuccessfullyProcessed, bool IsFailing) : IStreamProcessorState +{ + // /// + // /// Represents the state of an . + // /// + // /// The position of the stream. + // /// The reason for failing. + // /// The for when to retry processing. + // /// The number of times it has processed the Event at . + // /// Timestamp of last successful Stream process. + // /// Whether the stream processor is failing. + // public StreamProcessorState(ProcessingPosition position, string failureReason, DateTimeOffset retryTime, + // uint processingAttempts, + // DateTimeOffset lastSuccessfullyProcessed, bool isFailing) : this(position, failureReason, retryTime, + // processingAttempts, lastSuccessfullyProcessed, isFailing) + // { + // } + + + /// + /// Initializes a new instance of the class. + /// + /// The position of the stream. + /// + /// Timestamp of last successful Stream process. + public StreamProcessorState(StreamPosition streamPosition, EventLogSequenceNumber eventLogPosition, DateTimeOffset lastSuccessfullyProcessed) : this( + new ProcessingPosition(streamPosition, eventLogPosition), string.Empty, + lastSuccessfullyProcessed, 0, lastSuccessfullyProcessed, false) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The position of the stream. + /// Timestamp of last successful Stream process. + public StreamProcessorState(ProcessingPosition position, DateTimeOffset lastSuccessfullyProcessed) : this(position, string.Empty, + lastSuccessfullyProcessed, 0, lastSuccessfullyProcessed, false) + { + } + + public StreamProcessorState(StreamPosition streamPosition, DateTimeOffset lastSuccessfullyProcessed) : this( + new ProcessingPosition(streamPosition, EventLogSequenceNumber.Initial), lastSuccessfullyProcessed) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The position of the stream. + /// + StreamProcessorState(StreamPosition streamPosition, EventLogSequenceNumber eventLogPosition) : this( + new ProcessingPosition(streamPosition, eventLogPosition), string.Empty, + DateTimeOffset.UtcNow, 0, DateTimeOffset.MinValue, false) + { + } + + // public ProcessingPosition ProcessingPosition => new(Position, EventLogPosition); + + /// + public bool Partitioned => false; + + public Bucket ToProtobuf() + { + var protobuf = new Bucket() + { + BucketId = 0, + CurrentOffset = Position.StreamPosition.Value, + CurrentEventLogOffset = Position.EventLogPosition.Value, + LastSuccessfullyProcessed = Timestamp.FromDateTimeOffset(LastSuccessfullyProcessed), + Partitioned = false + }; + if (IsFailing) + { + protobuf.Failures.Add(new ProcessingFailure() + { + EventSourceId = PartitionId.None, + FailureReason = FailureReason, + RetryTime = Timestamp.FromDateTimeOffset(RetryTime), + ProcessingAttempts = ProcessingAttempts, + LastFailed = Timestamp.FromDateTimeOffset(LastSuccessfullyProcessed) + }); + } + + return protobuf; + } + + public ProcessingPosition EarliestProcessingPosition => Position; + + public bool TryGetTimespanToRetry(out TimeSpan timeToRetry) + { + if (RetryTime == DateTimeOffset.MaxValue) + { + timeToRetry = TimeSpan.Zero; + return false; + } + timeToRetry = TimeSpan.MaxValue; + if (IsFailing) + { + var retryTime = RetryTime; + var timeSpan = retryTime.Subtract(DateTimeOffset.UtcNow); + timeToRetry = timeSpan < TimeSpan.Zero ? TimeSpan.Zero : timeSpan; + return true; + } + + return false; + } + + public StreamProcessorState WithResult(IProcessingResult result, StreamEvent processedEvent, DateTimeOffset timestamp) + { + VerifyEventHasValidProcessingPosition(processedEvent); + + if (result.Retry) + { + return WithFailure(result, processedEvent, timestamp.Add(result.RetryTimeout), timestamp); + } + + return result.Succeeded + ? WithSuccessfullyProcessed(processedEvent, timestamp) + : WithFailure(result, processedEvent, DateTimeOffset.MaxValue, timestamp); + } + + void VerifyEventHasValidProcessingPosition(StreamEvent processedEvent) + { + + + if (processedEvent.CurrentProcessingPosition.StreamPosition != Position.StreamPosition) + { + throw new ArgumentException($"The processed event does not match the current position of the stream processor. Expected {Position}, got {processedEvent.CurrentProcessingPosition}", nameof(processedEvent)); + } + } + + public StreamProcessorState WithFailure(IProcessingResult failedProcessing, StreamEvent processedEvent, DateTimeOffset retryAt, DateTimeOffset _) + { + if (failedProcessing.Succeeded) + { + throw new ArgumentException("Processing result cannot be successful when adding a failing partition", nameof(failedProcessing)); + } + + return this with + { + ProcessingAttempts = ProcessingAttempts + 1, + FailureReason = failedProcessing.FailureReason, + RetryTime = retryAt, + IsFailing = true + }; + } + + public StreamProcessorState WithSuccessfullyProcessed(StreamEvent processedEvent, DateTimeOffset timestamp) => + new StreamProcessorState(processedEvent.NextProcessingPosition, timestamp); + + bool RetryTimeIsInThePast(DateTimeOffset retryTime) + => DateTimeOffset.UtcNow.CompareTo(retryTime) >= 0; + + public static StreamProcessorState New => new(StreamPosition.Start, EventLogSequenceNumber.Initial); +} diff --git a/Source/Events.Processing/Streams/StreamProcessors.cs b/Source/Events/Processing/Streams/StreamProcessors.cs similarity index 89% rename from Source/Events.Processing/Streams/StreamProcessors.cs rename to Source/Events/Processing/Streams/StreamProcessors.cs index d70c14a74..21a7dd670 100644 --- a/Source/Events.Processing/Streams/StreamProcessors.cs +++ b/Source/Events/Processing/Streams/StreamProcessors.cs @@ -100,20 +100,20 @@ public Try TryCreateAndRegister( } /// - public Task> ReprocessEventsFrom(StreamProcessorId streamProcessorId, TenantId tenant, StreamPosition position) + public Task> ReprocessEventsFrom(StreamProcessorId streamProcessorId, TenantId tenant, ProcessingPosition position) => _streamProcessors.TryGetValue(streamProcessorId, out var streamProcessor) ? streamProcessor.SetToPosition(tenant, position) - : Task.FromResult>(new StreamProcessorNotRegistered(streamProcessorId)); + : Task.FromResult>(new StreamProcessorNotRegistered(streamProcessorId)); /// - public async Task>>> ReprocessAllEvents(StreamProcessorId streamProcessorId) + public async Task>>> ReprocessAllEvents(StreamProcessorId streamProcessorId) => _streamProcessors.TryGetValue(streamProcessorId, out var streamProcessor) - ? Try>>.Succeeded(await streamProcessor.SetToInitialPositionForAllTenants().ConfigureAwait(false)) + ? Try>>.Succeeded(await streamProcessor.SetToInitialPositionForAllTenants().ConfigureAwait(false)) : new StreamProcessorNotRegistered(streamProcessorId); void Unregister(StreamProcessorId id) { - StreamProcessor existing; + StreamProcessor? existing; do { _streamProcessors.TryRemove(id, out existing); diff --git a/Source/Events/Processing/Streams/TimeToRetryForUnpartitionedStreamProcessor.cs b/Source/Events/Processing/Streams/TimeToRetryForUnpartitionedStreamProcessor.cs new file mode 100644 index 000000000..2d5a027a4 --- /dev/null +++ b/Source/Events/Processing/Streams/TimeToRetryForUnpartitionedStreamProcessor.cs @@ -0,0 +1,29 @@ +// // Copyright (c) Dolittle. All rights reserved. +// // Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// using System; +// +// namespace Dolittle.Runtime.Events.Processing.Streams; +// +// /// +// /// Represents an implementation of . +// /// +// public class TimeToRetryForUnpartitionedStreamProcessor : ICanGetTimeToRetryFor +// { +// /// +// public bool TryGetTimespanToRetry(StreamProcessorState streamProcessorState, out TimeSpan timeToRetry) +// { +// timeToRetry = TimeSpan.MaxValue; +// if (streamProcessorState.IsFailing) +// { +// var retryTime = streamProcessorState.RetryTime; +// timeToRetry = RetryTimeIsInThePast(retryTime) ? TimeSpan.Zero : retryTime.Subtract(DateTimeOffset.UtcNow); +// return true; +// } +// +// return false; +// } +// +// bool RetryTimeIsInThePast(DateTimeOffset retryTime) +// => DateTimeOffset.UtcNow.CompareTo(retryTime) >= 0; +// } diff --git a/Source/Events.Processing/SuccessfulProcessing.cs b/Source/Events/Processing/SuccessfulProcessing.cs similarity index 89% rename from Source/Events.Processing/SuccessfulProcessing.cs rename to Source/Events/Processing/SuccessfulProcessing.cs index 3118ce44d..b03f158a0 100644 --- a/Source/Events.Processing/SuccessfulProcessing.cs +++ b/Source/Events/Processing/SuccessfulProcessing.cs @@ -10,6 +10,8 @@ namespace Dolittle.Runtime.Events.Processing; /// public class SuccessfulProcessing : IProcessingResult { + public static readonly SuccessfulProcessing Instance = new(); + /// public bool Succeeded => true; @@ -21,4 +23,4 @@ public class SuccessfulProcessing : IProcessingResult /// public TimeSpan RetryTimeout => TimeSpan.Zero; -} \ No newline at end of file +} diff --git a/Source/Projections.Store/Copies/IProjectionCopyStore.cs b/Source/Events/Projections/Store/Copies/IProjectionCopyStore.cs similarity index 100% rename from Source/Projections.Store/Copies/IProjectionCopyStore.cs rename to Source/Events/Projections/Store/Copies/IProjectionCopyStore.cs diff --git a/Source/Projections.Store/Definition/Copies/MongoDB/CollectionName.cs b/Source/Events/Projections/Store/Definition/Copies/MongoDB/CollectionName.cs similarity index 100% rename from Source/Projections.Store/Definition/Copies/MongoDB/CollectionName.cs rename to Source/Events/Projections/Store/Definition/Copies/MongoDB/CollectionName.cs diff --git a/Source/Projections.Store/Definition/Copies/MongoDB/ConversionBSONType.cs b/Source/Events/Projections/Store/Definition/Copies/MongoDB/ConversionBSONType.cs similarity index 100% rename from Source/Projections.Store/Definition/Copies/MongoDB/ConversionBSONType.cs rename to Source/Events/Projections/Store/Definition/Copies/MongoDB/ConversionBSONType.cs diff --git a/Source/Projections.Store/Definition/Copies/MongoDB/CopyToMongoDBSpecification.cs b/Source/Events/Projections/Store/Definition/Copies/MongoDB/CopyToMongoDBSpecification.cs similarity index 100% rename from Source/Projections.Store/Definition/Copies/MongoDB/CopyToMongoDBSpecification.cs rename to Source/Events/Projections/Store/Definition/Copies/MongoDB/CopyToMongoDBSpecification.cs diff --git a/Source/Projections.Store/Definition/Copies/MongoDB/InvalidMongoDBCollectionName.cs b/Source/Events/Projections/Store/Definition/Copies/MongoDB/InvalidMongoDBCollectionName.cs similarity index 100% rename from Source/Projections.Store/Definition/Copies/MongoDB/InvalidMongoDBCollectionName.cs rename to Source/Events/Projections/Store/Definition/Copies/MongoDB/InvalidMongoDBCollectionName.cs diff --git a/Source/Projections.Store/Definition/Copies/MongoDB/InvalidMongoDBFieldConversion.cs b/Source/Events/Projections/Store/Definition/Copies/MongoDB/InvalidMongoDBFieldConversion.cs similarity index 100% rename from Source/Projections.Store/Definition/Copies/MongoDB/InvalidMongoDBFieldConversion.cs rename to Source/Events/Projections/Store/Definition/Copies/MongoDB/InvalidMongoDBFieldConversion.cs diff --git a/Source/Projections.Store/Definition/Copies/MongoDB/PropertyConversion.cs b/Source/Events/Projections/Store/Definition/Copies/MongoDB/PropertyConversion.cs similarity index 100% rename from Source/Projections.Store/Definition/Copies/MongoDB/PropertyConversion.cs rename to Source/Events/Projections/Store/Definition/Copies/MongoDB/PropertyConversion.cs diff --git a/Source/Projections.Store/Definition/Copies/ProjectionCopySpecification.cs b/Source/Events/Projections/Store/Definition/Copies/ProjectionCopySpecification.cs similarity index 100% rename from Source/Projections.Store/Definition/Copies/ProjectionCopySpecification.cs rename to Source/Events/Projections/Store/Definition/Copies/ProjectionCopySpecification.cs diff --git a/Source/Projections.Store/Definition/Copies/ProjectionProperty.cs b/Source/Events/Projections/Store/Definition/Copies/ProjectionProperty.cs similarity index 100% rename from Source/Projections.Store/Definition/Copies/ProjectionProperty.cs rename to Source/Events/Projections/Store/Definition/Copies/ProjectionProperty.cs diff --git a/Source/Projections.Store/Definition/IProjectionDefinitions.cs b/Source/Events/Projections/Store/Definition/IProjectionDefinitions.cs similarity index 100% rename from Source/Projections.Store/Definition/IProjectionDefinitions.cs rename to Source/Events/Projections/Store/Definition/IProjectionDefinitions.cs diff --git a/Source/Projections.Store/Definition/KeySelectorExpression.cs b/Source/Events/Projections/Store/Definition/KeySelectorExpression.cs similarity index 100% rename from Source/Projections.Store/Definition/KeySelectorExpression.cs rename to Source/Events/Projections/Store/Definition/KeySelectorExpression.cs diff --git a/Source/Projections.Store/Definition/OccurredFormat.cs b/Source/Events/Projections/Store/Definition/OccurredFormat.cs similarity index 100% rename from Source/Projections.Store/Definition/OccurredFormat.cs rename to Source/Events/Projections/Store/Definition/OccurredFormat.cs diff --git a/Source/Projections.Store/Definition/ProjectEventKeySelectorType.cs b/Source/Events/Projections/Store/Definition/ProjectEventKeySelectorType.cs similarity index 100% rename from Source/Projections.Store/Definition/ProjectEventKeySelectorType.cs rename to Source/Events/Projections/Store/Definition/ProjectEventKeySelectorType.cs diff --git a/Source/Projections.Store/Definition/ProjectionDefinition.cs b/Source/Events/Projections/Store/Definition/ProjectionDefinition.cs similarity index 100% rename from Source/Projections.Store/Definition/ProjectionDefinition.cs rename to Source/Events/Projections/Store/Definition/ProjectionDefinition.cs diff --git a/Source/Projections.Store/Definition/ProjectionEventSelector.cs b/Source/Events/Projections/Store/Definition/ProjectionEventSelector.cs similarity index 100% rename from Source/Projections.Store/Definition/ProjectionEventSelector.cs rename to Source/Events/Projections/Store/Definition/ProjectionEventSelector.cs diff --git a/Source/Projections.Store/IMetricsCollector.cs b/Source/Events/Projections/Store/IMetricsCollector.cs similarity index 100% rename from Source/Projections.Store/IMetricsCollector.cs rename to Source/Events/Projections/Store/IMetricsCollector.cs diff --git a/Source/Projections.Store/IProjectionPersister.cs b/Source/Events/Projections/Store/IProjectionPersister.cs similarity index 100% rename from Source/Projections.Store/IProjectionPersister.cs rename to Source/Events/Projections/Store/IProjectionPersister.cs diff --git a/Source/Projections.Store/IProjectionStore.cs b/Source/Events/Projections/Store/IProjectionStore.cs similarity index 100% rename from Source/Projections.Store/IProjectionStore.cs rename to Source/Events/Projections/Store/IProjectionStore.cs diff --git a/Source/Projections.Store/Log.cs b/Source/Events/Projections/Store/Log.cs similarity index 100% rename from Source/Projections.Store/Log.cs rename to Source/Events/Projections/Store/Log.cs diff --git a/Source/Projections.Store/MetricsCollector.cs b/Source/Events/Projections/Store/MetricsCollector.cs similarity index 100% rename from Source/Projections.Store/MetricsCollector.cs rename to Source/Events/Projections/Store/MetricsCollector.cs diff --git a/Source/Projections.Store/ProjectionDefinitionDoesNotExist.cs b/Source/Events/Projections/Store/ProjectionDefinitionDoesNotExist.cs similarity index 100% rename from Source/Projections.Store/ProjectionDefinitionDoesNotExist.cs rename to Source/Events/Projections/Store/ProjectionDefinitionDoesNotExist.cs diff --git a/Source/Projections.Store/ProjectionId.cs b/Source/Events/Projections/Store/ProjectionId.cs similarity index 100% rename from Source/Projections.Store/ProjectionId.cs rename to Source/Events/Projections/Store/ProjectionId.cs diff --git a/Source/Projections.Store/ProjectionKey.cs b/Source/Events/Projections/Store/ProjectionKey.cs similarity index 100% rename from Source/Projections.Store/ProjectionKey.cs rename to Source/Events/Projections/Store/ProjectionKey.cs diff --git a/Source/Projections.Store/ProjectionPersister.cs b/Source/Events/Projections/Store/ProjectionPersister.cs similarity index 100% rename from Source/Projections.Store/ProjectionPersister.cs rename to Source/Events/Projections/Store/ProjectionPersister.cs diff --git a/Source/Projections.Store/ProjectionStateDoesNotExist.cs b/Source/Events/Projections/Store/ProjectionStateDoesNotExist.cs similarity index 100% rename from Source/Projections.Store/ProjectionStateDoesNotExist.cs rename to Source/Events/Projections/Store/ProjectionStateDoesNotExist.cs diff --git a/Source/Projections.Store/ProjectionStore.cs b/Source/Events/Projections/Store/ProjectionStore.cs similarity index 100% rename from Source/Projections.Store/ProjectionStore.cs rename to Source/Events/Projections/Store/ProjectionStore.cs diff --git a/Source/Projections.Store/ProjectionsUnavailable.cs b/Source/Events/Projections/Store/ProjectionsUnavailable.cs similarity index 100% rename from Source/Projections.Store/ProjectionsUnavailable.cs rename to Source/Events/Projections/Store/ProjectionsUnavailable.cs diff --git a/Source/Projections.Store/State/IProjectionStates.cs b/Source/Events/Projections/Store/State/IProjectionStates.cs similarity index 100% rename from Source/Projections.Store/State/IProjectionStates.cs rename to Source/Events/Projections/Store/State/IProjectionStates.cs diff --git a/Source/Projections.Store/State/ProjectionCurrentState.cs b/Source/Events/Projections/Store/State/ProjectionCurrentState.cs similarity index 100% rename from Source/Projections.Store/State/ProjectionCurrentState.cs rename to Source/Events/Projections/Store/State/ProjectionCurrentState.cs diff --git a/Source/Projections.Store/State/ProjectionCurrentStateType.cs b/Source/Events/Projections/Store/State/ProjectionCurrentStateType.cs similarity index 100% rename from Source/Projections.Store/State/ProjectionCurrentStateType.cs rename to Source/Events/Projections/Store/State/ProjectionCurrentStateType.cs diff --git a/Source/Projections.Store/State/ProjectionState.cs b/Source/Events/Projections/Store/State/ProjectionState.cs similarity index 100% rename from Source/Projections.Store/State/ProjectionState.cs rename to Source/Events/Projections/Store/State/ProjectionState.cs diff --git a/Source/Events.Store/Actors/BootstrapProcedures.cs b/Source/Events/Store/Actors/BootstrapProcedures.cs similarity index 100% rename from Source/Events.Store/Actors/BootstrapProcedures.cs rename to Source/Events/Store/Actors/BootstrapProcedures.cs diff --git a/Source/Events/Store/Actors/Bucket.cs b/Source/Events/Store/Actors/Bucket.cs new file mode 100644 index 000000000..93a5e0d01 --- /dev/null +++ b/Source/Events/Store/Actors/Bucket.cs @@ -0,0 +1,49 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Events.Store.Streams; +using StreamProcessorState = Dolittle.Runtime.Events.Processing.Streams.StreamProcessorState; + +namespace Dolittle.Runtime.Events.Store.Actors; + +public partial class Bucket +{ + public IStreamProcessorState FromProtobuf() + { + return Partitioned ? FromProtobufPartitioned() : FromProtobufNonPartitioned(); + } + + IStreamProcessorState FromProtobufNonPartitioned() + { + var lastSuccessfullyProcessed = LastSuccessfullyProcessed.ToDateTimeOffset(); + switch (Failures.Count) + { + case 0: return new StreamProcessorState(Position(), "", lastSuccessfullyProcessed, 0, lastSuccessfullyProcessed, false); + case 1: + var failure = Failures[0]; + return new StreamProcessorState(Position(), failure.FailureReason, failure.RetryTime.ToDateTimeOffset(), + failure.ProcessingAttempts, + lastSuccessfullyProcessed, true); + default: + // This is probably invalid, as this should not be able to represent more than a single failure + var fail = Failures[0]; + return new StreamProcessorState(Position(), fail.FailureReason, fail.RetryTime.ToDateTimeOffset(), fail.ProcessingAttempts, + lastSuccessfullyProcessed, true); + } + } + + ProcessingPosition Position() => new(CurrentOffset, CurrentEventLogOffset); + + IStreamProcessorState FromProtobufPartitioned() + { + var failingPartitions = Failures + .ToImmutableDictionary(kv => new PartitionId(kv.EventSourceId), + _ => new FailingPartitionState(new StreamPosition(_.Offset), new EventLogSequenceNumber(_.EventLogOffset), _.RetryTime.ToDateTimeOffset(), + _.FailureReason, _.ProcessingAttempts, + _.LastFailed.ToDateTimeOffset())); + + return new Processing.Streams.Partitioned.StreamProcessorState(Position(), failingPartitions, LastSuccessfullyProcessed.ToDateTimeOffset()); + } +} diff --git a/Source/Events.Store/Actors/Committer.cs b/Source/Events/Store/Actors/Committer.cs similarity index 99% rename from Source/Events.Store/Actors/Committer.cs rename to Source/Events/Store/Actors/Committer.cs index e5883476c..9684c9d38 100644 --- a/Source/Events.Store/Actors/Committer.cs +++ b/Source/Events/Store/Actors/Committer.cs @@ -279,7 +279,7 @@ async Task TryHandleAggregateRootVersionInconsistency( _metrics.IncrementTotalAggregateRootVersionCacheInconsistenciesResolved(); _logger.AggregateRootVersionCacheInconsistencyResolved(aggregate.AggregateRoot, aggregate.EventSourceId, expectedAggregateRootVersion); _aggregateRootVersionCache[aggregate] = expectedAggregateRootVersion; - return Try.Succeeded(); + return Try.Succeeded; } if (newCurrentAggregateRootVersion != cachedAggregateRootVersion) { diff --git a/Source/Events.Store/Actors/EventLogStream.cs b/Source/Events/Store/Actors/EventLogStream.cs similarity index 62% rename from Source/Events.Store/Actors/EventLogStream.cs rename to Source/Events/Store/Actors/EventLogStream.cs index 7e699b3a0..fc8eea388 100644 --- a/Source/Events.Store/Actors/EventLogStream.cs +++ b/Source/Events/Store/Actors/EventLogStream.cs @@ -41,6 +41,7 @@ public ChannelReader Subscribe( ScopeId scope, EventLogSequenceNumber from, IReadOnlyCollection eventTypes, + string subscriptionName, CancellationToken cancellationToken) { if (!eventTypes.Any()) @@ -48,23 +49,33 @@ public ChannelReader Subscribe( throw new ArgumentException("No event types passed"); } - return StartSubscription(scope, from, eventTypes, cancellationToken); + return StartSubscription(scope, from, eventTypes, subscriptionName, cancellationToken); } public ChannelReader SubscribeAll( ScopeId scope, EventLogSequenceNumber from, + string subscriptionName, CancellationToken cancellationToken) => - StartSubscription(scope, from, ImmutableList.Empty, cancellationToken); + StartSubscription(scope, from, ImmutableList.Empty, subscriptionName, cancellationToken); - ChannelReader StartSubscription( - ScopeId scope, + public ChannelReader SubscribePublic(EventLogSequenceNumber from, CancellationToken cancellationToken) + { + var channel = Channel.CreateBounded(ChannelSize); + var filterConfig = new EventLogStreamActor.FilterConfig(ImmutableArray.Empty, true); + _actorSystem.Root.Spawn(_createProps.PropsFor(channel.Writer, ScopeId.Default, from, filterConfig, cancellationToken)); + return channel.Reader; + } + + ChannelReader StartSubscription(ScopeId scope, EventLogSequenceNumber from, IReadOnlyCollection eventTypes, + string subscriptionName, CancellationToken cancellationToken) { var channel = Channel.CreateBounded(ChannelSize); - _actorSystem.Root.Spawn(_createProps.PropsFor(channel.Writer, scope, from, eventTypes, cancellationToken)); + var filterConfig = new EventLogStreamActor.FilterConfig(eventTypes.ToImmutableHashSet(), subscriptionName: subscriptionName); + _actorSystem.Root.Spawn(_createProps.PropsFor(channel.Writer, scope, from, filterConfig, cancellationToken)); return channel.Reader; } } @@ -72,6 +83,8 @@ ChannelReader StartSubscription( // ReSharper disable once ClassNeverInstantiated.Global public class EventLogStreamActor : IActor { + public record FilterConfig(IReadOnlyCollection _eventTypes, bool publicOnly = false, string subscriptionName = "unnamed"); + readonly ChannelWriter _channelWriter; readonly CancellationToken _cancellationToken; @@ -81,19 +94,23 @@ public class EventLogStreamActor : IActor readonly ILogger _logger; readonly Uuid _subscriptionId; readonly Uuid _scope; + readonly bool _publicOnly; + readonly string _subscriptionName; public EventLogStreamActor( ChannelWriter channelWriter, ScopeId scope, EventLogSequenceNumber nextOffset, - IReadOnlyCollection eventTypeIds, + FilterConfig filterConfig, EventStoreClient eventStoreClient, ILogger logger, CancellationToken cancellationToken) { _channelWriter = channelWriter; _nextOffset = nextOffset; - _eventTypes = eventTypeIds; + _eventTypes = filterConfig._eventTypes; + _publicOnly = filterConfig.publicOnly; + _subscriptionName = filterConfig.subscriptionName; _eventStoreClient = eventStoreClient; _logger = logger; _cancellationToken = cancellationToken; @@ -114,19 +131,28 @@ public Task ReceiveAsync(IContext context) async Task OnSubscriptionEvents(SubscriptionEvents request, IContext context) { - if (request.FromOffset == _nextOffset) + try { - _nextOffset = request.ToOffset + 1; - Ack(_nextOffset, context); - await _channelWriter.WriteAsync(new EventLogBatch( - request.FromOffset, - request.ToOffset, - request.Events), _cancellationToken).ConfigureAwait(false); + if (request.FromOffset == _nextOffset) + { + _nextOffset = request.ToOffset + 1; + Ack(_nextOffset, context); + await _channelWriter.WriteAsync(new EventLogBatch( + request.FromOffset, + request.ToOffset, + request.Events), _cancellationToken).ConfigureAwait(false); + } + else + { + Ack(_nextOffset, context); + _logger.LogUnexpectedOffset(_nextOffset, request.FromOffset); + } } - else + catch (OperationCanceledException) { - Ack(_nextOffset, context); - _logger.LogUnexpectedOffset(_nextOffset, request.FromOffset); + // ReSharper disable once MethodHasAsyncOverload + // Subscription cancelled + context.Stop(context.Self); } } @@ -139,11 +165,12 @@ static void Ack(EventLogSequenceNumber nextOffset, IContext context) => async Task OnStopping() { _channelWriter.Complete(); - await _eventStoreClient.CancelSubscription(new CancelEventStoreSubscription + var cancelEventStoreSubscription = new CancelEventStoreSubscription { ScopeId = _scope, SubscriptionId = _subscriptionId - }, CancellationTokens.FromSeconds(5)).ConfigureAwait(false); + }; + await _eventStoreClient.CancelSubscription(cancelEventStoreSubscription, CancellationTokens.FromSeconds(5)).ConfigureAwait(false); } async Task OnStarted(IContext context) @@ -155,9 +182,17 @@ async Task OnStarted(IContext context) PidAddress = context.Self.Address, PidId = context.Self.Id, ScopeId = _scope, - SubscriptionId = _subscriptionId + SubscriptionId = _subscriptionId, + IncludePublicOnly = _publicOnly, + SubscriptionName = _subscriptionName }; await _eventStoreClient.RegisterSubscription(eventStoreSubscriptionRequest, _cancellationToken).ConfigureAwait(false); - context.ReenterAfterCancellation(_cancellationToken, () => context.Stop(context.Self)); + context.ReenterAfterCancellation(_cancellationToken, () => + { + if (!context.CancellationToken.IsCancellationRequested) + { + context.Stop(context.Self); + } + }); } } diff --git a/Source/Events.Store/Actors/EventStore.cs b/Source/Events/Store/Actors/EventStore.cs similarity index 95% rename from Source/Events.Store/Actors/EventStore.cs rename to Source/Events/Store/Actors/EventStore.cs index 078ee56ef..7ac0e8f72 100644 --- a/Source/Events.Store/Actors/EventStore.cs +++ b/Source/Events/Store/Actors/EventStore.cs @@ -31,7 +31,7 @@ public class EventStore : EventStoreBase readonly Dictionary _streamSubscriptionManagerPIDs = new(); PID? _committer; - bool _failedToStart; + bool FailedToStart => _startupFailure is not null; Dolittle.Protobuf.Contracts.Failure? _startupFailure; /// @@ -54,19 +54,16 @@ public override Task OnStarted() { if (!_tenants.All.Contains(_tenant)) { - _failedToStart = true; _startupFailure = new TenantNotConfigured(_tenant, _tenants.All).ToFailure(); return Task.CompletedTask; } if (!TrySpawnSubscriptionManager(ScopeId.Default, out var eventLogSubscriptionPid, out var error)) { - _failedToStart = true; _startupFailure = new EventStoreCouldNotBeStarted(_tenant, error, _tenants.All).ToFailure(); return Task.CompletedTask; } if (!Context.TrySpawnNamed(_propsFactory.PropsFor(), "committer", out _committer, out error)) { - _failedToStart = true; _startupFailure = new EventStoreCouldNotBeStarted(_tenant, error, _tenants.All).ToFailure(); return Task.CompletedTask; } @@ -108,9 +105,9 @@ Task RespondWithFailure(Failure failure) Task ForwardToCommitter(TRequest request, Func respondFailure) { - if (_failedToStart) + if (FailedToStart) { - return respondFailure(_startupFailure); + return respondFailure(_startupFailure!); } Context.Request(_committer!, request!, Context.Sender); return Task.CompletedTask; @@ -119,7 +116,7 @@ Task ForwardToCommitter(TRequest request, Func CommitExternal(CommitExternalEventsRequest request) { var scope = request.ScopeId.ToGuid(); - if (_failedToStart) + if (FailedToStart) { return Task.FromResult(new CommitExternalEventsResponse{Failure = _startupFailure}); } @@ -147,12 +144,12 @@ public override Task CommitExternal(CommitExternal public override Task RegisterSubscription(EventStoreSubscriptionRequest request, Action respond, Action onError) { - if (_failedToStart) + if (FailedToStart) { onError(_startupFailure!.Reason); return Task.CompletedTask; } - var scope = request.ScopeId.ToGuid(); + ScopeId scope = request.ScopeId?.ToGuid() ?? ScopeId.Default; if (!_streamSubscriptionManagerPIDs.TryGetValue(scope, out var pid)) { if (!TrySpawnSubscriptionManager(scope, out pid, out var error)) @@ -180,12 +177,12 @@ public override Task RegisterSubscription(EventStoreSubscriptionRequest request, public override Task CancelSubscription(CancelEventStoreSubscription request, Action respond, Action onError) { - if (_failedToStart) + if (FailedToStart) { onError(_startupFailure!.Reason); return Task.CompletedTask; } - var scope = request.ScopeId.ToGuid(); + ScopeId scope = request.ScopeId?.ToGuid() ?? ScopeId.Default; if (!_streamSubscriptionManagerPIDs.TryGetValue(scope, out var pid)) { onError("Subscription does not exist"); diff --git a/Source/Events/Store/Actors/EventStore.proto b/Source/Events/Store/Actors/EventStore.proto new file mode 100644 index 000000000..cbe4d8584 --- /dev/null +++ b/Source/Events/Store/Actors/EventStore.proto @@ -0,0 +1,163 @@ +syntax = "proto3"; + +package dolittle.runtime.events.actors; + +option csharp_namespace = "Dolittle.Runtime.Events.Store.Actors"; + +import "Runtime/Events/EventStore.proto"; +import "Runtime/Events/Committed.proto"; + +import "Protobuf/Failure.proto"; +import "Protobuf/Uuid.proto"; +import "Artifacts/Artifact.proto"; + +import "google/protobuf/empty.proto"; +import "google/protobuf/timestamp.proto"; + + +message EventStoreSubscriptionRequest{ + protobuf.Uuid subscription_id = 1; + protobuf.Uuid scope_id = 2; + repeated protobuf.Uuid event_type_ids = 3; + string pid_id = 4; + string pid_address = 5; + uint64 from_offset = 6; + bool include_public_only = 7; + string subscription_name = 8; // Debug name +} + +message StartEventStoreSubscription{ + protobuf.Uuid subscription_id = 1; + protobuf.Uuid scope_id = 2; + repeated protobuf.Uuid event_type_ids = 3; + string pid_id = 4; + string pid_address = 5; + uint64 from_offset = 6; + uint64 current_high_watermark = 7; + string subscription_name = 8; // Debug name +} + +message EventStoreSubscriptionAck{ + protobuf.Uuid subscription_id = 1; + protobuf.Uuid scope_id = 2; + bool ok = 3; +} + +message CancelEventStoreSubscription{ + protobuf.Uuid subscription_id = 1; + protobuf.Uuid scope_id = 2; +} + +message CancelEventStoreSubscriptionAck{ + protobuf.Uuid subscription_id = 1; +} + +message CommittedEventsRequest{ + uint64 from_offset = 1; + uint64 to_offset = 2; + repeated CommittedEvent events = 3; +} + +message SubscriptionEvents{ + protobuf.Uuid subscription_id = 1; + uint64 from_offset = 2; + uint64 to_offset = 3; + repeated CommittedEvent events = 4; +} + +message SubscriptionEventsAck{ + uint64 continue_from_offset = 1; +} + +message CommitExternalEventsRequest{ + CommittedEvent event = 1; + protobuf.Uuid scope_id = 2; +} +message CommitExternalEventsResponse{ + protobuf.Failure failure = 1; +} + +service EventStore { + rpc Commit (CommitEventsRequest) returns (CommitEventsResponse); + rpc CommitForAggregate (CommitAggregateEventsRequest) returns (CommitAggregateEventsResponse); + rpc CommitExternal (CommitExternalEventsRequest) returns (CommitExternalEventsResponse); + rpc RegisterSubscription(EventStoreSubscriptionRequest) returns (EventStoreSubscriptionAck); + rpc CancelSubscription(CancelEventStoreSubscription) returns (CancelEventStoreSubscriptionAck); +} + +message StreamSubscriptionId{ + protobuf.Uuid scope_id = 1; + protobuf.Uuid consumer_tenant_id = 2; + protobuf.Uuid producer_microservice_id = 3; + protobuf.Uuid producer_tenant_id = 4; + protobuf.Uuid stream_id = 5; + string partition_id = 6; +} + +message StreamProcessorId{ + protobuf.Uuid scope_id = 1; + protobuf.Uuid event_processor_id = 2; + protobuf.Uuid source_stream_id = 3; +} + +message StreamProcessorKey{ + oneof id { + StreamProcessorId stream_processor_id = 1; + StreamSubscriptionId subscription_id = 2; + } +} + +message StreamProcessorStateResponse{ + StreamProcessorKey stream_key = 1; + repeated Bucket bucket = 2; +} + +message SetStreamProcessorStateRequest{ + StreamProcessorKey stream_key = 1; + Bucket bucket = 2; +} + +message GetStreamProcessorPartitionStateResponse{ + StreamProcessorKey stream_key = 1; + Bucket partition = 2; + bool partitioned = 3; +} + +message ProcessingFailure{ + string event_source_id = 1; + uint64 offset = 2; + uint64 event_log_offset = 3; + string failure_reason = 4; + uint32 processing_attempts = 5; + google.protobuf.Timestamp retry_time = 6; + google.protobuf.Timestamp last_failed = 7; +} + + + +message Bucket{ + uint32 bucket_id = 1; + uint64 current_offset = 2; + uint64 current_event_log_offset = 3; + repeated ProcessingFailure failures = 4; + google.protobuf.Timestamp last_successfully_processed = 5; + bool partitioned = 6; +} + +message SetPartitionedStreamProcessorStateRequest{ + StreamProcessorKey stream_id = 1; + uint64 current_offset = 2; + uint64 current_event_log_offset = 3; + map failing_event_sources = 4; +} + + +service StreamProcessorState { + rpc GetByProcessorId (StreamProcessorId) returns (StreamProcessorStateResponse); + rpc SetByProcessorId (SetStreamProcessorStateRequest) returns (google.protobuf.Empty); +} + +service StreamSubscriptionState { + rpc GetBySubscriptionId (StreamSubscriptionId) returns (StreamProcessorStateResponse); + rpc SetBySubscriptionId (SetStreamProcessorStateRequest) returns (google.protobuf.Empty); +} diff --git a/Source/Events.Store/Actors/EventStoreCatchupActor.cs b/Source/Events/Store/Actors/EventStoreCatchupActor.cs similarity index 98% rename from Source/Events.Store/Actors/EventStoreCatchupActor.cs rename to Source/Events/Store/Actors/EventStoreCatchupActor.cs index d959057b7..9dd8ff94b 100644 --- a/Source/Events.Store/Actors/EventStoreCatchupActor.cs +++ b/Source/Events/Store/Actors/EventStoreCatchupActor.cs @@ -16,7 +16,7 @@ record EventLogCatchupResponse(EventLogSequenceNumber FromOffset, EventLogSequen public class EventStoreCatchupActor : IActor { - const int BatchSize = 1000; + const int BatchSize = 200; readonly IFetchCommittedEvents _eventsFetcher; readonly ILogger _logger; diff --git a/Source/Events.Store/Actors/EventStoreCouldNotBeStarted.cs b/Source/Events/Store/Actors/EventStoreCouldNotBeStarted.cs similarity index 100% rename from Source/Events.Store/Actors/EventStoreCouldNotBeStarted.cs rename to Source/Events/Store/Actors/EventStoreCouldNotBeStarted.cs diff --git a/Source/Events.Store/Actors/IMetricsCollector.cs b/Source/Events/Store/Actors/IMetricsCollector.cs similarity index 100% rename from Source/Events.Store/Actors/IMetricsCollector.cs rename to Source/Events/Store/Actors/IMetricsCollector.cs diff --git a/Source/Events/Store/Actors/Log.cs b/Source/Events/Store/Actors/Log.cs new file mode 100644 index 000000000..cf63794b7 --- /dev/null +++ b/Source/Events/Store/Actors/Log.cs @@ -0,0 +1,38 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Dolittle.Runtime.Aggregates; +using Dolittle.Runtime.Artifacts; +using Microsoft.Extensions.Logging; + +namespace Dolittle.Runtime.Events.Store.Actors; + +static partial class Log +{ + [LoggerMessage(0, LogLevel.Warning, + "Aggregate root '{AggregateRootId}' with event source '{EventSourceId}' has version inconsistency in cache. Expected {ExpectedAggregateRootVersion} but current is {CurrentAggregateRootVersion}")] + internal static partial void AggregateRootVersionCacheInconsistency(this ILogger logger, ArtifactId aggregateRootId, EventSourceId eventSourceId, + AggregateRootVersion expectedAggregateRootVersion, AggregateRootVersion currentAggregateRootVersion); + + [LoggerMessage(0, LogLevel.Warning, + "Aggregate root '{AggregateRootId}' with event source '{EventSourceId}' version inconsistency resolved it self. Aggregate root version is at the expected version {ExpectedAggregateRootVersion}")] + internal static partial void AggregateRootVersionCacheInconsistencyResolved(this ILogger logger, ArtifactId aggregateRootId, EventSourceId eventSourceId, + AggregateRootVersion expectedAggregateRootVersion); + + [LoggerMessage(0, LogLevel.Warning, + "Aggregate root '{AggregateRootId}' with event source '{EventSourceId}' version has a concurrency conflict, expected version {ExpectedAggregateRootVersion} but cached version {CachedVersion} was not consistent with stored version {StoredVersion}. Updating cache")] + internal static partial void AggregateRootConcurrencyConflictWithInconsistentCache(this ILogger logger, ArtifactId aggregateRootId, + EventSourceId eventSourceId, AggregateRootVersion expectedAggregateRootVersion, AggregateRootVersion cachedVersion, AggregateRootVersion storedVersion); + + [LoggerMessage(0, LogLevel.Warning, + "Aggregate root '{AggregateRootId}' with event source '{EventSourceId}' version has a concurrency conflict, expected version {ExpectedAggregateRootVersion} but cached version {CachedVersion} is consistent with storage")] + internal static partial void AggregateRootConcurrencyConflictWithConsistentCache(this ILogger logger, ArtifactId aggregateRootId, + EventSourceId eventSourceId, AggregateRootVersion expectedAggregateRootVersion, AggregateRootVersion cachedVersion); + + [LoggerMessage(0, LogLevel.Error, "Failed to persist stream subcription states for scope {ScopeId}")] + internal static partial void FailedToPersistStreamSubscriptionState(this ILogger logger, Exception e, ScopeId scopeId); + + [LoggerMessage(0, LogLevel.Error, "Failed to persist stream processor states")] + internal static partial void FailedToPersistStreamProcessorState(this ILogger logger, Exception e); +} diff --git a/Source/Events.Store/Actors/MetricsCollector.cs b/Source/Events/Store/Actors/MetricsCollector.cs similarity index 100% rename from Source/Events.Store/Actors/MetricsCollector.cs rename to Source/Events/Store/Actors/MetricsCollector.cs diff --git a/Source/Events/Store/Actors/StreamProcessorKey.cs b/Source/Events/Store/Actors/StreamProcessorKey.cs new file mode 100644 index 000000000..0dcf11292 --- /dev/null +++ b/Source/Events/Store/Actors/StreamProcessorKey.cs @@ -0,0 +1,23 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Dolittle.Runtime.Events.Store.Streams; + +namespace Dolittle.Runtime.Events.Store.Actors; + +public partial class StreamProcessorKey +{ + public IStreamProcessorId FromProtobuf() + { + switch (idCase_) + { + case IdOneofCase.StreamProcessorId: + return Processing.Streams.StreamProcessorId.FromProtobuf(StreamProcessorId); + case IdOneofCase.SubscriptionId: + return Runtime.EventHorizon.Consumer.SubscriptionId.FromProtobuf(SubscriptionId); + default: + throw new ArgumentOutOfRangeException(); + } + } +} diff --git a/Source/Events/Store/Actors/StreamProcessorStateManager.cs b/Source/Events/Store/Actors/StreamProcessorStateManager.cs new file mode 100644 index 000000000..b50f7d24a --- /dev/null +++ b/Source/Events/Store/Actors/StreamProcessorStateManager.cs @@ -0,0 +1,296 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Dolittle.Runtime.Actors; +using Dolittle.Runtime.Actors.Hosting; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Protobuf; +using Microsoft.Extensions.Logging; +using Proto; + +namespace Dolittle.Runtime.Events.Store.Actors; + +[TenantGrain(typeof(StreamProcessorStateActor), typeof(StreamProcessorStateClient),"dolittle.runtime.events.actors.StreamProcessorState")] +public class StreamProcessorStateManager : StreamProcessorStateBase +{ + readonly IStreamProcessorStateRepository _repository; + readonly ILogger _logger; + readonly IApplicationLifecycleHooks _lifecycleHooks; + + readonly Dictionary> _processorStates = new(); + readonly Dictionary> _changedSubscriptionStates = new(); + + readonly Dictionary _loadingScopes = new(); + + readonly HashSet _activeRequests = new(); + + IShutdownHook? _shutdownHook; + bool _shuttingDown; + + + public StreamProcessorStateManager(IContext context, IStreamProcessorStateRepository repository, ILogger logger, + IApplicationLifecycleHooks lifecycleHooks) : base(context) + { + _repository = repository; + _logger = logger; + _lifecycleHooks = lifecycleHooks; + } + + public override async Task OnStarted() + { + var defaultStates = new Dictionary(); + await foreach (var (id, state) in _repository.GetNonScoped(Context.CancellationToken)) + { + var streamProcessorKey = id.ToProtobuf(); + if (streamProcessorKey.IdCase != StreamProcessorKey.IdOneofCase.StreamProcessorId) + { + _logger.LogWarning("Got a non-stream processor key from the repository: {Key}", streamProcessorKey); + continue; + } + + defaultStates.Add(streamProcessorKey.StreamProcessorId, state.ToProtobuf()); + } + _processorStates.Add(ScopeId.Default, defaultStates); + + _logger.LogInformation("Retrieved the state of {Count} stream processors", defaultStates.Count); + + _shutdownHook = _lifecycleHooks.RegisterShutdownHook(); + Context.ReenterAfter(_shutdownHook.ShuttingDown, () => + { + _shuttingDown = true; + if (_activeRequests.Count == 0) // No current changes + { + _shutdownHook.MarkCompleted(); + } + }); + } + + + public override Task GetByProcessorId(StreamProcessorId processorId, Action respond, Action onError) + { + if (_shuttingDown) + { + onError("Runtime is shutting down"); + return Task.CompletedTask; + } + + ScopeId scopeId = processorId.ScopeId.ToGuid(); + if (TrySendResponse(scopeId, processorId, respond)) + { + return Task.CompletedTask; + } + + if (!_loadingScopes.TryGetValue(scopeId, out var scopeHasLoadedTask)) + { + scopeHasLoadedTask = LoadScope(scopeId); + } + + + Context.ReenterAfter(scopeHasLoadedTask, _ => + { + if (_.IsCompletedSuccessfully && TrySendResponse(scopeId, processorId, respond)) + { + // All OK + } + else + { + onError("Failed to get subscription state: " + _.Exception?.Message); + } + }); + return Task.CompletedTask; + } + + bool TrySendResponse(ScopeId scopeId, StreamProcessorId processorId, Action respond) + { + { + if (!_processorStates.TryGetValue(scopeId, out var scopeStates)) + { + // Scope has not been loaded + return false; + } + + // The scope is already loaded + SendResponse(scopeStates.TryGetValue(processorId, out var bucket) ? bucket : null); + return true; + } + + void SendResponse(Bucket? bucket) + { + var streamProcessorStateResponse = new StreamProcessorStateResponse + { + StreamKey = new StreamProcessorKey + { + StreamProcessorId = processorId + }, + }; + if(bucket is not null) + { + streamProcessorStateResponse.Bucket.Add(bucket); + } + respond(streamProcessorStateResponse); + } + } + + + Task LoadScope(ScopeId scopeId) + { + var taskCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + _loadingScopes.Add(scopeId, taskCompletionSource.Task); + return LoadScopeInternal(scopeId, taskCompletionSource); + } + + Task LoadScopeInternal(ScopeId scopeId, TaskCompletionSource taskCompletionSource) + { + var scopeTask = _repository.GetForScope(scopeId, Context.CancellationToken).ToListAsync().AsTask(); + Context.ReenterAfter(scopeTask, _ => + { + if (scopeTask.IsCompletedSuccessfully) + { + var buckets = new Dictionary(); + foreach (var streamProcessorStateWithId in scopeTask.Result) + { + var streamProcessorKey = streamProcessorStateWithId.Id.ToProtobuf(); + if (streamProcessorKey.IdCase == StreamProcessorKey.IdOneofCase.StreamProcessorId) + { + buckets[streamProcessorKey.StreamProcessorId] = streamProcessorStateWithId.State.ToProtobuf(); + } + } + + _processorStates[scopeId] = buckets; + taskCompletionSource.SetResult(); + _loadingScopes.Remove(scopeId); + } + else + { + _logger.LogError(scopeTask.Exception, "Failed to load scope {ScopeId}", scopeId); + if (!Context.CancellationToken.IsCancellationRequested && !_shuttingDown) + { + LoadScopeInternal(scopeId, taskCompletionSource); + } + } + }); + return taskCompletionSource.Task; + } + + + public override Task SetByProcessorId(SetStreamProcessorStateRequest request) + { + if (request.StreamKey.IdCase != StreamProcessorKey.IdOneofCase.StreamProcessorId) + { + throw new ArgumentException("Can only set processor state by processor id"); + } + + var key = request.StreamKey.StreamProcessorId; + ScopeId scopeId = key.ScopeId.ToGuid(); + + if (!TrySetProcessorState(scopeId, key, request.Bucket)) + { + // No change, so no update + return Task.CompletedTask; + } + + AddChange(scopeId, key, request.Bucket); + PersistCurrentProcessorState(scopeId); + return Task.CompletedTask; + } + + /// + /// Update current in-memory state + /// + /// true if there were real changes, false otherwise + bool TrySetProcessorState(ScopeId scope, StreamProcessorId processorId, Bucket state) + { + if (!_processorStates.TryGetValue(scope, out var scopedSubscriptionStates)) + { + _processorStates.Add(scope, scopedSubscriptionStates = new()); + } + + if (scopedSubscriptionStates.TryGetValue(processorId, out var existing)) + { + if (existing.Equals(state)) + { + return false; // No change + } + } + + scopedSubscriptionStates[processorId] = state; + return true; + } + + void AddChange(ScopeId scope, StreamProcessorId id, Bucket state) + { + if (!_changedSubscriptionStates.TryGetValue(scope, out var changedScopedSubscriptionStates)) + { + _changedSubscriptionStates.Add(scope, changedScopedSubscriptionStates = new()); + + } + + changedScopedSubscriptionStates[id] = state; + } + + void PersistCurrentProcessorState(ScopeId scopeId) + { + if (_activeRequests.Contains(scopeId)) + { + return; + } + + if (_changedSubscriptionStates.Count == 0) return; + if (!_changedSubscriptionStates.Remove(scopeId, out var currentChanges)) + { + return; // No changes for this scope + } + + _activeRequests.Add(scopeId); + var changes = FromProtobuf(currentChanges); + + Persist(changes, scopeId); + } + + void Persist(IReadOnlyDictionary changes, ScopeId scopeId) + { + _logger.LogTrace("Persisting {Count} changes for scope {ScopeId}", changes.Count, scopeId); + Context.ReenterAfter(_repository.PersistForScope(scopeId, changes, Context.CancellationToken), _ => + { + if (_.IsCompletedSuccessfully) + { + _activeRequests.Remove(scopeId); + PersistCurrentProcessorState(scopeId); + if (_shuttingDown && _activeRequests.Count == 0) + { + _shutdownHook.MarkCompleted(); + } + } + else + { + _logger.FailedToPersistStreamSubscriptionState(_.Exception!, scopeId); + // Try again + Persist(changes, scopeId); + } + }); + } + + IReadOnlyDictionary FromProtobuf( + IDictionary changes) + { + var dict = new Dictionary(); + foreach (var change in changes) + { + var streamProcessorId = Processing.Streams.StreamProcessorId.FromProtobuf(change.Key); + var state = change.Value.FromProtobuf(); + dict.Add(streamProcessorId, state); + } + + return dict; + } + + #region Unused + + public override Task GetByProcessorId(StreamProcessorId processorId) => throw new NotImplementedException("unused"); + + #endregion +} diff --git a/Source/Events.Store/Actors/StreamSubscriptionActor.cs b/Source/Events/Store/Actors/StreamSubscriptionActor.cs similarity index 87% rename from Source/Events.Store/Actors/StreamSubscriptionActor.cs rename to Source/Events/Store/Actors/StreamSubscriptionActor.cs index 3fd8cfe8c..37c65e4b5 100644 --- a/Source/Events.Store/Actors/StreamSubscriptionActor.cs +++ b/Source/Events/Store/Actors/StreamSubscriptionActor.cs @@ -16,13 +16,16 @@ namespace Dolittle.Runtime.Events.Store.Actors; // ReSharper disable once ClassNeverInstantiated.Global public class StreamSubscriptionActor : IActor { + const int MinWaitMs = 100; + const int MaxJitterMs = 400; readonly ScopeId _scope; readonly TenantId _tenantId; readonly ILogger _logger; - Func _shouldIncludeEvent; + Func? _shouldIncludeEvent; PID _target; Uuid _subscriptionId; + string _subscriptionName; public StreamSubscriptionActor(ScopeId scope, TenantId tenantId, ILogger logger) { @@ -44,6 +47,7 @@ public Task ReceiveAsync(IContext context) async Task OnStartEventStoreSubscription(StartEventStoreSubscription request, IContext context) { _subscriptionId = request.SubscriptionId; + _subscriptionName = request.SubscriptionName; _target = PID.FromAddress(request.PidAddress, request.PidId); _shouldIncludeEvent = CreateFilter(request.EventTypeIds); var fromOffset = request.FromOffset; @@ -65,6 +69,7 @@ async Task OnStartEventStoreSubscription(StartEventStoreSubscription request, IC catch (Exception e) { _logger.ErrorFetchingCatchupEvents(e); + await Task.Delay(MinWaitMs + new Random().Next(MaxJitterMs)); } } } @@ -83,7 +88,7 @@ async Task OnStartEventStoreSubscription(StartEventStoreSubscription request, IC Task OnCommittedEventsRequest(CommittedEventsRequest request, IContext context) => Publish(ToSubscriptionEvent(request), context); - + async Task Publish(SubscriptionEvents subscriptionEvent, IContext context) { while (!context.CancellationToken.IsCancellationRequested) @@ -103,9 +108,13 @@ async Task Publish(SubscriptionEvents subscriptionEvent, IContext context) context.Stop(context.Self); return; } + catch (TimeoutException) when (context.CancellationToken.IsCancellationRequested) + { + // Stopping, no need to log + } catch (Exception e) { - _logger.ErrorPublishingSubscribedEvents(e); + _logger.ErrorPublishingSubscribedEvents(e, _subscriptionName); } } } @@ -116,15 +125,15 @@ SubscriptionEvents ToSubscriptionEvent(CommittedEventsRequest request) => SubscriptionId = _subscriptionId, FromOffset = request.FromOffset, ToOffset = request.ToOffset, - Events = { request.Events.Where(_shouldIncludeEvent) } + Events = { request.Events.Where(_shouldIncludeEvent!) } }; - + SubscriptionEvents ToSubscriptionEvent(EventLogCatchupResponse response) => new() { SubscriptionId = _subscriptionId, FromOffset = response.FromOffset, ToOffset = response.ToOffset, - Events = { response.Events.Where(_shouldIncludeEvent) } + Events = { response.Events.Where(_shouldIncludeEvent!) } }; } diff --git a/Source/Events.Store/Actors/StreamSubscriptionManagerActor.cs b/Source/Events/Store/Actors/StreamSubscriptionManagerActor.cs similarity index 97% rename from Source/Events.Store/Actors/StreamSubscriptionManagerActor.cs rename to Source/Events/Store/Actors/StreamSubscriptionManagerActor.cs index 31ccdd5e3..6634654fb 100644 --- a/Source/Events.Store/Actors/StreamSubscriptionManagerActor.cs +++ b/Source/Events/Store/Actors/StreamSubscriptionManagerActor.cs @@ -116,8 +116,10 @@ Task OnEventStoreSubscriptionRequest(EventStoreSubscriptionRequest request, ICon PidAddress = request.PidAddress, SubscriptionId = request.SubscriptionId, ScopeId = request.ScopeId, - CurrentHighWatermark = _nextSequenceNumber + CurrentHighWatermark = _nextSequenceNumber, + SubscriptionName = request.SubscriptionName }); + context.Respond(new EventStoreSubscriptionAck { SubscriptionId = request.SubscriptionId, diff --git a/Source/Events/Store/Actors/StreamSubscriptionStateManager.cs b/Source/Events/Store/Actors/StreamSubscriptionStateManager.cs new file mode 100644 index 000000000..2df2adcfe --- /dev/null +++ b/Source/Events/Store/Actors/StreamSubscriptionStateManager.cs @@ -0,0 +1,295 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Dolittle.Runtime.Actors; +using Dolittle.Runtime.Actors.Hosting; +using Dolittle.Runtime.EventHorizon.Consumer; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Protobuf; +using Microsoft.Extensions.Logging; +using Proto; + +namespace Dolittle.Runtime.Events.Store.Actors; + +[TenantGrain(typeof(StreamSubscriptionStateActor), typeof(StreamSubscriptionStateClient), "dolittle.runtime.events.actors.StreamSubscriptionState")] +public class StreamSubscriptionStateManager : StreamSubscriptionStateBase +{ + readonly ISubscriptionStateRepository _repository; + readonly ILogger _logger; + readonly IApplicationLifecycleHooks _lifecycleHooks; + + + readonly Dictionary> _subscriptionStates = new(); + readonly Dictionary> _changedSubscriptionStates = new(); + + readonly HashSet _activeRequests = new(); + readonly Dictionary _loadingScopes = new(); + + + IShutdownHook _shutdownHook; + bool _shuttingDown; + + + public StreamSubscriptionStateManager(IContext context, ISubscriptionStateRepository repository, ILogger logger, + IApplicationLifecycleHooks lifecycleHooks) : base(context) + { + _repository = repository; + _logger = logger; + _lifecycleHooks = lifecycleHooks; + } + + public override Task OnStarted() + { + LoadScope(ScopeId.Default); + _shutdownHook = _lifecycleHooks.RegisterShutdownHook(); + Context.ReenterAfter(_shutdownHook.ShuttingDown, () => + { + _shuttingDown = true; + if (_activeRequests.Count == 0) // No current changes + { + _shutdownHook.MarkCompleted(); + } + }); + return Task.CompletedTask; + } + + + public override Task GetBySubscriptionId(StreamSubscriptionId subscriptionId, Action respond, Action onError) + { + if (_shuttingDown) + { + onError("Runtime is shutting down"); + return Task.CompletedTask; + } + + ScopeId scopeId = subscriptionId.ScopeId.ToGuid(); + if (TrySendResponse(scopeId, subscriptionId, respond)) + { + return Task.CompletedTask; + } + + if (!_loadingScopes.TryGetValue(scopeId, out var scopeHasLoadedTask)) + { + scopeHasLoadedTask = LoadScope(scopeId); + } + + + Context.ReenterAfter(scopeHasLoadedTask, _ => + { + if (_.IsCompletedSuccessfully && TrySendResponse(scopeId, subscriptionId, respond)) + { + // All OK + } + else + { + onError("Failed to get subscription state: " + scopeHasLoadedTask.Exception?.Message); + } + }); + return Task.CompletedTask; + } + + bool TrySendResponse(ScopeId scopeId, StreamSubscriptionId subscriptionId, Action respond) + { + { + if (!_subscriptionStates.TryGetValue(scopeId, out var scopeStates)) + { + // Scope has not been loaded + return false; + } + + // The scope is already loaded + SendResponse(scopeStates.TryGetValue(subscriptionId, out var bucket) ? bucket : null); + return true; + } + + void SendResponse(Bucket? bucket) + { + var streamProcessorStateResponse = new StreamProcessorStateResponse + { + StreamKey = new StreamProcessorKey + { + SubscriptionId = subscriptionId + }, + }; + if (bucket is not null) + { + streamProcessorStateResponse.Bucket.Add(bucket); + } + + respond(streamProcessorStateResponse); + } + } + + + Task LoadScope(ScopeId scopeId) + { + var taskCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + _loadingScopes.Add(scopeId, taskCompletionSource.Task); + LoadScopeInternal(scopeId, taskCompletionSource); + return taskCompletionSource.Task; + } + + void LoadScopeInternal(ScopeId scopeId, TaskCompletionSource taskCompletionSource) + { + var scopeTask = _repository.GetForScope(scopeId, Context.CancellationToken).ToListAsync().AsTask(); + Context.ReenterAfter(scopeTask, _ => + { + if (scopeTask.IsCompletedSuccessfully) + { + var buckets = new Dictionary(); + foreach (var streamProcessorStateWithId in scopeTask.Result) + { + var streamProcessorKey = streamProcessorStateWithId.Id.ToProtobuf(); + if (streamProcessorKey.IdCase == StreamProcessorKey.IdOneofCase.SubscriptionId) + { + buckets[streamProcessorKey.SubscriptionId] = streamProcessorStateWithId.State.ToProtobuf(); + } + else + { + _logger.LogWarning("Got unexpected stream processor key type {StreamProcessorKeyType} for scope {ScopeId}", streamProcessorKey.IdCase, + scopeId); + } + } + + _subscriptionStates[scopeId] = buckets; + taskCompletionSource.SetResult(); + _loadingScopes.Remove(scopeId); + } + else + { + _logger.LogError(scopeTask.Exception, "Failed to load scope {ScopeId}", scopeId); + if (!Context.CancellationToken.IsCancellationRequested && !_shuttingDown) + { + LoadScopeInternal(scopeId, taskCompletionSource); + } + } + }); + } + + public override Task SetBySubscriptionId(SetStreamProcessorStateRequest request) + { + if (request.StreamKey.IdCase != StreamProcessorKey.IdOneofCase.SubscriptionId) + { + throw new ArgumentException("Can only set subscription state by subscription id"); + } + + var subscriptionId = request.StreamKey.SubscriptionId; + ScopeId scopeId = subscriptionId.ScopeId.ToGuid(); + + if (!TrySetSubscriptionState(scopeId, subscriptionId, request.Bucket)) + { + // No change, so no update + return Task.CompletedTask; + } + + AddChange(scopeId, subscriptionId, request.Bucket); + + PersistCurrentSubscriptionState(scopeId); + return Task.CompletedTask; + } + + /// + /// Update current in-memory state + /// + /// true if there were real changes, false otherwise + bool TrySetSubscriptionState(ScopeId scope, StreamSubscriptionId subscriptionId, Bucket state) + { + if (!_subscriptionStates.TryGetValue(scope, out var scopedSubscriptionStates)) + { + _subscriptionStates.Add(scope, scopedSubscriptionStates = new()); + } + + if (scopedSubscriptionStates.TryGetValue(subscriptionId, out var existing)) + { + if (existing.Equals(state)) + { + return false; // No change + } + } + + scopedSubscriptionStates[subscriptionId] = state; + return true; + } + + void AddChange(ScopeId scope, StreamSubscriptionId subscriptionId, Bucket state) + { + if (!_changedSubscriptionStates.TryGetValue(scope, out var changedScopedSubscriptionStates)) + { + _changedSubscriptionStates.Add(scope, changedScopedSubscriptionStates = new()); + } + + changedScopedSubscriptionStates[subscriptionId] = state; + } + + void PersistCurrentSubscriptionState(ScopeId scopeId) + { + if (_activeRequests.Contains(scopeId)) + { + return; + } + + if (_changedSubscriptionStates.Count == 0) return; + if (!_changedSubscriptionStates.Remove(scopeId, out var currentChanges)) + { + return; // No changes for this scope + } + + _activeRequests.Add(scopeId); + var changes = FromProtobuf(currentChanges); + + Persist(changes, scopeId); + } + + void Persist(IReadOnlyDictionary changes, ScopeId scopeId) + { + _logger.LogTrace("Persisting {Count} changes for scope {ScopeId}", changes.Count, scopeId); + var persistTask = _repository.PersistForScope(scopeId, changes, Context.CancellationToken); + Context.ReenterAfter(persistTask, _ => + { + if (persistTask.IsCompletedSuccessfully) + { + _activeRequests.Remove(scopeId); + PersistCurrentSubscriptionState(scopeId); + if (_shuttingDown && _activeRequests.Count == 0) + { + _shutdownHook.MarkCompleted(); + } + } + else + { + _logger.FailedToPersistStreamSubscriptionState(persistTask.Exception!, scopeId); + // Try again + Persist(changes, scopeId); + } + }); + } + + IReadOnlyDictionary FromProtobuf(IDictionary changes) + { + var dict = new Dictionary(); + foreach (var change in changes) + { + var state = change.Value.FromProtobuf(); + if (state is StreamProcessorState streamProcessorState) + { + dict.Add(SubscriptionId.FromProtobuf(change.Key), streamProcessorState); + } + else + { + _logger.LogWarning("Unecpected state type: {stateType}", state.GetType().FullName); + } + } + + return dict; + } + + #region Unused, handled with reentrant overloads + + public override Task GetBySubscriptionId(StreamSubscriptionId request) => throw new NotImplementedException("unused"); + + #endregion +} diff --git a/Source/Events.Store/AggregateRootConcurrencyConflict.cs b/Source/Events/Store/AggregateRootConcurrencyConflict.cs similarity index 100% rename from Source/Events.Store/AggregateRootConcurrencyConflict.cs rename to Source/Events/Store/AggregateRootConcurrencyConflict.cs diff --git a/Source/Events.Store/AggregateRootVersionIsOutOfOrder.cs b/Source/Events/Store/AggregateRootVersionIsOutOfOrder.cs similarity index 100% rename from Source/Events.Store/AggregateRootVersionIsOutOfOrder.cs rename to Source/Events/Store/AggregateRootVersionIsOutOfOrder.cs diff --git a/Source/Events.Store/CommittedAggregateEvent.cs b/Source/Events/Store/CommittedAggregateEvent.cs similarity index 100% rename from Source/Events.Store/CommittedAggregateEvent.cs rename to Source/Events/Store/CommittedAggregateEvent.cs diff --git a/Source/Events.Store/CommittedAggregateEventExtensions.cs b/Source/Events/Store/CommittedAggregateEventExtensions.cs similarity index 100% rename from Source/Events.Store/CommittedAggregateEventExtensions.cs rename to Source/Events/Store/CommittedAggregateEventExtensions.cs diff --git a/Source/Events.Store/CommittedAggregateEvents.cs b/Source/Events/Store/CommittedAggregateEvents.cs similarity index 100% rename from Source/Events.Store/CommittedAggregateEvents.cs rename to Source/Events/Store/CommittedAggregateEvents.cs diff --git a/Source/Events.Store/CommittedAggregateEventsExtensions.cs b/Source/Events/Store/CommittedAggregateEventsExtensions.cs similarity index 100% rename from Source/Events.Store/CommittedAggregateEventsExtensions.cs rename to Source/Events/Store/CommittedAggregateEventsExtensions.cs diff --git a/Source/Events.Store/CommittedEvent.cs b/Source/Events/Store/CommittedEvent.cs similarity index 100% rename from Source/Events.Store/CommittedEvent.cs rename to Source/Events/Store/CommittedEvent.cs diff --git a/Source/Events.Store/CommittedEventExtensions.cs b/Source/Events/Store/CommittedEventExtensions.cs similarity index 100% rename from Source/Events.Store/CommittedEventExtensions.cs rename to Source/Events/Store/CommittedEventExtensions.cs diff --git a/Source/Events.Store/CommittedEventSequence.cs b/Source/Events/Store/CommittedEventSequence.cs similarity index 100% rename from Source/Events.Store/CommittedEventSequence.cs rename to Source/Events/Store/CommittedEventSequence.cs diff --git a/Source/Events.Store/CommittedEvents.cs b/Source/Events/Store/CommittedEvents.cs similarity index 100% rename from Source/Events.Store/CommittedEvents.cs rename to Source/Events/Store/CommittedEvents.cs diff --git a/Source/Events.Store/CommittedEventsExtensions.cs b/Source/Events/Store/CommittedEventsExtensions.cs similarity index 100% rename from Source/Events.Store/CommittedEventsExtensions.cs rename to Source/Events/Store/CommittedEventsExtensions.cs diff --git a/Source/Events.Store/CommittedExternalEvent.cs b/Source/Events/Store/CommittedExternalEvent.cs similarity index 100% rename from Source/Events.Store/CommittedExternalEvent.cs rename to Source/Events/Store/CommittedExternalEvent.cs diff --git a/Source/Events.Store/CommittedExternalEventExtensions.cs b/Source/Events/Store/CommittedExternalEventExtensions.cs similarity index 100% rename from Source/Events.Store/CommittedExternalEventExtensions.cs rename to Source/Events/Store/CommittedExternalEventExtensions.cs diff --git a/Source/Events.Store/Event.cs b/Source/Events/Store/Event.cs similarity index 100% rename from Source/Events.Store/Event.cs rename to Source/Events/Store/Event.cs diff --git a/Source/Events.Store/EventCanNotBeNull.cs b/Source/Events/Store/EventCanNotBeNull.cs similarity index 100% rename from Source/Events.Store/EventCanNotBeNull.cs rename to Source/Events/Store/EventCanNotBeNull.cs diff --git a/Source/Events.Store/EventHorizon/ConsentId.cs b/Source/Events/Store/EventHorizon/ConsentId.cs similarity index 100% rename from Source/Events.Store/EventHorizon/ConsentId.cs rename to Source/Events/Store/EventHorizon/ConsentId.cs diff --git a/Source/Events.Store/EventHorizon/IWriteEventHorizonEvents.cs b/Source/Events/Store/EventHorizon/IWriteEventHorizonEvents.cs similarity index 95% rename from Source/Events.Store/EventHorizon/IWriteEventHorizonEvents.cs rename to Source/Events/Store/EventHorizon/IWriteEventHorizonEvents.cs index 42a901e6b..1fe349892 100644 --- a/Source/Events.Store/EventHorizon/IWriteEventHorizonEvents.cs +++ b/Source/Events/Store/EventHorizon/IWriteEventHorizonEvents.cs @@ -3,7 +3,6 @@ using System.Threading; using System.Threading.Tasks; -using Dolittle.Runtime.Events.Store.Streams; namespace Dolittle.Runtime.Events.Store.EventHorizon; diff --git a/Source/Events/Store/EventHorizon/SubscriptionId.cs b/Source/Events/Store/EventHorizon/SubscriptionId.cs new file mode 100644 index 000000000..e5f6963c9 --- /dev/null +++ b/Source/Events/Store/EventHorizon/SubscriptionId.cs @@ -0,0 +1,50 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Domain.Platform; +using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Actors; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Protobuf; + +namespace Dolittle.Runtime.EventHorizon.Consumer; + +/// +/// Represents an the unique identifier of an Event Horizon Subscription. +/// +public record SubscriptionId( + TenantId ConsumerTenantId, + MicroserviceId ProducerMicroserviceId, + TenantId ProducerTenantId, + ScopeId ScopeId, + StreamId StreamId, + PartitionId PartitionId) : IStreamProcessorId +{ + /// + public override string ToString() => + $"Consumer Tenant: {ConsumerTenantId.Value} Producer Microservice: {ProducerMicroserviceId.Value} Producer Tenant: {ProducerTenantId.Value} Scope: {ScopeId.Value} Stream: {StreamId.Value} Partition: {PartitionId.Value}'"; + + + public StreamProcessorKey ToProtobuf() => new() + { + SubscriptionId = new StreamSubscriptionId + { + ConsumerTenantId = ConsumerTenantId.ToProtobuf(), + ProducerMicroserviceId = ProducerMicroserviceId.ToProtobuf(), + ProducerTenantId = ProducerTenantId.ToProtobuf(), + ScopeId = ScopeId.ToProtobuf(), + StreamId = StreamId.ToProtobuf(), + PartitionId = PartitionId.Value + } + }; + + public static SubscriptionId FromProtobuf(StreamSubscriptionId subscriptionId) => + new( + ConsumerTenantId: subscriptionId.ConsumerTenantId.ToGuid(), + ProducerMicroserviceId: subscriptionId.ProducerMicroserviceId.ToGuid(), + ProducerTenantId: subscriptionId.ProducerTenantId.ToGuid(), + ScopeId: subscriptionId.ScopeId.ToGuid(), + StreamId: subscriptionId.StreamId.ToGuid(), + PartitionId: subscriptionId.PartitionId); +} diff --git a/Source/Events.Store/EventLogSequenceIsOutOfOrder.cs b/Source/Events/Store/EventLogSequenceIsOutOfOrder.cs similarity index 100% rename from Source/Events.Store/EventLogSequenceIsOutOfOrder.cs rename to Source/Events/Store/EventLogSequenceIsOutOfOrder.cs diff --git a/Source/Events.Store/EventLogSequenceNumber.cs b/Source/Events/Store/EventLogSequenceNumber.cs similarity index 52% rename from Source/Events.Store/EventLogSequenceNumber.cs rename to Source/Events/Store/EventLogSequenceNumber.cs index 744709f55..0e6632d89 100644 --- a/Source/Events.Store/EventLogSequenceNumber.cs +++ b/Source/Events/Store/EventLogSequenceNumber.cs @@ -1,6 +1,7 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using Dolittle.Runtime.Rudimentary; namespace Dolittle.Runtime.Events.Store; @@ -8,16 +9,40 @@ namespace Dolittle.Runtime.Events.Store; /// /// Represents the sequence number of the Event Log as a natural number, corresponding to the number of events that has been committed to the Event Store. /// -public record EventLogSequenceNumber(ulong Value) : ConceptAs(Value) +public record EventLogSequenceNumber(ulong Value) : ConceptAs(Value), IComparable { /// /// The initial sequence number of the Event Store before any Events are committed. /// public static readonly EventLogSequenceNumber Initial = 0L; + public EventLogSequenceNumber Increment() => new(Value + 1); + /// /// Implicitly convert a to an . /// /// The number. public static implicit operator EventLogSequenceNumber(ulong number) => new(number); + + public static bool operator <(EventLogSequenceNumber left, EventLogSequenceNumber right) + { + return left.Value.CompareTo(right.Value) < 0; + } + + public static bool operator <=(EventLogSequenceNumber left, EventLogSequenceNumber right) + { + return left.Value.CompareTo(right.Value) <= 0; + } + + public static bool operator >(EventLogSequenceNumber left, EventLogSequenceNumber right) + { + return left.Value.CompareTo(right.Value) > 0; + } + + public static bool operator >=(EventLogSequenceNumber left, EventLogSequenceNumber right) + { + return left.Value.CompareTo(right.Value) >= 0; + } + + public int CompareTo(EventLogSequenceNumber? other) => Value.CompareTo(other?.Value); } diff --git a/Source/Events.Store/EventSequence.cs b/Source/Events/Store/EventSequence.cs similarity index 100% rename from Source/Events.Store/EventSequence.cs rename to Source/Events/Store/EventSequence.cs diff --git a/Source/Events.Store/EventStore.cs b/Source/Events/Store/EventStore.cs similarity index 100% rename from Source/Events.Store/EventStore.cs rename to Source/Events/Store/EventStore.cs diff --git a/Source/Events.Store/EventStoreConsistencyError.cs b/Source/Events/Store/EventStoreConsistencyError.cs similarity index 100% rename from Source/Events.Store/EventStoreConsistencyError.cs rename to Source/Events/Store/EventStoreConsistencyError.cs diff --git a/Source/Events.Store/EventStoreFailures.cs b/Source/Events/Store/EventStoreFailures.cs similarity index 100% rename from Source/Events.Store/EventStoreFailures.cs rename to Source/Events/Store/EventStoreFailures.cs diff --git a/Source/Events.Store/EventStorePersistenceError.cs b/Source/Events/Store/EventStorePersistenceError.cs similarity index 100% rename from Source/Events.Store/EventStorePersistenceError.cs rename to Source/Events/Store/EventStorePersistenceError.cs diff --git a/Source/Events.Store/EventStoreUnavailable.cs b/Source/Events/Store/EventStoreUnavailable.cs similarity index 100% rename from Source/Events.Store/EventStoreUnavailable.cs rename to Source/Events/Store/EventStoreUnavailable.cs diff --git a/Source/Events.Store/EventTypesExtensions.cs b/Source/Events/Store/EventTypesExtensions.cs similarity index 100% rename from Source/Events.Store/EventTypesExtensions.cs rename to Source/Events/Store/EventTypesExtensions.cs diff --git a/Source/Events.Store/EventWasAppliedByOtherAggregateRoot.cs b/Source/Events/Store/EventWasAppliedByOtherAggregateRoot.cs similarity index 100% rename from Source/Events.Store/EventWasAppliedByOtherAggregateRoot.cs rename to Source/Events/Store/EventWasAppliedByOtherAggregateRoot.cs diff --git a/Source/Events.Store/EventWasAppliedToOtherEventSource.cs b/Source/Events/Store/EventWasAppliedToOtherEventSource.cs similarity index 100% rename from Source/Events.Store/EventWasAppliedToOtherEventSource.cs rename to Source/Events/Store/EventWasAppliedToOtherEventSource.cs diff --git a/Source/Events.Store/ExceptionExtensions.cs b/Source/Events/Store/ExceptionExtensions.cs similarity index 100% rename from Source/Events.Store/ExceptionExtensions.cs rename to Source/Events/Store/ExceptionExtensions.cs diff --git a/Source/Events.Store/ICommitEvents.cs b/Source/Events/Store/ICommitEvents.cs similarity index 100% rename from Source/Events.Store/ICommitEvents.cs rename to Source/Events/Store/ICommitEvents.cs diff --git a/Source/Events.Store/IEventLogStream.cs b/Source/Events/Store/IEventLogStream.cs similarity index 69% rename from Source/Events.Store/IEventLogStream.cs rename to Source/Events/Store/IEventLogStream.cs index a32232a38..14fb61f77 100644 --- a/Source/Events.Store/IEventLogStream.cs +++ b/Source/Events/Store/IEventLogStream.cs @@ -21,12 +21,14 @@ public interface IEventLogStream /// The . /// From offset, inclusive /// Included event types, min 1 + /// Debug name /// /// ChannelReader Subscribe( ScopeId scope, EventLogSequenceNumber from, IReadOnlyCollection eventTypes, + string subscriptionName, CancellationToken cancellationToken); /// @@ -34,7 +36,17 @@ ChannelReader Subscribe( /// /// The . /// From offset, inclusive + /// Debug name /// /// - ChannelReader SubscribeAll(ScopeId scopeId, EventLogSequenceNumber from, CancellationToken cancellationToken); + ChannelReader SubscribeAll(ScopeId scopeId, EventLogSequenceNumber from, string subscriptionName, CancellationToken cancellationToken); + + /// + /// Subscribe to the complete event log stream at the given offset, including public events only + /// + /// The . + /// From offset, inclusive + /// + /// + ChannelReader SubscribePublic(EventLogSequenceNumber from, CancellationToken cancellationToken); } diff --git a/Source/Events.Store/IEventStore.cs b/Source/Events/Store/IEventStore.cs similarity index 100% rename from Source/Events.Store/IEventStore.cs rename to Source/Events/Store/IEventStore.cs diff --git a/Source/Events.Store/IFetchAggregateRootVersions.cs b/Source/Events/Store/IFetchAggregateRootVersions.cs similarity index 100% rename from Source/Events.Store/IFetchAggregateRootVersions.cs rename to Source/Events/Store/IFetchAggregateRootVersions.cs diff --git a/Source/Events.Store/IFetchCommittedEvents.cs b/Source/Events/Store/IFetchCommittedEvents.cs similarity index 72% rename from Source/Events.Store/IFetchCommittedEvents.cs rename to Source/Events/Store/IFetchCommittedEvents.cs index d11cb9f11..38da58bb6 100644 --- a/Source/Events.Store/IFetchCommittedEvents.cs +++ b/Source/Events/Store/IFetchCommittedEvents.cs @@ -6,6 +6,8 @@ using System.Threading.Tasks; using Dolittle.Runtime.Aggregates; using Dolittle.Runtime.Artifacts; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Rudimentary; namespace Dolittle.Runtime.Events.Store; @@ -33,7 +35,7 @@ public interface IFetchCommittedEvents /// The . /// Task FetchCommittedEvents(ScopeId scopeId, EventLogSequenceNumber from, int limit, CancellationToken cancellationToken); - + /// /// Fetches the applied to an Event Source by an Aggregate Root. /// @@ -41,7 +43,8 @@ public interface IFetchCommittedEvents /// The identifying the Aggregate Root. /// The . /// An of . - IAsyncEnumerable FetchStreamForAggregate(EventSourceId eventSource, ArtifactId aggregateRoot, CancellationToken cancellationToken); + IAsyncEnumerable + FetchStreamForAggregate(EventSourceId eventSource, ArtifactId aggregateRoot, CancellationToken cancellationToken); /// /// Fetches the applied to an Event Source by an Aggregate Root, filtered by Event Types. @@ -51,8 +54,9 @@ public interface IFetchCommittedEvents /// The of identified the event types that should be fetched. /// The . /// An of . - IAsyncEnumerable FetchStreamForAggregate(EventSourceId eventSource, ArtifactId aggregateRoot, IEnumerable eventTypes, CancellationToken cancellationToken); - + IAsyncEnumerable FetchStreamForAggregate(EventSourceId eventSource, ArtifactId aggregateRoot, IEnumerable eventTypes, + CancellationToken cancellationToken); + /// /// TODO: This should be made into a streaming call. /// Fetches all s applied to an Event Source by an Aggregate Root after the given version. @@ -62,5 +66,28 @@ public interface IFetchCommittedEvents /// The to fetch events after. /// The . /// A that, when resolved, returns the containing all applied to the Event Source by the Aggregate root, in the order of which they appear in the Event Log. - Task FetchForAggregateAfter(EventSourceId eventSource, ArtifactId aggregateRoot, AggregateRootVersion after, CancellationToken cancellationToken); + Task FetchForAggregateAfter(EventSourceId eventSource, ArtifactId aggregateRoot, AggregateRootVersion after, + CancellationToken cancellationToken); + + // /// + // /// Get the number of events matching the filter before and including the given . + // /// + // /// + // /// + // /// + // /// + // /// + // Task GetStreamPositionFromArtifactSet(ScopeId scope, EventLogSequenceNumber to, IEnumerable eventTypes, + // CancellationToken cancellationToken); + + // /// + // /// Get the number of events matching the filter before and including the given . + // /// + // /// + // /// + // /// + // /// + // /// + // Task> GetEventLogSequenceFromArtifactSet(ScopeId scope, StreamPosition nextStreamPosition, IEnumerable eventTypes, + // CancellationToken cancellationToken); } diff --git a/Source/Events/Store/IStreamProcessorStateRepository.cs b/Source/Events/Store/IStreamProcessorStateRepository.cs new file mode 100644 index 000000000..5509b5da2 --- /dev/null +++ b/Source/Events/Store/IStreamProcessorStateRepository.cs @@ -0,0 +1,62 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.EventHorizon.Consumer; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Rudimentary; + +namespace Dolittle.Runtime.Events.Store; + +/// +/// Defines a repository for . +/// +public interface IStreamProcessorStateRepository + where TId : IStreamProcessorId + where TState : IStreamProcessorState +{ + /// + /// Gets the for the given . + /// + /// The unique representing the . + /// The . + /// A that, when resolved, returns . + Task> TryGet(TId streamProcessorId, CancellationToken cancellationToken); + + /// + /// Gets the for the given from the correct + /// collection, either or . + /// + /// The to get the stream processor states from. + /// The . + /// A that, when resolved, returns . + IAsyncEnumerable> GetForScope(ScopeId scopeId, CancellationToken cancellationToken); + + /// + /// Persist the for and . + /// Handles separately also. + /// IsUpsert option creates the document if one isn't found. + /// + /// The . + /// The of and . + /// The . + /// A representing the asynchronous operation. + Task PersistForScope(ScopeId scope, IReadOnlyDictionary streamProcessorStates, CancellationToken cancellationToken); +} + +/// +/// Defines a repository for . +/// +public interface IStreamProcessorStateRepository : IStreamProcessorStateRepository +{ + /// + /// Gets the for the given from the correct + /// collection, either or . + /// + /// The . + /// A that, when resolved, returns . + IAsyncEnumerable> GetNonScoped(CancellationToken cancellationToken); +} diff --git a/Source/Events/Store/ISubscriptionStateRepository.cs b/Source/Events/Store/ISubscriptionStateRepository.cs new file mode 100644 index 000000000..49ea4687f --- /dev/null +++ b/Source/Events/Store/ISubscriptionStateRepository.cs @@ -0,0 +1,12 @@ +using Dolittle.Runtime.EventHorizon.Consumer; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store.Streams; + +namespace Dolittle.Runtime.Events.Store; + +/// +/// Defines a repository for . +/// +public interface ISubscriptionStateRepository : IStreamProcessorStateRepository +{ +} \ No newline at end of file diff --git a/Source/Events.Store/InconsistentNumberOfCommittedAggregateEvents.cs b/Source/Events/Store/InconsistentNumberOfCommittedAggregateEvents.cs similarity index 100% rename from Source/Events.Store/InconsistentNumberOfCommittedAggregateEvents.cs rename to Source/Events/Store/InconsistentNumberOfCommittedAggregateEvents.cs diff --git a/Source/Events.Store/Log.cs b/Source/Events/Store/Log.cs similarity index 87% rename from Source/Events.Store/Log.cs rename to Source/Events/Store/Log.cs index 603523caf..b55f712e9 100644 --- a/Source/Events.Store/Log.cs +++ b/Source/Events/Store/Log.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using Dolittle.Runtime.Events.Processing.Streams; using Microsoft.Extensions.Logging; using Proto; @@ -30,11 +31,15 @@ static partial class Log [LoggerMessage(0, LogLevel.Warning, "Error fetching events from aggregate")] internal static partial void ErrorFetchingEventsFromAggregate(this ILogger logger, Exception ex); - [LoggerMessage(0, LogLevel.Warning, "Error fetching catchup events")] + [LoggerMessage(0, LogLevel.Warning, "Error fetching catchup events. Will retry after debounce.")] internal static partial void ErrorFetchingCatchupEvents(this ILogger logger, Exception ex); - [LoggerMessage(0, LogLevel.Warning, "Error publishing subscribed events")] - internal static partial void ErrorPublishingSubscribedEvents(this ILogger logger, Exception ex); + [LoggerMessage(0, LogLevel.Warning, "Error publishing subscribed events for {SubscriptionName}")] + internal static partial void ErrorPublishingSubscribedEvents(this ILogger logger, Exception ex, string subscriptionName); + + + [LoggerMessage(0, LogLevel.Debug, "{StreamProcessorId}: EventLogSequenceNumber is already set - skipping")] + internal static partial void EventLogSequenceNumberAlreadySet(this ILogger logger, StreamProcessorId streamProcessorId); static readonly Action _eventsReceivedForCommitting = LoggerMessage .Define( @@ -57,7 +62,7 @@ internal static void LogUnexpectedOffset(this ILogger logger, EventLogSequenceNu static readonly Action _subscriptionReturnedDeadLetter = LoggerMessage .Define( - LogLevel.Warning, + LogLevel.Debug, new EventId(0, nameof(SubscriptionReturnedDeadLetter)), "Subscription target returned dead letter response"); diff --git a/Source/Events.Store/MissingEventsForExpectedAggregateRootVersion.cs b/Source/Events/Store/MissingEventsForExpectedAggregateRootVersion.cs similarity index 100% rename from Source/Events.Store/MissingEventsForExpectedAggregateRootVersion.cs rename to Source/Events/Store/MissingEventsForExpectedAggregateRootVersion.cs diff --git a/Source/Events.Store/NoEventsToCommit.cs b/Source/Events/Store/NoEventsToCommit.cs similarity index 100% rename from Source/Events.Store/NoEventsToCommit.cs rename to Source/Events/Store/NoEventsToCommit.cs diff --git a/Source/Events.Store/Persistence/Aggregate.cs b/Source/Events/Store/Persistence/Aggregate.cs similarity index 100% rename from Source/Events.Store/Persistence/Aggregate.cs rename to Source/Events/Store/Persistence/Aggregate.cs diff --git a/Source/Events.Store/Persistence/AggregateRootVersionRange.cs b/Source/Events/Store/Persistence/AggregateRootVersionRange.cs similarity index 100% rename from Source/Events.Store/Persistence/AggregateRootVersionRange.cs rename to Source/Events/Store/Persistence/AggregateRootVersionRange.cs diff --git a/Source/Events.Store/Persistence/Commit.cs b/Source/Events/Store/Persistence/Commit.cs similarity index 100% rename from Source/Events.Store/Persistence/Commit.cs rename to Source/Events/Store/Persistence/Commit.cs diff --git a/Source/Events.Store/Persistence/CommitBuilder.cs b/Source/Events/Store/Persistence/CommitBuilder.cs similarity index 100% rename from Source/Events.Store/Persistence/CommitBuilder.cs rename to Source/Events/Store/Persistence/CommitBuilder.cs diff --git a/Source/Events.Store/Persistence/CommitPipeline.cs b/Source/Events/Store/Persistence/CommitPipeline.cs similarity index 100% rename from Source/Events.Store/Persistence/CommitPipeline.cs rename to Source/Events/Store/Persistence/CommitPipeline.cs diff --git a/Source/Events.Store/Persistence/EventsForAggregateAlreadyAddedToCommit.cs b/Source/Events/Store/Persistence/EventsForAggregateAlreadyAddedToCommit.cs similarity index 100% rename from Source/Events.Store/Persistence/EventsForAggregateAlreadyAddedToCommit.cs rename to Source/Events/Store/Persistence/EventsForAggregateAlreadyAddedToCommit.cs diff --git a/Source/Events.Store/Persistence/IPersistCommits.cs b/Source/Events/Store/Persistence/IPersistCommits.cs similarity index 100% rename from Source/Events.Store/Persistence/IPersistCommits.cs rename to Source/Events/Store/Persistence/IPersistCommits.cs diff --git a/Source/Events.Store/ScopeId.cs b/Source/Events/Store/ScopeId.cs similarity index 100% rename from Source/Events.Store/ScopeId.cs rename to Source/Events/Store/ScopeId.cs diff --git a/Source/Events/Store/StreamProcessorStateWithId.cs b/Source/Events/Store/StreamProcessorStateWithId.cs new file mode 100644 index 000000000..a76827ce1 --- /dev/null +++ b/Source/Events/Store/StreamProcessorStateWithId.cs @@ -0,0 +1,15 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Store.Streams; + +namespace Dolittle.Runtime.Events.Store; + +/// +/// Represents both the with its corresponding . +/// +/// The . +/// The . +public record StreamProcessorStateWithId(TId Id, TState State) + where TId : IStreamProcessorId + where TState : IStreamProcessorState; diff --git a/Source/Events/Store/Streams/Actors/StreamProcessorActor.cs b/Source/Events/Store/Streams/Actors/StreamProcessorActor.cs new file mode 100644 index 000000000..79a92f92b --- /dev/null +++ b/Source/Events/Store/Streams/Actors/StreamProcessorActor.cs @@ -0,0 +1,17 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Store.Streams.Legacy; + + + +namespace Dolittle.Runtime.Events.Store.Streams.Actors; + +public class StreamProcessorActor +{ + readonly IStreamEventSubscriber _subscriber; + readonly IStreamProcessorStates _streamProcessorStates; + readonly IMapStreamPositionToEventLogPosition _eventLogPositionEnricher; + + +} diff --git a/Source/Events.Store/Streams/CannotGetPartitionedFetcherForEventLog.cs b/Source/Events/Store/Streams/CannotGetPartitionedFetcherForEventLog.cs similarity index 100% rename from Source/Events.Store/Streams/CannotGetPartitionedFetcherForEventLog.cs rename to Source/Events/Store/Streams/CannotGetPartitionedFetcherForEventLog.cs diff --git a/Source/Events.Store/Streams/CannotGetPartitionedFetcherForUnpartitionedStream.cs b/Source/Events/Store/Streams/CannotGetPartitionedFetcherForUnpartitionedStream.cs similarity index 100% rename from Source/Events.Store/Streams/CannotGetPartitionedFetcherForUnpartitionedStream.cs rename to Source/Events/Store/Streams/CannotGetPartitionedFetcherForUnpartitionedStream.cs diff --git a/Source/Events.Store/Streams/EventLogStreamDefinition.cs b/Source/Events/Store/Streams/EventLogStreamDefinition.cs similarity index 90% rename from Source/Events.Store/Streams/EventLogStreamDefinition.cs rename to Source/Events/Store/Streams/EventLogStreamDefinition.cs index ef04bbb92..5781ec432 100644 --- a/Source/Events.Store/Streams/EventLogStreamDefinition.cs +++ b/Source/Events/Store/Streams/EventLogStreamDefinition.cs @@ -21,4 +21,6 @@ public record EventLogStreamDefinition : IStreamDefinition /// public IFilterDefinition FilterDefinition => default; + + public static readonly EventLogStreamDefinition Instance = new(); } diff --git a/Source/Events.Processing/EventProcessorId.cs b/Source/Events/Store/Streams/EventProcessorId.cs similarity index 100% rename from Source/Events.Processing/EventProcessorId.cs rename to Source/Events/Store/Streams/EventProcessorId.cs diff --git a/Source/Events.Store/Streams/EventWaiter.cs b/Source/Events/Store/Streams/EventWaiter.cs similarity index 99% rename from Source/Events.Store/Streams/EventWaiter.cs rename to Source/Events/Store/Streams/EventWaiter.cs index 70d02d7cd..c61d4936a 100644 --- a/Source/Events.Store/Streams/EventWaiter.cs +++ b/Source/Events/Store/Streams/EventWaiter.cs @@ -18,7 +18,7 @@ public class EventWaiter { readonly object _lock = new(); readonly SortedList> _taskCompletionSources; - StreamPosition _lastNotified; + StreamPosition? _lastNotified; /// /// Initializes a new instance of the class. diff --git a/Source/Events.Store/Streams/EventWaiterId.cs b/Source/Events/Store/Streams/EventWaiterId.cs similarity index 100% rename from Source/Events.Store/Streams/EventWaiterId.cs rename to Source/Events/Store/Streams/EventWaiterId.cs diff --git a/Source/Events.Store/Streams/Filters/EventHorizon/IWriteEventsToPublicStreams.cs b/Source/Events/Store/Streams/Filters/EventHorizon/IWriteEventsToPublicStreams.cs similarity index 100% rename from Source/Events.Store/Streams/Filters/EventHorizon/IWriteEventsToPublicStreams.cs rename to Source/Events/Store/Streams/Filters/EventHorizon/IWriteEventsToPublicStreams.cs diff --git a/Source/Events.Store/Streams/Filters/EventHorizon/PublicFilterDefinition.cs b/Source/Events/Store/Streams/Filters/EventHorizon/PublicFilterDefinition.cs similarity index 100% rename from Source/Events.Store/Streams/Filters/EventHorizon/PublicFilterDefinition.cs rename to Source/Events/Store/Streams/Filters/EventHorizon/PublicFilterDefinition.cs diff --git a/Source/Events.Store/Streams/Filters/FilterDefinition.cs b/Source/Events/Store/Streams/Filters/FilterDefinition.cs similarity index 100% rename from Source/Events.Store/Streams/Filters/FilterDefinition.cs rename to Source/Events/Store/Streams/Filters/FilterDefinition.cs diff --git a/Source/Events.Store/Streams/Filters/FilterDefinitions.cs b/Source/Events/Store/Streams/Filters/FilterDefinitions.cs similarity index 100% rename from Source/Events.Store/Streams/Filters/FilterDefinitions.cs rename to Source/Events/Store/Streams/Filters/FilterDefinitions.cs diff --git a/Source/Events.Store/Streams/Filters/IFilterDefinition.cs b/Source/Events/Store/Streams/Filters/IFilterDefinition.cs similarity index 86% rename from Source/Events.Store/Streams/Filters/IFilterDefinition.cs rename to Source/Events/Store/Streams/Filters/IFilterDefinition.cs index 6c907c012..0038d0323 100644 --- a/Source/Events.Store/Streams/Filters/IFilterDefinition.cs +++ b/Source/Events/Store/Streams/Filters/IFilterDefinition.cs @@ -27,4 +27,9 @@ public interface IFilterDefinition /// Gets a value indicating whether the filter defines a public stream definition. /// bool Public { get; } + + /// + /// Determine if the filter supports validation + /// + public bool CanBeValidated => !Public; } \ No newline at end of file diff --git a/Source/Events.Store/Streams/Filters/IFilterDefinitions.cs b/Source/Events/Store/Streams/Filters/IFilterDefinitions.cs similarity index 100% rename from Source/Events.Store/Streams/Filters/IFilterDefinitions.cs rename to Source/Events/Store/Streams/Filters/IFilterDefinitions.cs diff --git a/Source/Events.Store/Streams/Filters/TypeFilterWithEventSourcePartitionDefinition.cs b/Source/Events/Store/Streams/Filters/TypeFilterWithEventSourcePartitionDefinition.cs similarity index 100% rename from Source/Events.Store/Streams/Filters/TypeFilterWithEventSourcePartitionDefinition.cs rename to Source/Events/Store/Streams/Filters/TypeFilterWithEventSourcePartitionDefinition.cs diff --git a/Source/Events.Store/Streams/ICanFetchEventTypesFromPartitionedStream.cs b/Source/Events/Store/Streams/ICanFetchEventTypesFromPartitionedStream.cs similarity index 100% rename from Source/Events.Store/Streams/ICanFetchEventTypesFromPartitionedStream.cs rename to Source/Events/Store/Streams/ICanFetchEventTypesFromPartitionedStream.cs diff --git a/Source/Events.Store/Streams/ICanFetchEventTypesFromStream.cs b/Source/Events/Store/Streams/ICanFetchEventTypesFromStream.cs similarity index 100% rename from Source/Events.Store/Streams/ICanFetchEventTypesFromStream.cs rename to Source/Events/Store/Streams/ICanFetchEventTypesFromStream.cs diff --git a/Source/Events/Store/Streams/ICanFetchEventsFromPartitionedStream.cs b/Source/Events/Store/Streams/ICanFetchEventsFromPartitionedStream.cs new file mode 100644 index 000000000..1d47dd1a0 --- /dev/null +++ b/Source/Events/Store/Streams/ICanFetchEventsFromPartitionedStream.cs @@ -0,0 +1,41 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Rudimentary; + +namespace Dolittle.Runtime.Events.Store.Streams; + +/// +/// Defines a system that can fetch events from streams. +/// +public interface ICanFetchEventsFromPartitionedStream : ICanFetchEventsFromStream +{ + /// + /// Fetch events in the given partition from a given . + /// + /// The . + /// the position in the stream. + /// The . + /// The with result. + Task>> FetchInPartition(PartitionId partitionId, StreamPosition position, CancellationToken cancellationToken); + + /// + /// Fetch events in the given partition from a given . + /// + /// The . + /// the from (inclusive) position in the stream. + /// the to(exclusive position in the stream. + /// + /// The . + /// The with result. + Task<(IList events, bool hasMoreEvents)> FetchInPartition(PartitionId partitionId, StreamPosition from, StreamPosition to, ISet artifactIds, + CancellationToken cancellationToken); + + Task<(StreamEvent? events, bool hasMoreEvents)> FetchNextEventInPartition(PartitionId partitionId, StreamPosition from, StreamPosition to, + ISet artifactIds, + CancellationToken cancellationToken); +} diff --git a/Source/Events.Store/Streams/ICanFetchEventsFromStream.cs b/Source/Events/Store/Streams/ICanFetchEventsFromStream.cs similarity index 54% rename from Source/Events.Store/Streams/ICanFetchEventsFromStream.cs rename to Source/Events/Store/Streams/ICanFetchEventsFromStream.cs index 54a00b08c..1ddbf03e7 100644 --- a/Source/Events.Store/Streams/ICanFetchEventsFromStream.cs +++ b/Source/Events/Store/Streams/ICanFetchEventsFromStream.cs @@ -16,10 +16,25 @@ public interface ICanFetchEventsFromStream /// /// Fetch the events from a given . /// - /// the position in the stream. + /// the position in the stream. /// The . /// The . - Task>> Fetch(StreamPosition streamPosition, CancellationToken cancellationToken); + Task>> Fetch(StreamPosition position, CancellationToken cancellationToken); + + /// + /// Fetch the events from a given . + /// + /// the position in the stream. + /// The . + /// The . + Task> FetchSingle(StreamPosition position, CancellationToken cancellationToken); + + /// + /// Fetch the last event written to the stream + /// + /// The . + /// The . + Task> FetchLast(CancellationToken cancellationToken); /// /// Gets the that will be used for the next event written to the stream. diff --git a/Source/Events.Store/Streams/ICanFetchRangeOfEventsFromStream.cs b/Source/Events/Store/Streams/ICanFetchRangeOfEventsFromStream.cs similarity index 100% rename from Source/Events.Store/Streams/ICanFetchRangeOfEventsFromStream.cs rename to Source/Events/Store/Streams/ICanFetchRangeOfEventsFromStream.cs diff --git a/Source/Events.Store/Streams/IEventFetchers.cs b/Source/Events/Store/Streams/IEventFetchers.cs similarity index 81% rename from Source/Events.Store/Streams/IEventFetchers.cs rename to Source/Events/Store/Streams/IEventFetchers.cs index f3f8645f2..a577076ab 100644 --- a/Source/Events.Store/Streams/IEventFetchers.cs +++ b/Source/Events/Store/Streams/IEventFetchers.cs @@ -17,7 +17,7 @@ public interface IEventFetchers /// The . /// The . /// The . - /// A that, whn resolved, returns the . + /// A that, when resolved, returns the . Task GetFetcherFor(ScopeId scopeId, IStreamDefinition streamDefinition, CancellationToken cancellationToken); /// @@ -26,7 +26,7 @@ public interface IEventFetchers /// The . /// The . /// The . - /// A that, whn resolved, returns the . + /// A that, when resolved, returns the . Task GetPartitionedFetcherFor(ScopeId scopeId, IStreamDefinition streamDefinition, CancellationToken cancellationToken); /// @@ -35,7 +35,7 @@ public interface IEventFetchers /// The . /// The . /// The . - /// A that, whn resolved, returns the . + /// A that, when resolved, returns the . Task GetRangeFetcherFor(ScopeId scopeId, IStreamDefinition streamDefinition, CancellationToken cancellationToken); /// @@ -44,7 +44,7 @@ public interface IEventFetchers /// The . /// The . /// The . - /// A that, whn resolved, returns the . + /// A that, when resolved, returns the . Task GetTypeFetcherFor(ScopeId scopeId, IStreamDefinition streamDefinition, CancellationToken cancellationToken); /// @@ -53,6 +53,6 @@ public interface IEventFetchers /// The . /// The . /// The . - /// A that, whn resolved, returns the . + /// A that, when resolved, returns the . Task GetPartitionedTypeFetcherFor(ScopeId scopeId, IStreamDefinition streamDefinition, CancellationToken cancellationToken); } diff --git a/Source/Events.Store/Streams/INotifyOfPublicStreamEvents.cs b/Source/Events/Store/Streams/INotifyOfPublicStreamEvents.cs similarity index 99% rename from Source/Events.Store/Streams/INotifyOfPublicStreamEvents.cs rename to Source/Events/Store/Streams/INotifyOfPublicStreamEvents.cs index 20b040b82..81f484b04 100644 --- a/Source/Events.Store/Streams/INotifyOfPublicStreamEvents.cs +++ b/Source/Events/Store/Streams/INotifyOfPublicStreamEvents.cs @@ -14,4 +14,4 @@ public interface INotifyOfPublicStreamEvents /// The of the stream. /// The of the event. void NotifyForEvent(StreamId stream, StreamPosition position); -} \ No newline at end of file +} diff --git a/Source/Events.Store/Streams/INotifyOfStreamEvents.cs b/Source/Events/Store/Streams/INotifyOfStreamEvents.cs similarity index 99% rename from Source/Events.Store/Streams/INotifyOfStreamEvents.cs rename to Source/Events/Store/Streams/INotifyOfStreamEvents.cs index 7510b61e6..8976278da 100644 --- a/Source/Events.Store/Streams/INotifyOfStreamEvents.cs +++ b/Source/Events/Store/Streams/INotifyOfStreamEvents.cs @@ -15,4 +15,4 @@ public interface INotifyOfStreamEvents /// The of the stream. /// The of the event. void NotifyForEvent(ScopeId scope, StreamId stream, StreamPosition position); -} \ No newline at end of file +} diff --git a/Source/Events.Store/Streams/IStreamDefinition.cs b/Source/Events/Store/Streams/IStreamDefinition.cs similarity index 100% rename from Source/Events.Store/Streams/IStreamDefinition.cs rename to Source/Events/Store/Streams/IStreamDefinition.cs diff --git a/Source/Events.Store/Streams/IStreamDefinitionRepository.cs b/Source/Events/Store/Streams/IStreamDefinitionRepository.cs similarity index 100% rename from Source/Events.Store/Streams/IStreamDefinitionRepository.cs rename to Source/Events/Store/Streams/IStreamDefinitionRepository.cs diff --git a/Source/Events.Store/Streams/IStreamDefinitions.cs b/Source/Events/Store/Streams/IStreamDefinitions.cs similarity index 100% rename from Source/Events.Store/Streams/IStreamDefinitions.cs rename to Source/Events/Store/Streams/IStreamDefinitions.cs diff --git a/Source/Events/Store/Streams/IStreamEventSubscriber.cs b/Source/Events/Store/Streams/IStreamEventSubscriber.cs new file mode 100644 index 000000000..34edaef7a --- /dev/null +++ b/Source/Events/Store/Streams/IStreamEventSubscriber.cs @@ -0,0 +1,32 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Channels; +using Dolittle.Runtime.Artifacts; + +namespace Dolittle.Runtime.Events.Store.Streams; + +public interface IStreamEventSubscriber +{ + public ChannelReader SubscribePublic(ProcessingPosition position, CancellationToken cancellationToken); + + /// + /// Subscribe to a stream of events for a specific scope and a set of event types. + /// + /// The source scope + /// The set of subscribed events + /// The to continue from (inclusive) + /// Whether the events should be tagged with "partitioned" + /// Identifier for the given subscription, used for debugging only + /// + /// + ChannelReader Subscribe( + ScopeId scopeId, + IReadOnlyCollection artifactIds, + ProcessingPosition position, + bool partitioned, + string subscriptionName, + CancellationToken cancellationToken); +} diff --git a/Source/Events.Store/Streams/IStreamEventWatcher.cs b/Source/Events/Store/Streams/IStreamEventWatcher.cs similarity index 100% rename from Source/Events.Store/Streams/IStreamEventWatcher.cs rename to Source/Events/Store/Streams/IStreamEventWatcher.cs diff --git a/Source/Events.Store/Streams/IStreamProcessorId.cs b/Source/Events/Store/Streams/IStreamProcessorId.cs similarity index 85% rename from Source/Events.Store/Streams/IStreamProcessorId.cs rename to Source/Events/Store/Streams/IStreamProcessorId.cs index 78fe364af..77f2fd78a 100644 --- a/Source/Events.Store/Streams/IStreamProcessorId.cs +++ b/Source/Events/Store/Streams/IStreamProcessorId.cs @@ -12,4 +12,6 @@ public interface IStreamProcessorId /// Gets the . /// ScopeId ScopeId { get; } -} \ No newline at end of file + + Dolittle.Runtime.Events.Store.Actors.StreamProcessorKey ToProtobuf(); +} diff --git a/Source/Events/Store/Streams/IStreamProcessorState.cs b/Source/Events/Store/Streams/IStreamProcessorState.cs new file mode 100644 index 000000000..10de20fa2 --- /dev/null +++ b/Source/Events/Store/Streams/IStreamProcessorState.cs @@ -0,0 +1,56 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store.Actors; + +namespace Dolittle.Runtime.Events.Store.Streams; + +public interface IStreamProcessorState +{ + /// + /// Gets the . + /// + ProcessingPosition Position { get; } + + /// + /// Gets a value indicating whether this is partitioned or not. + /// + bool Partitioned { get; } + + Bucket ToProtobuf(); + + /// + /// Get the earliest position that the stream processor needs to process. This is normally the same as the + /// but can be earlier in the stream if the stream processor is partitioned and there exists failing partitions. + /// + ProcessingPosition EarliestProcessingPosition { get; } + + public bool TryGetTimespanToRetry(out TimeSpan timeToRetry); + + public IStreamProcessorState WithResult(IProcessingResult result, StreamEvent processedEvent, DateTimeOffset timestamp); + public IStreamProcessorState WithFailure(IProcessingResult failedProcessing, StreamEvent processedEvent, DateTimeOffset retryAt, DateTimeOffset timestamp); + public IStreamProcessorState WithSuccessfullyProcessed(StreamEvent processedEvent, DateTimeOffset timestamp); +} + +/// +/// Defines the basis for the state of a . +/// +public interface IStreamProcessorState : IStreamProcessorState where T : IStreamProcessorState +{ + IStreamProcessorState IStreamProcessorState.WithResult(IProcessingResult result, StreamEvent processedEvent, DateTimeOffset timestamp) => + WithResult(result, processedEvent, timestamp); + + IStreamProcessorState IStreamProcessorState.WithFailure(IProcessingResult failedProcessing, StreamEvent processedEvent, DateTimeOffset retryAt, DateTimeOffset timestamp) => + WithFailure(failedProcessing, processedEvent, retryAt, timestamp); + + IStreamProcessorState IStreamProcessorState.WithSuccessfullyProcessed(StreamEvent processedEvent, DateTimeOffset timestamp) => + WithSuccessfullyProcessed(processedEvent, timestamp); + + public new T WithResult(IProcessingResult result, StreamEvent processedEvent, DateTimeOffset timestamp); + + public new T WithFailure(IProcessingResult failedProcessing, StreamEvent processedEvent, DateTimeOffset retryAt, DateTimeOffset timestamp); + public new T WithSuccessfullyProcessed(StreamEvent processedEvent, DateTimeOffset timestamp); +} diff --git a/Source/Events.Store/Streams/IStreamProcessorStateRepository.cs b/Source/Events/Store/Streams/IStreamProcessorStates.cs similarity index 97% rename from Source/Events.Store/Streams/IStreamProcessorStateRepository.cs rename to Source/Events/Store/Streams/IStreamProcessorStates.cs index cffa6cd28..95b8158f6 100644 --- a/Source/Events.Store/Streams/IStreamProcessorStateRepository.cs +++ b/Source/Events/Store/Streams/IStreamProcessorStates.cs @@ -10,7 +10,7 @@ namespace Dolittle.Runtime.Events.Store.Streams; /// /// Defines a system repository for stream processor states. /// -public interface IStreamProcessorStateRepository +public interface IStreamProcessorStates { /// /// Gets the for the given . @@ -28,4 +28,4 @@ public interface IStreamProcessorStateRepository /// The . /// A representing the asynchronous operation. Task Persist(IStreamProcessorId streamProcessorId, IStreamProcessorState streamProcessorState, CancellationToken cancellationToken); -} \ No newline at end of file +} diff --git a/Source/Events.Store/Streams/IWaitForEventInPublicStream.cs b/Source/Events/Store/Streams/IWaitForEventInPublicStream.cs similarity index 99% rename from Source/Events.Store/Streams/IWaitForEventInPublicStream.cs rename to Source/Events/Store/Streams/IWaitForEventInPublicStream.cs index 40bf08710..8e6e5f0b3 100644 --- a/Source/Events.Store/Streams/IWaitForEventInPublicStream.cs +++ b/Source/Events/Store/Streams/IWaitForEventInPublicStream.cs @@ -30,4 +30,4 @@ public interface IWaitForEventInPublicStream /// The . /// The representing the asynchronous operation. Task WaitForEvent(StreamId stream, StreamPosition position, CancellationToken token); -} \ No newline at end of file +} diff --git a/Source/Events.Store/Streams/IWaitForEventInStream.cs b/Source/Events/Store/Streams/IWaitForEventInStream.cs similarity index 99% rename from Source/Events.Store/Streams/IWaitForEventInStream.cs rename to Source/Events/Store/Streams/IWaitForEventInStream.cs index c644b04e6..dbbafb014 100644 --- a/Source/Events.Store/Streams/IWaitForEventInStream.cs +++ b/Source/Events/Store/Streams/IWaitForEventInStream.cs @@ -32,4 +32,4 @@ public interface IWaitForEventInStream /// The . /// The representing the asynchronous operation. Task WaitForEvent(ScopeId scope, StreamId stream, StreamPosition position, CancellationToken token); -} \ No newline at end of file +} diff --git a/Source/Events.Store/Streams/IWaitForEventsToBeAppendedToStream.cs b/Source/Events/Store/Streams/IWaitForEventsToBeAppendedToStream.cs similarity index 100% rename from Source/Events.Store/Streams/IWaitForEventsToBeAppendedToStream.cs rename to Source/Events/Store/Streams/IWaitForEventsToBeAppendedToStream.cs diff --git a/Source/Events.Store/Streams/IWriteEventsToStreams.cs b/Source/Events/Store/Streams/IWriteEventsToStreams.cs similarity index 100% rename from Source/Events.Store/Streams/IWriteEventsToStreams.cs rename to Source/Events/Store/Streams/IWriteEventsToStreams.cs diff --git a/Source/Events/Store/Streams/Legacy/EventLogSequenceFromStreamPosition.cs b/Source/Events/Store/Streams/Legacy/EventLogSequenceFromStreamPosition.cs new file mode 100644 index 000000000..5054a179b --- /dev/null +++ b/Source/Events/Store/Streams/Legacy/EventLogSequenceFromStreamPosition.cs @@ -0,0 +1,58 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.DependencyInversion.Lifecycle; +using Dolittle.Runtime.DependencyInversion.Scoping; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store.Streams.Filters; +using Dolittle.Runtime.Rudimentary; + +namespace Dolittle.Runtime.Events.Store.Streams.Legacy; + +[Singleton, PerTenant] +public class EventLogSequenceFromStreamPosition: IGetEventLogSequenceFromStreamPosition +{ + readonly IEventFetchers _eventFetchers; + + public EventLogSequenceFromStreamPosition(IEventFetchers eventFetchers) + { + _eventFetchers = eventFetchers; + } + + /// + /// + /// + /// + /// + /// + /// + /// + public async Task> TryGetEventLogPositionForStreamProcessor(StreamProcessorId id, bool partitioned, StreamPosition streamPosition, + CancellationToken cancellationToken) + { + var sourceStream = new StreamId(id.SourceStreamId); + IStreamDefinition streamDefinition = new StreamDefinition(new FilterDefinition(sourceStream, sourceStream, partitioned)); + var fetcher = await _eventFetchers.GetFetcherFor(id.ScopeId, streamDefinition, cancellationToken); + + var eventFromStream = await fetcher.FetchSingle(streamPosition, cancellationToken); + + if (!eventFromStream.Success) + { + // We are at the end of the stream, get the last event + var lastEvent = await fetcher.FetchLast(cancellationToken); + if (lastEvent.Success) + { + return lastEvent.Result.Event.EventLogSequenceNumber.Increment(); + } + // No Events, start from the beginning + return EventLogSequenceNumber.Initial; + } + + + + return eventFromStream.Result.Event.EventLogSequenceNumber; + } +} diff --git a/Source/Events/Store/Streams/Legacy/Extensions.cs b/Source/Events/Store/Streams/Legacy/Extensions.cs new file mode 100644 index 000000000..6e9c01af2 --- /dev/null +++ b/Source/Events/Store/Streams/Legacy/Extensions.cs @@ -0,0 +1,24 @@ +// // Copyright (c) Dolittle. All rights reserved. +// // Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// using System.Linq; +// using System.Threading; +// using System.Threading.Tasks; +// using Dolittle.Runtime.Events.Processing.Streams; +// +// namespace Dolittle.Runtime.Events.Store.Streams.Legacy; +// +// static class Extensions +// { +// public static async Task FetchEventLogSequenceNumberAsync(this ICanFetchRangeOfEventsFromStream fetcher, StreamProcessorId id, StreamPosition position, +// CancellationToken cancellationToken) +// { +// var evt = await fetcher.FetchRange(new StreamPositionRange(position, 1), cancellationToken).Take(1).SingleAsync(cancellationToken); +// if (position != evt.Position) +// { +// throw new StreamProcessorStateDoesNotExist(id); +// } +// +// return evt.Event.EventLogSequenceNumber; +// } +// } diff --git a/Source/Events/Store/Streams/Legacy/IGetEventLogSequenceFromStreamPosition.cs b/Source/Events/Store/Streams/Legacy/IGetEventLogSequenceFromStreamPosition.cs new file mode 100644 index 000000000..0acab651a --- /dev/null +++ b/Source/Events/Store/Streams/Legacy/IGetEventLogSequenceFromStreamPosition.cs @@ -0,0 +1,15 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Rudimentary; + +namespace Dolittle.Runtime.Events.Store.Streams.Legacy; + +public interface IGetEventLogSequenceFromStreamPosition +{ + Task> TryGetEventLogPositionForStreamProcessor(StreamProcessorId id, bool partitioned, StreamPosition streamPosition, + CancellationToken cancellationToken); +} diff --git a/Source/Events/Store/Streams/Legacy/StreamPositionToEventLogPositionService.cs b/Source/Events/Store/Streams/Legacy/StreamPositionToEventLogPositionService.cs new file mode 100644 index 000000000..723b2d2a7 --- /dev/null +++ b/Source/Events/Store/Streams/Legacy/StreamPositionToEventLogPositionService.cs @@ -0,0 +1,114 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.DependencyInversion.Lifecycle; +using Dolittle.Runtime.DependencyInversion.Scoping; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Rudimentary; +using Microsoft.Extensions.Logging; +using StreamProcessorState = Dolittle.Runtime.Events.Processing.Streams.StreamProcessorState; + +namespace Dolittle.Runtime.Events.Store.Streams.Legacy; + +public interface IMapStreamPositionToEventLogPosition +{ + Task> WithEventLogSequence(StreamProcessorStateWithId request, + CancellationToken cancellationToken); +} + +[Singleton, PerTenant] +public class StreamPositionToEventLogPositionService : IMapStreamPositionToEventLogPosition +{ + readonly ILogger _logger; + readonly IGetEventLogSequenceFromStreamPosition _getEventLogSequenceFromStreamPosition; + + public StreamPositionToEventLogPositionService( + ILogger logger, IGetEventLogSequenceFromStreamPosition getEventLogSequenceFromStreamPosition) + { + _logger = logger; + _getEventLogSequenceFromStreamPosition = getEventLogSequenceFromStreamPosition; + } + + public Task> WithEventLogSequence(StreamProcessorStateWithId request, + CancellationToken cancellationToken) + { + if (request.State.Position.EventLogPosition.Value > EventLogSequenceNumber.Initial.Value) + { + _logger.EventLogSequenceNumberAlreadySet(request.Id); + return Task.FromResult(Try.Succeeded(request.State)); + } + + return request.State switch + { + Dolittle.Runtime.Events.Processing.Streams.Partitioned.StreamProcessorState state => FetchForPartitioned(request.Id, state, cancellationToken), + StreamProcessorState state => FetchForNonPartitioned(request.Id, state, cancellationToken), + _ => Task.FromResult(Try.Failed(new ArgumentOutOfRangeException(nameof(request)))) + }; + } + + Task> FetchForPartitioned( + StreamProcessorId id, + Processing.Streams.Partitioned.StreamProcessorState state, + CancellationToken cancellationToken) => + Try.DoAsync(async () => state with + { + Position = state.Position with + { + EventLogPosition = await GetEventLogPosition(id, true, state.Position.StreamPosition, cancellationToken) + }, + FailingPartitions = await Enrich(id, state.FailingPartitions, cancellationToken) + }); + + async Task GetEventLogPosition(StreamProcessorId id, bool partitioned, StreamPosition streamPosition, CancellationToken cancellationToken) + { + if(streamPosition == StreamPosition.Start) + { + return EventLogSequenceNumber.Initial; + } + var eventLogPosition = await _getEventLogSequenceFromStreamPosition.TryGetEventLogPositionForStreamProcessor(id, partitioned, streamPosition, cancellationToken); + + if (!eventLogPosition.Success) + { + throw eventLogPosition.Exception; + } + + return eventLogPosition.Result; + } + + async Task> Enrich(StreamProcessorId id, + ImmutableDictionary failingPartitions, CancellationToken cancellationToken) + { + if (failingPartitions.Count == 0) return failingPartitions; + + var enriched = new Dictionary(); + + foreach (var failingPartition in failingPartitions) + { + enriched.Add(failingPartition.Key, failingPartition.Value with + { + Position = failingPartition.Value.Position with + { + EventLogPosition = await GetEventLogPosition(id, true, failingPartition.Value.Position.StreamPosition, cancellationToken) + }, + }); + } + + return enriched.ToImmutableDictionary(); + } + + Task> FetchForNonPartitioned(StreamProcessorId id, StreamProcessorState state, + CancellationToken cancellationToken) => + Try.DoAsync(async () => state with + { + Position = state.Position with + { + EventLogPosition = await GetEventLogPosition(id, false, state.Position.StreamPosition, cancellationToken) + } + }); +} diff --git a/Source/Events.Store/Streams/LoggerExtensions.cs b/Source/Events/Store/Streams/LoggerExtensions.cs similarity index 90% rename from Source/Events.Store/Streams/LoggerExtensions.cs rename to Source/Events/Store/Streams/LoggerExtensions.cs index 0e903da21..ebdd0494b 100644 --- a/Source/Events.Store/Streams/LoggerExtensions.cs +++ b/Source/Events/Store/Streams/LoggerExtensions.cs @@ -8,25 +8,25 @@ namespace Dolittle.Runtime.Events.Store.Streams; static class LoggerExtensions { - static readonly Action _waitForEventAtPosition = LoggerMessage + static readonly Action _waitForEventAtPosition = LoggerMessage .Define( LogLevel.Trace, new EventId(2059664795, nameof(WaitForEventAtPosition)), "Start waiting for event coming in at position: {Position} in {IsPublic}stream: {StreamId} in scope: {Scope}"); - static readonly Action _waitForEventAppended = LoggerMessage + static readonly Action _waitForEventAppended = LoggerMessage .Define( LogLevel.Trace, new EventId(2059674795, nameof(WaitForEventAppended)), "Start waiting for event to be appended to {IsPublic}stream: {StreamId} in scope: {Scope}"); - static readonly Action _waiterNotifyForEvent = LoggerMessage + static readonly Action _waiterNotifyForEvent = LoggerMessage .Define( LogLevel.Trace, new EventId(255784820, nameof(WaiterNotifyForEvent)), "Notifying that an event has been written at position: {Position} in {IsPublic}stream: {StreamId} in scope: {Scope}"); - static readonly Action _waitingTimedOut = LoggerMessage + static readonly Action _waitingTimedOut = LoggerMessage .Define( LogLevel.Trace, new EventId(188707764, nameof(WaitingTimedOut)), @@ -43,4 +43,4 @@ internal static void WaiterNotifyForEvent(this ILogger logger, StreamPosition po internal static void WaitingTimedOut(this ILogger logger, EventWaiterId eventWaiter) => _waitingTimedOut(logger, eventWaiter, null); -} \ No newline at end of file +} diff --git a/Source/Events.Store/Streams/NoEventFetcherForStream.cs b/Source/Events/Store/Streams/NoEventFetcherForStream.cs similarity index 100% rename from Source/Events.Store/Streams/NoEventFetcherForStream.cs rename to Source/Events/Store/Streams/NoEventFetcherForStream.cs diff --git a/Source/Events.Store/Streams/NoEventInPartitionInStreamFromPosition.cs b/Source/Events/Store/Streams/NoEventInPartitionInStreamFromPosition.cs similarity index 100% rename from Source/Events.Store/Streams/NoEventInPartitionInStreamFromPosition.cs rename to Source/Events/Store/Streams/NoEventInPartitionInStreamFromPosition.cs diff --git a/Source/Events.Store/Streams/NoEventInStreamAtPosition.cs b/Source/Events/Store/Streams/NoEventInStreamAtPosition.cs similarity index 100% rename from Source/Events.Store/Streams/NoEventInStreamAtPosition.cs rename to Source/Events/Store/Streams/NoEventInStreamAtPosition.cs diff --git a/Source/Events.Store/Streams/PartitionId.cs b/Source/Events/Store/Streams/PartitionId.cs similarity index 100% rename from Source/Events.Store/Streams/PartitionId.cs rename to Source/Events/Store/Streams/PartitionId.cs diff --git a/Source/Events/Store/Streams/ProcessingPosition.cs b/Source/Events/Store/Streams/ProcessingPosition.cs new file mode 100644 index 000000000..7ba71cf53 --- /dev/null +++ b/Source/Events/Store/Streams/ProcessingPosition.cs @@ -0,0 +1,52 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Dolittle.Runtime.Events.Store.Streams; + +/// +/// +/// +/// Number of processed events in the stream +/// The current event log position the stream has reached +public record ProcessingPosition(StreamPosition StreamPosition, EventLogSequenceNumber EventLogPosition) : IComparable +{ + public static readonly ProcessingPosition Initial = new(StreamPosition.Start, EventLogSequenceNumber.Initial); + + public int CompareTo(ProcessingPosition? other) + { + if (ReferenceEquals(this, other)) return 0; + if (other is null) return 1; + var eventLogPositionComparison = EventLogPosition.CompareTo(other.EventLogPosition); + return eventLogPositionComparison != 0 ? eventLogPositionComparison : EventLogPosition.CompareTo(other.EventLogPosition); + } + + /// + /// The current event was included in the stream, increment the stream position as well as the event log position + /// + /// + public ProcessingPosition IncrementWithStream() + { + return new(StreamPosition.Increment(), EventLogPosition.Increment()); + } + + /// + /// The current event was not included in the stream, only increment the event log position + /// + /// + public ProcessingPosition IncrementEventLogOnly() + { + return this with { EventLogPosition = EventLogPosition.Increment() }; + } + + /// + /// If the event log position has not been initialized, + /// the processing position is not valid before the event log position has been retrieved based on the stream position + /// + /// + public bool HasStreamPositionOnly() + { + return StreamPosition.Value > 0 && EventLogPosition.Value == 0; + } +} diff --git a/Source/Events.Store/Streams/StreamDefinition.cs b/Source/Events/Store/Streams/StreamDefinition.cs similarity index 100% rename from Source/Events.Store/Streams/StreamDefinition.cs rename to Source/Events/Store/Streams/StreamDefinition.cs diff --git a/Source/Events.Store/Streams/StreamDefinitionDoesNotExist.cs b/Source/Events/Store/Streams/StreamDefinitionDoesNotExist.cs similarity index 100% rename from Source/Events.Store/Streams/StreamDefinitionDoesNotExist.cs rename to Source/Events/Store/Streams/StreamDefinitionDoesNotExist.cs diff --git a/Source/Events.Store/Streams/StreamDefinitions.cs b/Source/Events/Store/Streams/StreamDefinitions.cs similarity index 100% rename from Source/Events.Store/Streams/StreamDefinitions.cs rename to Source/Events/Store/Streams/StreamDefinitions.cs diff --git a/Source/Events.Store/Streams/StreamEvent.cs b/Source/Events/Store/Streams/StreamEvent.cs similarity index 64% rename from Source/Events.Store/Streams/StreamEvent.cs rename to Source/Events/Store/Streams/StreamEvent.cs index 1cc52c632..1146b8ac5 100644 --- a/Source/Events.Store/Streams/StreamEvent.cs +++ b/Source/Events/Store/Streams/StreamEvent.cs @@ -6,4 +6,9 @@ namespace Dolittle.Runtime.Events.Store.Streams; /// /// Represents a that is a part of a stream. /// -public record StreamEvent(CommittedEvent Event, StreamPosition Position, StreamId Stream, PartitionId Partition, bool Partitioned); \ No newline at end of file +public record StreamEvent(CommittedEvent Event, StreamPosition Position, StreamId Stream, PartitionId Partition, bool Partitioned) +{ + public ProcessingPosition NextProcessingPosition => new(Position.Increment(), Event.EventLogSequenceNumber.Increment()); + public ProcessingPosition CurrentProcessingPosition => new(Position, Event.EventLogSequenceNumber); + +} diff --git a/Source/Events/Store/Streams/StreamEventSubscriber.cs b/Source/Events/Store/Streams/StreamEventSubscriber.cs new file mode 100644 index 000000000..839d7513e --- /dev/null +++ b/Source/Events/Store/Streams/StreamEventSubscriber.cs @@ -0,0 +1,95 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Channels; +using System.Threading.Tasks; +using Dolittle.Runtime.Artifacts; +using Dolittle.Runtime.DependencyInversion.Lifecycle; +using Dolittle.Runtime.DependencyInversion.Scoping; +using Dolittle.Runtime.Protobuf; + +namespace Dolittle.Runtime.Events.Store.Streams; + +[Singleton, PerTenant] +public class StreamEventSubscriber : IStreamEventSubscriber +{ + const int ChannelCapacity = 100; + readonly IEventLogStream _eventLogStream; + + public StreamEventSubscriber(IEventLogStream eventLogStream) => _eventLogStream = eventLogStream; + + public ChannelReader SubscribePublic(ProcessingPosition position, CancellationToken cancellationToken) + { + var channel = Channel.CreateBounded(ChannelCapacity); + ToStreamEvents( + _eventLogStream.SubscribePublic(position.EventLogPosition, cancellationToken), + channel.Writer, + position, + evt => evt.Public, + false, + cancellationToken); + return channel.Reader; + } + + public ChannelReader Subscribe( + ScopeId scopeId, + IReadOnlyCollection artifactIds, + ProcessingPosition position, + bool partitioned, + string subscriptionName, + CancellationToken cancellationToken) + { + var eventTypes = artifactIds.Select(_ => _.Value.ToProtobuf()).ToHashSet(); + + var channel = Channel.CreateBounded(ChannelCapacity); + ToStreamEvents( + _eventLogStream.Subscribe(scopeId, position.EventLogPosition, artifactIds, subscriptionName, cancellationToken), + channel.Writer, + position, + evt => eventTypes.Contains(evt.EventType.Id), + partitioned, + cancellationToken); + return channel.Reader; + } + + static void ToStreamEvents(ChannelReader reader, ChannelWriter writer, ProcessingPosition startingPosition, + Func include, bool partitioned, + CancellationToken cancellationToken) => + _ = Task.Run(async () => + { + var current = startingPosition.StreamPosition; + + try + { + while (!cancellationToken.IsCancellationRequested) + { + var eventLogBatch = await reader.ReadAsync(cancellationToken); + + foreach (var evt in eventLogBatch.MatchedEvents) + { + if (include(evt)) + { + var streamEvent = new StreamEvent(evt.FromProtobuf(), current, StreamId.EventLog, evt.EventSourceId, partitioned); + // ReSharper disable once MethodSupportsCancellation + await writer.WriteAsync(streamEvent); + current = current.Increment(); + } + } + } + + writer.TryComplete(); + } + catch (ChannelClosedException) + { + writer.TryComplete(); + } + catch (Exception e) + { + writer.TryComplete(e); + } + }, CancellationToken.None); +} diff --git a/Source/Events.Store/Streams/StreamEventWatcher.cs b/Source/Events/Store/Streams/StreamEventWatcher.cs similarity index 100% rename from Source/Events.Store/Streams/StreamEventWatcher.cs rename to Source/Events/Store/Streams/StreamEventWatcher.cs diff --git a/Source/Events.Store/Streams/StreamId.cs b/Source/Events/Store/Streams/StreamId.cs similarity index 80% rename from Source/Events.Store/Streams/StreamId.cs rename to Source/Events/Store/Streams/StreamId.cs index b3c538de2..6abc53fc2 100644 --- a/Source/Events.Store/Streams/StreamId.cs +++ b/Source/Events/Store/Streams/StreamId.cs @@ -26,10 +26,16 @@ public record StreamId(Guid Value) : ConceptAs(Value) /// /// representation. public static implicit operator StreamId(Guid streamId) => new(streamId); + + /// + /// Implicitly convert from a to a . + /// + /// representation. + public static implicit operator StreamId(string streamId) => new(Guid.Parse(streamId)); /// /// Creates a new instance of with a unique id. /// /// A new . public static StreamId New() => Guid.NewGuid(); -} \ No newline at end of file +} diff --git a/Source/Events.Store/Streams/StreamPosition.cs b/Source/Events/Store/Streams/StreamPosition.cs similarity index 100% rename from Source/Events.Store/Streams/StreamPosition.cs rename to Source/Events/Store/Streams/StreamPosition.cs diff --git a/Source/Events.Store/Streams/StreamPositionRange.cs b/Source/Events/Store/Streams/StreamPositionRange.cs similarity index 100% rename from Source/Events.Store/Streams/StreamPositionRange.cs rename to Source/Events/Store/Streams/StreamPositionRange.cs diff --git a/Source/Events/Store/Streams/StreamProcessorId.cs b/Source/Events/Store/Streams/StreamProcessorId.cs new file mode 100644 index 000000000..96d250e07 --- /dev/null +++ b/Source/Events/Store/Streams/StreamProcessorId.cs @@ -0,0 +1,37 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Actors; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Protobuf; + +namespace Dolittle.Runtime.Events.Processing.Streams; + +/// +/// Represents a unique key for a . +/// +/// The . +/// . +/// The . +public record StreamProcessorId(ScopeId ScopeId, EventProcessorId EventProcessorId, StreamId SourceStreamId) : IStreamProcessorId +{ + /// + public override string ToString() => $"Scope: {ScopeId.Value} Event Processor Id: {EventProcessorId.Value} Source Stream: {SourceStreamId.Value}"; + + public static StreamProcessorId FromProtobuf(Dolittle.Runtime.Events.Store.Actors.StreamProcessorId streamProcessorId) + => new( + streamProcessorId.ScopeId.ToGuid(), + streamProcessorId.EventProcessorId.ToGuid(), + streamProcessorId.SourceStreamId.ToGuid()); + + public StreamProcessorKey ToProtobuf() => new() + { + StreamProcessorId = new Store.Actors.StreamProcessorId + { + ScopeId = ScopeId.ToProtobuf(), + EventProcessorId = EventProcessorId.ToProtobuf(), + SourceStreamId = SourceStreamId.ToProtobuf() + }, + }; +} diff --git a/Source/Events.Store/Streams/StreamProcessorStateDoesNotExist.cs b/Source/Events/Store/Streams/StreamProcessorStateDoesNotExist.cs similarity index 100% rename from Source/Events.Store/Streams/StreamProcessorStateDoesNotExist.cs rename to Source/Events/Store/Streams/StreamProcessorStateDoesNotExist.cs diff --git a/Source/Events/Store/Streams/StreamProcessorStatesClient.cs b/Source/Events/Store/Streams/StreamProcessorStatesClient.cs new file mode 100644 index 000000000..4dab03c58 --- /dev/null +++ b/Source/Events/Store/Streams/StreamProcessorStatesClient.cs @@ -0,0 +1,92 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.DependencyInversion.Lifecycle; +using Dolittle.Runtime.DependencyInversion.Scoping; +using Dolittle.Runtime.Events.Store.Actors; +using Dolittle.Runtime.Rudimentary; + +namespace Dolittle.Runtime.Events.Store.Streams; + +/// +/// Represents an implementation of . +/// +[Singleton, PerTenant] +public class StreamProcessorStatesClient : IStreamProcessorStates +{ + readonly StreamProcessorStateClient _streamProcessorStateClient; + readonly StreamSubscriptionStateClient _streamSubscriptionStateClient; + + /// + /// Initializes a new instance of the class. + /// + /// The . + /// The . + public StreamProcessorStatesClient(StreamProcessorStateClient streamProcessorStateClient, + StreamSubscriptionStateClient streamSubscriptionStateClient) + { + _streamProcessorStateClient = streamProcessorStateClient; + _streamSubscriptionStateClient = streamSubscriptionStateClient; + } + + /// + /// + public Task> TryGetFor(IStreamProcessorId streamProcessorId, CancellationToken cancellationToken) + { + return Try.DoAsync(async () => + { + var processorKey = streamProcessorId.ToProtobuf(); + switch (processorKey.IdCase) + { + case StreamProcessorKey.IdOneofCase.StreamProcessorId: + var response = await _streamProcessorStateClient.GetByProcessorId(processorKey.StreamProcessorId, cancellationToken).ConfigureAwait(false); + return ToResponse(streamProcessorId, response); + + case StreamProcessorKey.IdOneofCase.SubscriptionId: + return ToResponse(streamProcessorId, + await _streamSubscriptionStateClient.GetBySubscriptionId(processorKey.SubscriptionId, cancellationToken).ConfigureAwait(false)); + + case StreamProcessorKey.IdOneofCase.None: + default: + throw new ArgumentOutOfRangeException(nameof(streamProcessorId)); + } + }); + + static IStreamProcessorState ToResponse(IStreamProcessorId processorId, StreamProcessorStateResponse? response) + { + return response!.Bucket.Count switch + { + 0 => throw new StreamProcessorStateDoesNotExist(processorId), + 1 => response!.Bucket.Single().FromProtobuf(), + _ => throw new ArgumentOutOfRangeException("State contains more than one bucket, not yet supported") + }; + } + } + + /// + public async Task Persist(IStreamProcessorId streamProcessorId, IStreamProcessorState streamProcessorState, CancellationToken cancellationToken) + { + var processorKey = streamProcessorId.ToProtobuf(); + var request = new SetStreamProcessorStateRequest + { + StreamKey = processorKey, + Bucket = streamProcessorState.ToProtobuf() + }; + switch (processorKey.IdCase) + { + case StreamProcessorKey.IdOneofCase.StreamProcessorId: + await _streamProcessorStateClient.SetByProcessorId(request, cancellationToken).ConfigureAwait(false); + return; + case StreamProcessorKey.IdOneofCase.SubscriptionId: + await _streamSubscriptionStateClient.SetBySubscriptionId(request, cancellationToken).ConfigureAwait(false); + return; + case StreamProcessorKey.IdOneofCase.None: + default: + throw new ArgumentOutOfRangeException(nameof(streamProcessorId)); + } + } +} diff --git a/Source/Events.Store/UncommittedAggregateEvents.cs b/Source/Events/Store/UncommittedAggregateEvents.cs similarity index 100% rename from Source/Events.Store/UncommittedAggregateEvents.cs rename to Source/Events/Store/UncommittedAggregateEvents.cs diff --git a/Source/Events.Store/UncommittedEvent.cs b/Source/Events/Store/UncommittedEvent.cs similarity index 100% rename from Source/Events.Store/UncommittedEvent.cs rename to Source/Events/Store/UncommittedEvent.cs diff --git a/Source/Events.Store/UncommittedEvents.cs b/Source/Events/Store/UncommittedEvents.cs similarity index 100% rename from Source/Events.Store/UncommittedEvents.cs rename to Source/Events/Store/UncommittedEvents.cs diff --git a/Source/Events.Store/UnsupportedFetchForAggregatesInBatchesType.cs b/Source/Events/Store/UnsupportedFetchForAggregatesInBatchesType.cs similarity index 100% rename from Source/Events.Store/UnsupportedFetchForAggregatesInBatchesType.cs rename to Source/Events/Store/UnsupportedFetchForAggregatesInBatchesType.cs diff --git a/Source/Hosting/Scopes/ScopedHostBuilder.cs b/Source/Hosting/Scopes/ScopedHostBuilder.cs index 8be01bd17..b6c1c5f02 100644 --- a/Source/Hosting/Scopes/ScopedHostBuilder.cs +++ b/Source/Hosting/Scopes/ScopedHostBuilder.cs @@ -58,10 +58,12 @@ public IHostBuilder ConfigureServices(Action public IHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory) + where TContainerBuilder: notnull => throw new OperationNotSupportedOnScopedHostBuilder(nameof(UseServiceProviderFactory)); /// public IHostBuilder UseServiceProviderFactory(Func> factory) + where TContainerBuilder: notnull => throw new OperationNotSupportedOnScopedHostBuilder(nameof(UseServiceProviderFactory)); /// diff --git a/Source/Metrics/Hosting/HostBuilderExtensions.cs b/Source/Metrics/Hosting/HostBuilderExtensions.cs index d1e7c63e9..6d972631b 100644 --- a/Source/Metrics/Hosting/HostBuilderExtensions.cs +++ b/Source/Metrics/Hosting/HostBuilderExtensions.cs @@ -9,7 +9,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Prometheus; -using Prometheus.DotNetRuntime; namespace Dolittle.Runtime.Metrics.Hosting; diff --git a/Source/MongoDB/UpsertHelpers.cs b/Source/MongoDB/UpsertHelpers.cs new file mode 100644 index 000000000..b22fd3b2d --- /dev/null +++ b/Source/MongoDB/UpsertHelpers.cs @@ -0,0 +1,27 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using MongoDB.Driver; + +namespace Dolittle.Runtime.MongoDB; + +public static class UpsertHelpers where TV : class +{ + static readonly FilterDefinitionBuilder _filterDefinitionBuilder = new(); + + public static async Task UpsertMany(IMongoCollection collection, IReadOnlyDictionary entities) + { + if (entities.Count == 0) + { + return; + } + + await collection.BulkWriteAsync(entities.Select(e => new ReplaceOneModel(_filterDefinitionBuilder.Eq("_id", e.Key), e.Value) + { + IsUpsert = true, + })); + } +} diff --git a/Source/Platform/Handshake/IRequestConverter.cs b/Source/Platform/Handshake/IRequestConverter.cs index be7966ade..bb247bfba 100644 --- a/Source/Platform/Handshake/IRequestConverter.cs +++ b/Source/Platform/Handshake/IRequestConverter.cs @@ -1,6 +1,7 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; using Dolittle.Runtime.Handshake.Contracts; using Dolittle.Runtime.Protobuf; @@ -18,5 +19,5 @@ public interface IRequestConverter /// The parsed handshake request, if parsing succeeded. /// The failure, if the parsing failed. /// True if the parsing succeeded, false if not. - bool TryConvert(HandshakeRequest request, out Request parsed, out Failure failure); + bool TryConvert(HandshakeRequest request, [NotNullWhen(true)] out Request? parsed, [NotNullWhen(false)] out Failure? failure); } diff --git a/Source/Platform/Handshake/RequestConverter.cs b/Source/Platform/Handshake/RequestConverter.cs index 71d78e84d..63938098f 100644 --- a/Source/Platform/Handshake/RequestConverter.cs +++ b/Source/Platform/Handshake/RequestConverter.cs @@ -1,6 +1,7 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; using Dolittle.Runtime.Client; using Dolittle.Runtime.Handshake.Contracts; using Dolittle.Runtime.Protobuf; @@ -13,7 +14,7 @@ namespace Dolittle.Runtime.Platform.Handshake; public class RequestConverter : IRequestConverter { /// - public bool TryConvert(HandshakeRequest request, out Request parsed, out Failure failure) + public bool TryConvert(HandshakeRequest request, [NotNullWhen(true)] out Request? parsed, [NotNullWhen(false)] out Failure? failure) { parsed = null; if (string.IsNullOrWhiteSpace(request.SdkIdentifier)) diff --git a/Source/Platform/Platform.csproj b/Source/Platform/Platform.csproj index de55a9f33..59736e73d 100644 --- a/Source/Platform/Platform.csproj +++ b/Source/Platform/Platform.csproj @@ -10,7 +10,7 @@ - - + + diff --git a/Source/Projections.Store.Copies.MongoDB/Projections.Store.Copies.MongoDB.csproj b/Source/Projections.Store.Copies.MongoDB/Projections.Store.Copies.MongoDB.csproj index 3f5cb5860..7225aa83d 100644 --- a/Source/Projections.Store.Copies.MongoDB/Projections.Store.Copies.MongoDB.csproj +++ b/Source/Projections.Store.Copies.MongoDB/Projections.Store.Copies.MongoDB.csproj @@ -11,7 +11,7 @@ - + diff --git a/Source/Projections.Store.MongoDB/Projections.Store.MongoDB.csproj b/Source/Projections.Store.MongoDB/Projections.Store.MongoDB.csproj index 209a48ca9..bbaa7346e 100644 --- a/Source/Projections.Store.MongoDB/Projections.Store.MongoDB.csproj +++ b/Source/Projections.Store.MongoDB/Projections.Store.MongoDB.csproj @@ -8,12 +8,11 @@ - - + diff --git a/Source/Projections.Store.MongoDB/State/ProjectionStates.cs b/Source/Projections.Store.MongoDB/State/ProjectionStates.cs index 5f5c70d0c..245c09bba 100644 --- a/Source/Projections.Store.MongoDB/State/ProjectionStates.cs +++ b/Source/Projections.Store.MongoDB/State/ProjectionStates.cs @@ -58,13 +58,14 @@ public async Task> TryGet(ProjectionId projection, ScopeId var collection = await _projections.GetStates(scope, projection, token).ConfigureAwait(false); var projectionState = await collection .Find(CreateKeyFilter(key)) - .Project(_ => _.ContentRaw) .SingleOrDefaultAsync(token) .ConfigureAwait(false); - return string.IsNullOrEmpty(projectionState) + + + return projectionState is null || (string.IsNullOrEmpty(projectionState.ContentRaw)) ? Try.Failed(new ProjectionStateDoesNotExist(projection, key, scope)) - : new ProjectionState(projectionState); + : new ProjectionState(projectionState.ContentRaw); } catch (Exception ex) { @@ -80,15 +81,10 @@ public async Task> TryGet(ProjectionId projection, ScopeId var collection = await _projections.GetStates(scope, projection, token).ConfigureAwait(false); var states = collection .Find(Builders.Filter.Empty) - .Project(_ => new Tuple(_.ContentRaw, _.Key)) - .ToAsyncEnumerable(token); + .ToAsyncEnumerable(token) + .Select(_ => (new ProjectionState(_.ContentRaw), new ProjectionKey(_.Key))); - var result = states.Select(_ => - { - return (_.Item1, _.Item2); - }); - - return Try>.Succeeded(result); + return Try>.Succeeded(states); } catch (Exception ex) { diff --git a/Source/Projections.Store.Services.Grpc/Projections.Store.Services.Grpc.csproj b/Source/Projections.Store.Services.Grpc/Projections.Store.Services.Grpc.csproj index 57fc90804..538051a6e 100644 --- a/Source/Projections.Store.Services.Grpc/Projections.Store.Services.Grpc.csproj +++ b/Source/Projections.Store.Services.Grpc/Projections.Store.Services.Grpc.csproj @@ -12,7 +12,6 @@ - diff --git a/Source/Projections.Store.Services.WebAPI/Projections.Store.Services.WebAPI.csproj b/Source/Projections.Store.Services.WebAPI/Projections.Store.Services.WebAPI.csproj index 237a93b1b..d2723c6d9 100644 --- a/Source/Projections.Store.Services.WebAPI/Projections.Store.Services.WebAPI.csproj +++ b/Source/Projections.Store.Services.WebAPI/Projections.Store.Services.WebAPI.csproj @@ -12,6 +12,7 @@ + diff --git a/Source/Projections.Store.Services/Projections.Store.Services.csproj b/Source/Projections.Store.Services/Projections.Store.Services.csproj index cfc9c09f9..7dc310fb1 100644 --- a/Source/Projections.Store.Services/Projections.Store.Services.csproj +++ b/Source/Projections.Store.Services/Projections.Store.Services.csproj @@ -1,5 +1,5 @@ - + Dolittle.Runtime.Projections.Store.Services @@ -7,17 +7,16 @@ - - - - - - - - + + + + + + + - + diff --git a/Source/Projections.Store/Projections.Store.csproj b/Source/Projections.Store/Projections.Store.csproj deleted file mode 100644 index 853731680..000000000 --- a/Source/Projections.Store/Projections.Store.csproj +++ /dev/null @@ -1,22 +0,0 @@ - - - - - Dolittle.Runtime.Projections.Store - Dolittle.Runtime.Projections.Store - - - - - - - - - - - - - - - - diff --git a/Source/Protobuf/ExecutionExtensions.cs b/Source/Protobuf/ExecutionExtensions.cs index 21842f909..278d8bcd3 100644 --- a/Source/Protobuf/ExecutionExtensions.cs +++ b/Source/Protobuf/ExecutionExtensions.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; using System.Diagnostics; using System.Globalization; using Dolittle.Runtime.Execution; diff --git a/Source/Protobuf/Failure.cs b/Source/Protobuf/Failure.cs index d19e604db..c7893d056 100644 --- a/Source/Protobuf/Failure.cs +++ b/Source/Protobuf/Failure.cs @@ -24,7 +24,7 @@ public Failure(FailureReason reason) /// Implicitly convert to . /// /// to convert. - public static implicit operator FailureContract(Failure failure) => + public static implicit operator FailureContract?(Failure? failure) => failure != null ? new FailureContract { Id = failure.Id.Value.ToProtobuf(), Reason = failure.Reason } : null; @@ -33,5 +33,5 @@ public static implicit operator FailureContract(Failure failure) => /// Implicitly convert to . /// /// to convert. - public static implicit operator Failure(FailureContract failure) => failure?.ToFailure(); -} \ No newline at end of file + public static implicit operator Failure?(FailureContract? failure) => failure?.ToFailure(); +} diff --git a/Source/Resources/MongoDB/MongoDBConfiguration.cs b/Source/Resources/MongoDB/MongoDBConfiguration.cs index 950ac629e..9e555e55d 100644 --- a/Source/Resources/MongoDB/MongoDBConfiguration.cs +++ b/Source/Resources/MongoDB/MongoDBConfiguration.cs @@ -15,12 +15,12 @@ public class MongoDBConfiguration /// /// Gets or sets the MongoDB host. /// - public string Host { get; set; } + public string? Host { get; set; } /// /// Gets or sets the database name. /// - public string Database { get; set; } + public string? Database { get; set; } /// /// Gets or sets the value indicating whether or not to use SSL. diff --git a/Source/Rudimentary/Partial.cs b/Source/Rudimentary/Partial.cs index 809db1702..456551b8f 100644 --- a/Source/Rudimentary/Partial.cs +++ b/Source/Rudimentary/Partial.cs @@ -63,4 +63,46 @@ protected Partial(Exception exception) : base(exception) { } /// The to convert. /// /// /// /// . public static implicit operator Partial(Exception exception) => Failed(exception); -} \ No newline at end of file +} + +/// +/// Represents the result of an operation that either succeeds with a result or fails, with a potential exception. +/// +public class Partial : Try +{ + protected Partial() : base() + { + } + + protected Partial(bool isPartial, Exception exception) : base(exception) + { + IsPartialResult = isPartial; + } + + protected Partial(Exception exception) : base(exception) { } + + /// + /// Gets a value indicating whether this is a partial result. + /// + public bool IsPartialResult { get; } + + /// + /// Creates a new result indicating a successful operation. + /// + /// A new result. + public static new Partial Succeeded() => new(); + + /// + /// Creates a new result indicating a successful operation. + /// + /// The that caused the operation to fail. + /// A new result. + public static Partial PartialSuccess(Exception exception) => new(true, exception); + + /// + /// Creates a new result indicating a failed operation because of an exception. + /// + /// The that caused the operation to fail. + /// A new result. + public static new Partial Failed(Exception exception) => new(false, exception); +} diff --git a/Source/Rudimentary/Pipelines/ReadyBatch.cs b/Source/Rudimentary/Pipelines/ReadyBatch.cs index ce323df1e..a22552a8c 100644 --- a/Source/Rudimentary/Pipelines/ReadyBatch.cs +++ b/Source/Rudimentary/Pipelines/ReadyBatch.cs @@ -17,7 +17,7 @@ public record ReadyBatch(TBatch Batch, TaskCompletionSource Complet /// /// Completes the batch. /// - public void Complete() => Completion.TrySetResult(Try.Succeeded()); + public void Complete() => Completion.TrySetResult(Try.Succeeded); /// /// Fails the batch. diff --git a/Source/Rudimentary/Rudimentary.csproj b/Source/Rudimentary/Rudimentary.csproj index 209c3b5b5..c221dda3a 100644 --- a/Source/Rudimentary/Rudimentary.csproj +++ b/Source/Rudimentary/Rudimentary.csproj @@ -1,12 +1,12 @@  - + Dolittle.Runtime.Rudimentary Dolittle.Runtime.Rudimentary - - + + diff --git a/Source/Rudimentary/TaskGroup.cs b/Source/Rudimentary/TaskGroup.cs index 2821b508a..7a95c4318 100644 --- a/Source/Rudimentary/TaskGroup.cs +++ b/Source/Rudimentary/TaskGroup.cs @@ -38,22 +38,22 @@ public TaskGroup(IEnumerable tasks) /// /// Event that occurs when the first task in the group completes. /// - public event Action OnFirstTaskCompleted; + public event Action? OnFirstTaskCompleted; /// /// Event that occurs when the first task in the group fails with an . /// - public event Action OnFirstTaskFailure; + public event Action? OnFirstTaskFailure; /// /// Event that occurs when all of the tasks in the group have completed. /// - public event Action OnAllTasksCompleted; + public event Action? OnAllTasksCompleted; /// /// Event that occurs when any other task in the group other than the first fails with an . /// - public event Action OnOtherTaskFailures; + public event Action? OnOtherTaskFailures; /// /// Waits for the first task to complete, then cancels the provided token source, and waits for all to complete. @@ -91,7 +91,7 @@ public async Task WaitForAllCancellingOnFirst(CancellationTokenSource cancellati } } - Exception GetFirstFailureAndInvokeFirstCompleted() + Exception? GetFirstFailureAndInvokeFirstCompleted() { foreach (var task in _tasks) { @@ -113,7 +113,7 @@ Exception GetFirstFailureAndInvokeFirstCompleted() return default; } - void InvokeOtherTaskFailures(Exception firstFailure) + void InvokeOtherTaskFailures(Exception? firstFailure) { foreach (var task in _tasks) { diff --git a/Source/Rudimentary/Try.cs b/Source/Rudimentary/Try.cs index 3630941ee..f8ab1ede4 100644 --- a/Source/Rudimentary/Try.cs +++ b/Source/Rudimentary/Try.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; namespace Dolittle.Runtime.Rudimentary; @@ -22,12 +23,13 @@ protected Try(Exception exception) /// /// Gets a value indicating whether the operation succeeded. /// + [MemberNotNullWhen(false, nameof(Exception))] public bool Success { get; } /// /// Gets the that caused the operation to fail. /// - public Exception Exception { get; } + public Exception? Exception { get; } /// /// Appends the result if the operation succeeded, or returns the original failure if the operation failed. @@ -50,7 +52,7 @@ public static Try Do(Action @try) try { @try(); - return Succeeded(); + return Succeeded; } catch (Exception ex) { @@ -68,7 +70,7 @@ public static async Task DoAsync(Func @try) try { await @try().ConfigureAwait(false); - return Succeeded(); + return Succeeded; } catch (Exception ex) { @@ -87,7 +89,7 @@ public static async Task DoAsync(Func @try) /// Creates a new result indicating a successful operation. /// /// A new result. - public static Try Succeeded() => new(); + public static Try Succeeded { get; } = new(); /// /// Creates a new result indicating a failed operation because of an exception. @@ -116,4 +118,4 @@ public static async Task DoAsync(Func @try) /// The to convert. /// . public static implicit operator Try(Exception exception) => Failed(exception); -} \ No newline at end of file +} diff --git a/Source/Rudimentary/Try{TResult}.cs b/Source/Rudimentary/Try{TResult}.cs index 35090bc0e..2cc721938 100644 --- a/Source/Rudimentary/Try{TResult}.cs +++ b/Source/Rudimentary/Try{TResult}.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; namespace Dolittle.Runtime.Rudimentary; @@ -14,15 +15,23 @@ public class Try : Try { protected Try(TResult result) => Result = result; - protected Try(Exception exception) : base(exception) { } + protected Try(Exception exception) : base(exception) + { + } /// /// Gets the result. /// - public TResult Result { get; protected set; } + public TResult? Result { get; protected set; } + + public new Exception? Exception => base.Exception; + + [MemberNotNullWhen(true, nameof(Result))] + [MemberNotNullWhen(false, nameof(Exception))] + public new bool Success => base.Success; /// - /// Projects the successfull result if the operation succeeded, or returns the original failure if the operation failed. + /// Projects the successful result if the operation succeeded, or returns the original failure if the operation failed. /// /// A transform function to apply to the result. /// The type of the projected result. @@ -31,6 +40,45 @@ public Try Select(Func sel => Success ? Try.Succeeded(selector(Result)) : Try.Failed(Exception); + + /// + /// Projects the successful result if the operation succeeded, or returns the original failure if the operation failed. + /// + /// A transform function to apply to the result. + /// The type of the projected result. + /// A new result that contains the projected result if the operation succeeded. + public async ValueTask> SelectAsync(Func> selector) + { + return Success + ? await Try.DoAsync(() => selector(Result)) + : Try.Failed(Exception); + } + + /// + /// Projects the successful result if the operation succeeded, or returns the original or new failure if the operation failed. + /// + /// A transform function to apply to the result. + /// The type of the projected result. + /// A new result that contains the projected result if the operation succeeded. + public Try Reduce(Func> selector) + { + return Success + ? selector(Result) + : Try.Failed(Exception); + } + + /// + /// Projects the successful result if the operation succeeded, or returns the original or new failure if the operation failed. + /// + /// A transform function to apply to the result. + /// The type of the projected result. + /// A new result that contains the projected result if the operation succeeded. + public async ValueTask> ReduceAsync(Func>> selector) + { + return Success + ? await selector(Result) + : Try.Failed(Exception); + } /// /// Try to do something that returns a result. @@ -78,7 +126,7 @@ public static async Task> DoAsync(Func> @try) /// /// The of the operation. /// A new result. - public static Try Succeeded(TResult result) => new(result); + public static new Try Succeeded(TResult result) => new(result); /// /// Creates a new result indicating a failed operation because of an exception. @@ -99,14 +147,14 @@ public static async Task> DoAsync(Func> @try) /// /// The to convert. /// . - public static implicit operator TResult(Try @try) => @try.Result; + public static implicit operator TResult?(Try @try) => @try.Result; /// /// Implicitly convert to . /// /// The to convert. /// . - public static implicit operator Exception(Try @try) => @try.Exception; + public static implicit operator Exception?(Try @try) => @try.Exception; /// /// Implicitly convert result to . @@ -121,4 +169,4 @@ public static async Task> DoAsync(Func> @try) /// The to convert. /// . public static implicit operator Try(Exception exception) => Failed(exception); -} \ No newline at end of file +} diff --git a/Source/Server/.dolittle/runtime.yml b/Source/Server/.dolittle/runtime.yml index 24073ef83..7037285a0 100644 --- a/Source/Server/.dolittle/runtime.yml +++ b/Source/Server/.dolittle/runtime.yml @@ -3,17 +3,17 @@ tenants: resources: eventStore: servers: - - localhost + - localhost database: event_store maxConnectionPoolSize: 1000 projections: servers: - - localhost + - localhost database: projections maxConnectionPoolSize: 1000 embeddings: servers: - - localhost + - localhost database: embeddings maxConnectionPoolSize: 1000 readModels: diff --git a/Source/Server/HealthChecks/EmbeddingStoreHealthCheck.cs b/Source/Server/HealthChecks/EmbeddingStoreHealthCheck.cs deleted file mode 100644 index 421e6a04e..000000000 --- a/Source/Server/HealthChecks/EmbeddingStoreHealthCheck.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Embeddings.Store.MongoDB; -using Dolittle.Runtime.Tenancy; -using MongoDB.Driver; - -namespace Dolittle.Runtime.Server.HealthChecks; - -/// -/// Represents an implementation of that checks the Embedding Store database. -/// -public class EmbeddingStoreHealthCheck : MongoDatabaseHealthCheck -{ - readonly Func _getConnectionForTenant; - - /// - /// Initializes a new instance of the class. - /// - /// The performer to use to perform the health check for all tenants. - /// The factory to use to get the Event Store connection for a tenant. - public EmbeddingStoreHealthCheck(IPerformActionsForAllTenants forAllTenants, Func getConnectionForTenant) - : base(forAllTenants) - { - _getConnectionForTenant = getConnectionForTenant; - } - - /// - protected override IMongoDatabase GetDatabaseFor(TenantId tenant) - => _getConnectionForTenant(tenant).Database; -} diff --git a/Source/Server/Program.cs b/Source/Server/Program.cs index 414c85e1c..8742ca77b 100644 --- a/Source/Server/Program.cs +++ b/Source/Server/Program.cs @@ -14,7 +14,6 @@ using Dolittle.Runtime.Services; using Dolittle.Runtime.Services.Hosting; using Dolittle.Runtime.Tenancy; -using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -54,7 +53,7 @@ static void VerifyConfiguration(IServiceProvider provider) var config = provider.GetRequiredService>(); if (!config.Value.Any()) { - logger.LogWarning("No tenants are configured in the Runtime. Without any tenants the Runtime will no function properly."); + logger.LogWarning("No tenants are configured in the Runtime. Without any tenants the Runtime will not function properly."); } } catch (Exception e) diff --git a/Source/Server/Server.csproj b/Source/Server/Server.csproj index 43b7675cc..60bdd7429 100644 --- a/Source/Server/Server.csproj +++ b/Source/Server/Server.csproj @@ -1,6 +1,6 @@ - + Dolittle.Runtime.Server Dolittle.Runtime.Server @@ -24,4 +24,8 @@ + + + + diff --git a/Source/Server/Web/KestrelConfiguration.cs b/Source/Server/Web/KestrelConfiguration.cs index c71157e8b..120d8364a 100644 --- a/Source/Server/Web/KestrelConfiguration.cs +++ b/Source/Server/Web/KestrelConfiguration.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Dolittle.Runtime.DependencyInversion; -using Dolittle.Runtime.Metrics.Configuration; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.Extensions.Options; diff --git a/Source/Server/appsettings.json b/Source/Server/appsettings.json index f39832285..e995907a9 100644 --- a/Source/Server/appsettings.json +++ b/Source/Server/appsettings.json @@ -6,6 +6,7 @@ "Proto": "Warning", "Microsoft": "Information", "Microsoft.AspNetCore": "Warning", + "Grpc.AspNetCore": "Warning", "Dolittle": "Information" }, "Console": { @@ -16,5 +17,14 @@ "UseUtcTimestamp": true } } + }, + "Dolittle": { + "Runtime": { + "EventStore": { + "BackwardsCompatibility": { + "Version": "V6" + } + } + } } } diff --git a/Source/Services.Clients/IReverseCallClient.cs b/Source/Services.Clients/IReverseCallClient.cs index c927818d3..e89d39593 100644 --- a/Source/Services.Clients/IReverseCallClient.cs +++ b/Source/Services.Clients/IReverseCallClient.cs @@ -1,6 +1,7 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using System.Threading; using System.Threading.Tasks; using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; @@ -14,7 +15,7 @@ namespace Dolittle.Runtime.Services.Clients; /// Type of the response that is received after the initial Connect call. /// Type of the requests sent from the server to the client. /// Type of the responses received from the client. -public interface IReverseCallClient +public interface IReverseCallClient : IDisposable where TConnectArguments : class where TConnectResponse : class where TRequest : class diff --git a/Source/Services.Clients/ReverseCallClient.cs b/Source/Services.Clients/ReverseCallClient.cs index 0ef74e923..2330db116 100644 --- a/Source/Services.Clients/ReverseCallClient.cs +++ b/Source/Services.Clients/ReverseCallClient.cs @@ -25,7 +25,7 @@ namespace Dolittle.Runtime.Services.Clients; /// Type of the response that is received after the initial Connect call. /// Type of the requests sent from the server to the client using . /// Type of the responses received from the client using . -public class ReverseCallClient : IReverseCallClient, IDisposable +public class ReverseCallClient : IReverseCallClient where TClient : ClientBase where TClientMessage : IMessage, new() where TServerMessage : IMessage, new() @@ -163,9 +163,8 @@ protected virtual void Dispose(bool disposing) { if (disposing) { - _writeLock.Dispose(); + _writeLock?.Dispose(); } - _disposed = true; } } diff --git a/Source/Services/Actors/ReverseCallDispatcherActor.cs b/Source/Services/Actors/ReverseCallDispatcherActor.cs new file mode 100644 index 000000000..8cbcd5981 --- /dev/null +++ b/Source/Services/Actors/ReverseCallDispatcherActor.cs @@ -0,0 +1,590 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.ExceptionServices; +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Actors; +using Dolittle.Runtime.Execution; +using Dolittle.Runtime.Protobuf; +using Dolittle.Runtime.Rudimentary; +using Dolittle.Runtime.Services.ReverseCalls; +using Dolittle.Services.Contracts; +using Google.Protobuf; +using Microsoft.Extensions.Logging; +using Proto; +using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; + +namespace Dolittle.Runtime.Services.Actors; + +public class ReverseCallDispatcherActor : IActor, IAsyncDisposable + where TClientMessage : IMessage, new() + where TServerMessage : IMessage, new() + where TConnectArguments : class + where TConnectResponse : class + where TRequest : class + where TResponse : class +{ + public static class Messages + { + public record ReceiveArguments(bool NotValidateExecutionContext, CancellationToken CancellationToken); + + public record Accept(TConnectResponse Response, CancellationToken CancellationToken); + + public record Reject(TConnectResponse Response); + + public record Call(TRequest Request, ExecutionContext ExecutionContext); + + public record Send(TServerMessage Request); + + public record CallResponse(TResponse Response, ReverseCallId CallId); + + public record InitDisconnect(InitiateDisconnect InitiateDisconnect); + } + + public record Tokens(CancellationTokenSource? ShutdownTokenSource, CancellationTokenSource? DeadlineTokenSource); + + public class Wrapper : IReverseCallDispatcher + { + readonly ActorSystem _actorSystem; + readonly PID _actor; + + readonly CancellationTokenSource? _shutdownTokenSource; + readonly CancellationTokenSource? _deadlineTokenSource; + + public Wrapper( + ActorSystem actorSystem, + ICreateProps propsCreator, + RequestId requestId, + IPingedConnection connection, + IConvertReverseCallMessages messageConverter) + { + _shutdownTokenSource = messageConverter.SupportsGracefulShutdown ? new CancellationTokenSource() : null; + _deadlineTokenSource = messageConverter.SupportsGracefulShutdown ? new CancellationTokenSource() : null; + _actorSystem = actorSystem; + _actor = actorSystem.Root.SpawnNamed( + propsCreator.PropsFor>( + connection, + messageConverter, + new Tokens(_shutdownTokenSource, _deadlineTokenSource)), + $"reverse-call-dispatcher-{requestId.Value}"); + } + + public void Dispose() => _actor.Stop(_actorSystem); + + public CancellationToken? ShutdownToken => _shutdownTokenSource?.Token; + + public CancellationToken? DeadlineToken => _deadlineTokenSource?.Token; + + public TConnectArguments? Arguments { get; private set; } + + public ExecutionContext? ExecutionContext { get; private set; } + + public async Task ReceiveArguments(CancellationToken cancellationToken, bool notValidateExecutionContext = false) + { + var getResult = await _actorSystem.Root + .RequestAsync>( + _actor, + new Messages.ReceiveArguments(notValidateExecutionContext, cancellationToken), + CancellationToken.None).ConfigureAwait(false); + if (!getResult.Success) + { + ExceptionDispatchInfo.Capture(getResult.Exception).Throw(); + } + + var (receivedArguments, arguments, executionContext) = getResult.Result; + Arguments = arguments; + ExecutionContext = executionContext; + return receivedArguments; + } + + public async Task Accept(TConnectResponse response, CancellationToken cancellationToken) + { + var request = await _actorSystem.Root.RequestAsync(_actor, new Messages.Accept(response, cancellationToken), CancellationToken.None) + .ConfigureAwait(false); + if (!request.Success) + { + ExceptionDispatchInfo.Capture(request.Exception).Throw(); + } + } + + public async Task Reject(TConnectResponse response, CancellationToken cancellationToken) + { + var request = await _actorSystem.Root.RequestAsync(_actor, new Messages.Reject(response), CancellationToken.None).ConfigureAwait(false); + if (!request.Success) + { + ExceptionDispatchInfo.Capture(request.Exception).Throw(); + } + } + + public async Task Call(TRequest request, ExecutionContext executionContext, CancellationToken cancellationToken) + { + var getResult = await _actorSystem.Root.RequestAsync>(_actor, new Messages.Call(request, executionContext), CancellationToken.None) + .ConfigureAwait(false); + if (!getResult.Success) + { + ExceptionDispatchInfo.Capture(getResult.Exception).Throw(); + } + + return getResult.Result; + } + + public async Task WriteMessage(TServerMessage message, CancellationToken cancellationToken) + { + var getResult = await _actorSystem.Root.RequestAsync(_actor, new Messages.Send(message), CancellationToken.None) + .ConfigureAwait(false); + if (!getResult.Success) + { + ExceptionDispatchInfo.Capture(getResult.Exception).Throw(); + } + } + } + + readonly CancellationTokenSource? _shutdownTokenSource; + readonly CancellationTokenSource? _deadlineTokenSource; + readonly IPingedConnection _reverseCallConnection; + readonly IConvertReverseCallMessages _messageConverter; + readonly ICreateExecutionContexts _executionContextFactory; + readonly IMetricsCollector _metricsCollector; + readonly ILogger> _logger; + readonly Dictionary> _calls = new(); + + bool _disposed; + bool _receivedArguments; + bool _accepted; + bool _rejected; + + public ReverseCallDispatcherActor( + IPingedConnection reverseCallConnection, + IConvertReverseCallMessages messageConverter, + ICreateExecutionContexts executionContextFactory, + IMetricsCollector metricsCollector, + Tokens tokens, + ILogger> logger) + { + _shutdownTokenSource = tokens.ShutdownTokenSource; + _deadlineTokenSource = tokens.DeadlineTokenSource; + _reverseCallConnection = reverseCallConnection; + _messageConverter = messageConverter; + _executionContextFactory = executionContextFactory; + _metricsCollector = metricsCollector; + _logger = logger; + this._shutdownTokenSource = _shutdownTokenSource; + } + + public Task ReceiveAsync(IContext context) + => context.Message switch + { + Messages.ReceiveArguments receiveArguments => OnReceiveArguments(receiveArguments, context), + Messages.Accept accept => OnAccept(accept, context, context.Respond), + Messages.Reject reject => OnReject(reject, context.Respond), + Messages.Call message => OnCall(context, message, context.Respond), + Messages.CallResponse response => OnCallResponse(response), + Messages.Send response => OnSend(response, context.Respond), + Messages.InitDisconnect initDisconnect => OnInitDisconnect(initDisconnect, context), + Stopped => DisposeAsync().AsTask(), + _ => Task.CompletedTask + }; + + Task OnInitDisconnect(Messages.InitDisconnect msg, IContext ctx) + { + _logger.ReceivedInitiateDisconnect(); + _shutdownTokenSource!.Cancel(); + var gradePeriod = msg.InitiateDisconnect.GracePeriod ?? TimeSpan.FromSeconds(20); + ctx.ReenterAfter(Task.Delay(gradePeriod), () => + { + try + { + _deadlineTokenSource!.Cancel(); + } + catch + { + // ignored + } + + ; + }); + return Task.CompletedTask; + } + + + Task OnCallResponse(Messages.CallResponse msg) + { + if (_calls.Remove(msg.CallId, out var completionSource)) + { + completionSource.SetResult(msg.Response); + } + else + { + _logger.CouldNotFindCallId(); + } + + return Task.CompletedTask; + } + + async Task OnReceiveArguments(Messages.ReceiveArguments msg, IContext context) + { + if (_receivedArguments) + { + RespondWithError(new ReverseCallDispatcherAlreadyTriedToReceiveArguments()); + return; + } + + _receivedArguments = true; + var clientToRuntimeStream = _reverseCallConnection.RuntimeStream; + if (!await clientToRuntimeStream.MoveNext(msg.CancellationToken).ConfigureAwait(false)) + { + RespondFailedWithoutError(); + return; + } + + var arguments = _messageConverter.GetConnectArguments(clientToRuntimeStream.Current); + if (arguments is null) + { + _logger.ReceivedInitialMessageByArgumentsNotSet(); + RespondFailedWithoutError(); + return; + } + + var callContext = _messageConverter.GetArgumentsContext(arguments); + if (callContext?.PingInterval == null) + { + _logger.ReceivedArgumentsButPingIntervalNotSet(); + RespondFailedWithoutError(); + return; + } + + if (callContext?.ExecutionContext == null) + { + _logger.ReceivedArgumentsButCallExecutionContextNotSet(); + RespondFailedWithoutError(); + return; + } + + var createExecutionContext = msg.NotValidateExecutionContext + ? Try.Succeeded(callContext.ExecutionContext.ToExecutionContext()) + : _executionContextFactory.TryCreateUsing(callContext.ExecutionContext); + if (!createExecutionContext.Success) + { + _logger.ReceivedInvalidExecutionContext(createExecutionContext.Exception); + RespondFailedWithoutError(); + return; + } + + RespondSucceeded(arguments, createExecutionContext.Result); + + void RespondWithError(Exception ex) + { + context.Respond(Try<(bool, TConnectArguments?, ExecutionContext?)>.Failed(ex)); + } + + void RespondFailedWithoutError() + { + context.Respond(Try<(bool, TConnectArguments?, ExecutionContext?)>.Succeeded((false, null, null))); + } + + void RespondSucceeded(TConnectArguments arguments, ExecutionContext executionContext) + { + context.Respond(Try<(bool, TConnectArguments?, ExecutionContext?)>.Succeeded((true, arguments, executionContext))); + } + } + + async Task OnAccept(Messages.Accept msg, IContext context, Action respond) + { + var hasNotResponded = CheckHasNotResponded(); + if (!hasNotResponded.Success) + { + context.Respond(Try.Failed(hasNotResponded.Exception)); + return; + } + + _accepted = true; + try + { + var message = new TServerMessage(); + _messageConverter.SetConnectResponse(msg.Response, message); + // Blocking here is okay + await _reverseCallConnection.ClientStream.WriteAsync(message); + context.ReenterAfter(ReadClientMessages(context, msg.CancellationToken), async _ => + { + await DisposeAsync().ConfigureAwait(false); + RespondSuccess(); + }); + } + catch (Exception e) + { + context.Respond(Try.Failed(e)); + } + + void RespondError(Exception e) + { + respond(Try.Failed(e)); + } + + void RespondSuccess() + { + respond(Try.Succeeded); + } + } + + async Task OnReject(Messages.Reject msg, Action respond) + { + var hasNotResponded = CheckHasNotResponded(); + if (!hasNotResponded.Success) + { + respond(Try.Failed(hasNotResponded.Exception)); + return; + } + + _rejected = true; + try + { + var message = new TServerMessage(); + _messageConverter.SetConnectResponse(msg.Response, message); + await _reverseCallConnection.ClientStream.WriteAsync(message).ConfigureAwait(false); + respond(Try.Succeeded); + } + catch (Exception e) + { + respond(Try.Failed(e)); + } + } + + async Task OnSend(Messages.Send command, Action respond) + { + if (_disposed) + { + RespondError(new CannotPerformCallOnCompletedReverseCallConnection()); + return; + } + + if (_rejected) + { + RespondError(new ReverseCallDispatcherAlreadyRejected()); + return; + } + + try + { + await _reverseCallConnection.ClientStream.WriteAsync(command.Request).ConfigureAwait(false); + respond(Try.Succeeded); + } + catch (Exception e) + { + RespondError(e); + } + + + void RespondError(Exception ex) + { + respond(Try.Failed(ex)); + } + } + + + Task OnCall(IContext context, Messages.Call msg, Action> respond) + { + if (_disposed) + { + return RespondError(new CannotPerformCallOnCompletedReverseCallConnection()); + } + + if (_rejected) + { + return RespondError(new ReverseCallDispatcherAlreadyRejected()); + } + + var (callId, completionSource) = CreateNewCall(); + var (request, executionContext) = msg; + context.SafeReenterAfter( + CallAndWaitForResponse(CreateMessage(callId, request, executionContext), callId, completionSource), + result => + { + if (!result.Success) + { + _calls.Remove(callId); + } + + return Respond(result); + }, + (ex, _) => + { + _calls.Remove(callId); + return RespondError(ex); + }); + return Task.CompletedTask; + + Task RespondError(Exception ex) + { + respond(Try.Failed(ex)); + return Task.CompletedTask; + } + + Task Respond(Try result) + { + respond(result); + return Task.CompletedTask; + } + } + + async Task> CallAndWaitForResponse(TServerMessage message, ReverseCallId callId, TaskCompletionSource completionSource) + { + try + { + _logger.WritingRequest(callId); + _metricsCollector.AddRequest(); + var stopWatch = new Stopwatch(); + stopWatch.Start(); + await _reverseCallConnection.ClientStream.WriteAsync(message).ConfigureAwait(false); + var response = await completionSource.Task.ConfigureAwait(false); + stopWatch.Stop(); + _metricsCollector.AddToTotalRequestTime(stopWatch.Elapsed); + return response; + } + catch (Exception e) + { + _metricsCollector.AddFailedRequest(); + _logger.CallFailed(e); + return e; + } + } + + (ReverseCallId, TaskCompletionSource) CreateNewCall() + { + var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var callId = ReverseCallId.New(); + while (!_calls.TryAdd(callId, completionSource)) + { + callId = ReverseCallId.New(); + } + + return (callId, completionSource); + } + + TServerMessage CreateMessage(ReverseCallId callId, TRequest request, ExecutionContext executionContext) + { + var callContext = new ReverseCallRequestContext + { + CallId = callId.ToProtobuf(), + ExecutionContext = executionContext.ToProtobuf(), + }; + + _messageConverter.SetRequestContext(callContext, request); + var message = new TServerMessage(); + _messageConverter.SetRequest(request, message); + return message; + } + + async Task ReadClientMessages(IContext context, CancellationToken cancellationToken) + { + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _reverseCallConnection.CancellationToken, context.CancellationToken); + try + { + var reader = _reverseCallConnection.RuntimeStream; + while (!cts.Token.IsCancellationRequested && await reader.MoveNext(cts.Token).ConfigureAwait(false)) + { + var message = reader.Current; + var initiateDisconnect = _messageConverter.GetInitiateDisconnect(message); + if (initiateDisconnect is not null) + { + _logger.ReceivedInitiateDisconnect(); + context.Send(context.Self, new Messages.InitDisconnect(initiateDisconnect)); + continue; + } + + var response = _messageConverter.GetResponse(message); + if (response != null) + { + _logger.ReceivedResponse(); + var callContext = _messageConverter.GetResponseContext(response); + if (callContext?.CallId != null) + { + ReverseCallId callId = callContext.CallId.ToGuid(); + context.Send(context.Self, new Messages.CallResponse(response, callId)); + } + else + { + _logger.ReceivedResponseButCallContextNotSet(); + } + } + else + { + _logger.ReceivedMessageButDidNotContainResponse(); + } + } + } + catch (System.IO.IOException ex) when (ex.Message.StartsWith("The client reset the request stream", StringComparison.Ordinal)) + { + _logger.ClientDisconnected(); + } + catch (Exception ex) + { + if (!cts.Token.IsCancellationRequested) + { + _logger.ErrorWhileHandlingClientMessages(ex); + } + } + } + + + public ValueTask DisposeAsync() + { + if (_disposed) + { + return ValueTask.CompletedTask; + } + + _disposed = true; + foreach (var (_, completionSource) in _calls) + { + try + { + completionSource.SetCanceled(); + } + catch + { + // ignored + } + } + + _reverseCallConnection?.Dispose(); + try + { + _shutdownTokenSource?.Cancel(); + _shutdownTokenSource?.Dispose(); + } + catch + { + // ignored + } + try + { + _deadlineTokenSource?.Cancel(); + _deadlineTokenSource?.Dispose(); + } + catch + { + // ignored + } + + return ValueTask.CompletedTask; + } + + Try CheckHasNotResponded() + { + if (_accepted) + { + return new ReverseCallDispatcherAlreadyAccepted(); + } + + if (_rejected) + { + return new ReverseCallDispatcherAlreadyRejected(); + } + + return Try.Succeeded; + } +} diff --git a/Source/Services/Actors/ReverseCallStreamWriterActor.cs b/Source/Services/Actors/ReverseCallStreamWriterActor.cs new file mode 100644 index 000000000..8aad51b3e --- /dev/null +++ b/Source/Services/Actors/ReverseCallStreamWriterActor.cs @@ -0,0 +1,196 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics; +using System.Runtime.ExceptionServices; +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Actors; +using Dolittle.Runtime.Rudimentary; +using Dolittle.Services.Contracts; +using Google.Protobuf; +using Grpc.Core; +using Microsoft.Extensions.Logging; +using Proto; + +namespace Dolittle.Runtime.Services.ReverseCalls; + +public class ReverseCallStreamWriterActor : IActor + where TClientMessage : IMessage, new() + where TServerMessage : IMessage, new() + where TConnectArguments : class + where TConnectResponse : class + where TRequest : class + where TResponse : class +{ + public class Wrapper : IReverseCallStreamWriter + { + readonly ActorSystem _actorSystem; + readonly IAsyncStreamWriter _originalStream; + readonly PID _actor; + + public Wrapper( + ActorSystem actorSystem, + ICreateProps props, + RequestId requestId, + IConvertReverseCallMessages messageConverter, + IAsyncStreamWriter originalStream, + CancellationToken cancellationToken, + TimeSpan? pingTimeout) + { + _actorSystem = actorSystem; + _originalStream = originalStream; + _actor = actorSystem.Root.SpawnNamed( + props.PropsFor>( + requestId, + messageConverter, + originalStream, + pingTimeout ?? TimeSpan.Zero, + cancellationToken), + $"reverse-call-stream-writer-{requestId.Value}"); + } + + public async Task WriteAsync(TServerMessage message) + { + var result = await _actorSystem.Root.RequestAsync(_actor, message, CancellationToken.None); + if (!result.Success) + { + ExceptionDispatchInfo.Capture(result.Exception).Throw(); + } + } + + public WriteOptions? WriteOptions + { + get => _originalStream.WriteOptions; + set => _originalStream.WriteOptions = value; + } + + public void MaybeWritePing() + { + } + + public void Dispose() => _actorSystem.Root.Stop(_actor); + } + + readonly RequestId _requestId; + readonly IConvertReverseCallMessages _messageConverter; + readonly IAsyncStreamWriter _originalStream; + readonly IMetricsCollector _metrics; + readonly ILogger _logger; + readonly CancellationToken _cancellationToken; + readonly TimeSpan? _pingTimeout; + + public ReverseCallStreamWriterActor( + RequestId requestId, + IConvertReverseCallMessages messageConverter, + IAsyncStreamWriter originalStream, + IMetricsCollector metrics, + ILogger> logger, + TimeSpan pingTimeout, + CancellationToken cancellationToken) + { + _requestId = requestId; + _messageConverter = messageConverter; + _originalStream = originalStream; + _metrics = metrics; + _logger = logger; + _cancellationToken = cancellationToken; + _pingTimeout = pingTimeout == TimeSpan.Zero ? null : pingTimeout; + } + + public Task ReceiveAsync(IContext context) + => context.Message switch + { + Started => OnStarted(context), + ReceiveTimeout => OnPingTimeout(), + TServerMessage msg => OnWrite(msg, context.Respond), + Stopping => OnStopped(), + _ => Task.CompletedTask + }; + + Task OnStarted(IContext context) + { + if (_pingTimeout.HasValue) + { + context.SetReceiveTimeout(_pingTimeout.Value); + } + return Task.CompletedTask; + } + + Task OnStopped() + { + _logger.DisposedWrappedAsyncStreamWriter(_requestId); + return Task.CompletedTask; + } + async Task OnPingTimeout() + { + var message = new TServerMessage(); + _messageConverter.SetPing(message, new Ping()); + await WriteMessage(message, false, _ => {}).ConfigureAwait(false); + } + + async Task OnWrite(TServerMessage msg, Action respond) => await WriteMessage(msg, false, respond).ConfigureAwait(false); + + async Task WriteMessage(TServerMessage msg, bool isPing, Action respond) + { + LogWriting(isPing); + if (_cancellationToken.IsCancellationRequested) + { + RespondError(new OperationCanceledException($"{GetType().Name} for request id {_requestId} is cancelled")); + return; + } + + var stopwatch = Stopwatch.StartNew(); + try + { + await _originalStream.WriteAsync(msg)!.ConfigureAwait(false); + stopwatch.Stop(); + var messageSize = msg.CalculateSize(); + _metrics.AddToTotalStreamWriteTime(stopwatch.Elapsed); + _metrics.IncrementTotalStreamWrites(); + _metrics.IncrementTotalStreamWriteBytes(messageSize); + LogDoneWriting(isPing, stopwatch.Elapsed, messageSize); + RespondSuccess(); + } + catch (Exception e) + { + RespondError(e); + } + + void RespondError(Exception e) + { + respond(Try.Failed(e)); + } + + void RespondSuccess() + { + respond(Try.Succeeded); + } + } + + void LogWriting(bool isPing) + { + if (isPing) + { + _logger.WritingPing(_requestId); + } + else + { + _logger.WritingMessage(_requestId, typeof(TServerMessage)); + } + } + + void LogDoneWriting(bool isPing, TimeSpan writeTime, int messageSize) + { + if (isPing) + { + _metrics.IncrementTotalPingsSent(); + _logger.WrotePing(_requestId, writeTime); + } + else + { + _logger.WroteMessage(_requestId, writeTime, messageSize); + } + } +} diff --git a/Source/Services/Configuration/EndpointsConfiguration.cs b/Source/Services/Configuration/EndpointsConfiguration.cs index 575ce54c9..ee7d0ca65 100644 --- a/Source/Services/Configuration/EndpointsConfiguration.cs +++ b/Source/Services/Configuration/EndpointsConfiguration.cs @@ -14,17 +14,17 @@ public record EndpointsConfiguration /// /// Gets the configuration for the public endpoint. /// - public EndpointConfiguration Public { get; init; } = new() {Port = 50052}; + public EndpointConfiguration Public { get; set; } = new() {Port = 50052}; /// /// Gets the configuration for the private endpoint. /// - public EndpointConfiguration Private { get; init; } = new() {Port = 50053}; + public EndpointConfiguration Private { get; set; } = new() {Port = 50053}; /// /// Gets the configuration for the management endpoint. /// - public EndpointConfiguration Management { get; init; } = new() {Port = 51052}; + public EndpointConfiguration Management { get; set; } = new() {Port = 51052}; /// /// Gets the configuration for the management web endpoint. diff --git a/Source/Services/Configuration/ReverseCallsConfiguration.cs b/Source/Services/Configuration/ReverseCallsConfiguration.cs new file mode 100644 index 000000000..e72b9b864 --- /dev/null +++ b/Source/Services/Configuration/ReverseCallsConfiguration.cs @@ -0,0 +1,19 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Configuration; + +namespace Dolittle.Runtime.Services.Configuration; + +/// +/// Represents the configuration of reverse calls for gRPC services. +/// +[Configuration("reverseCalls")] +public record ReverseCallsConfiguration +{ + /// + /// Gets the configuration for whether to use actors for reverse calls. + /// + public bool UseActors { get; init; } = true; + +} diff --git a/Source/Services/ConnectArgumentsValidationResult.cs b/Source/Services/ConnectArgumentsValidationResult.cs index 0e70551d2..9d9d29ca0 100644 --- a/Source/Services/ConnectArgumentsValidationResult.cs +++ b/Source/Services/ConnectArgumentsValidationResult.cs @@ -11,7 +11,7 @@ public record ConnectArgumentsValidationResult /// /// Creates a successful . /// - public static ConnectArgumentsValidationResult Ok => new() { Success = true, FailureReason = default }; + public static ConnectArgumentsValidationResult Ok { get; } = new() { Success = true, FailureReason = default }; /// /// Creates a failed . @@ -27,5 +27,5 @@ public record ConnectArgumentsValidationResult /// /// Gets the reason for why the validation failed. /// - public string FailureReason { get; private init; } -} \ No newline at end of file + public string? FailureReason { get; private init; } +} diff --git a/Source/Services/IConvertReverseCallMessages.cs b/Source/Services/IConvertReverseCallMessages.cs index af2e17ff9..b50ea7b6a 100644 --- a/Source/Services/IConvertReverseCallMessages.cs +++ b/Source/Services/IConvertReverseCallMessages.cs @@ -24,13 +24,12 @@ public interface IConvertReverseCallMessages /// Gets the from a . /// /// The to get the connect arguments from. /// The in the message. - TConnectArguments GetConnectArguments(TClientMessage message); + TConnectArguments? GetConnectArguments(TClientMessage message); /// /// Sets the in a . @@ -51,14 +50,14 @@ public interface IConvertReverseCallMessages /// The . /// The . - TResponse GetResponse(TClientMessage message); + TResponse? GetResponse(TClientMessage message); /// /// Gets the from the . /// /// The . /// The . - ReverseCallArgumentsContext GetArgumentsContext(TConnectArguments message); + ReverseCallArgumentsContext? GetArgumentsContext(TConnectArguments message); /// /// Sets the in a . @@ -72,7 +71,7 @@ public interface IConvertReverseCallMessages /// The to get the context from. /// The in the request. - ReverseCallResponseContext GetResponseContext(TResponse message); + ReverseCallResponseContext? GetResponseContext(TResponse message); /// /// Sets the in the . @@ -86,12 +85,21 @@ public interface IConvertReverseCallMessages /// The to get the pong from. /// The in the message. - Pong GetPong(TClientMessage message); + Pong? GetPong(TClientMessage message); + bool SupportsGracefulShutdown => false; + + /// + /// If the protocol supports it, and it is of the correct type, get from the . + /// + /// + /// + InitiateDisconnect? GetInitiateDisconnect(TClientMessage message) => null; + /// /// Creates a signifying a failed connection. /// /// The reason for failure. /// The failed . TConnectResponse CreateFailedConnectResponse(FailureReason failureMessage); -} \ No newline at end of file +} diff --git a/Source/Services/IReverseCallDispatcher.cs b/Source/Services/IReverseCallDispatcher.cs index 8f510fac7..794e8a6b6 100644 --- a/Source/Services/IReverseCallDispatcher.cs +++ b/Source/Services/IReverseCallDispatcher.cs @@ -35,6 +35,16 @@ public interface IReverseCallDispatcher received from the initial Connect call from the client. /// ExecutionContext ExecutionContext { get; } + + /// + /// I + /// + CancellationToken? ShutdownToken { get; } + + /// + /// + /// + CancellationToken? DeadlineToken { get; } /// /// Waits for the initial Connect call arguments from the client. @@ -68,4 +78,12 @@ public interface IReverseCallDispatcherThe . /// A that, when resolved, returns the from the client. Task Call(TRequest request, ExecutionContext executionContext, CancellationToken cancellationToken); + + /// + /// Write a message to the client without waiting for a response. + /// + /// + /// + /// + Task WriteMessage(TServerMessage message, CancellationToken cancellationToken); } diff --git a/Source/Services/InitiateDisconnect.cs b/Source/Services/InitiateDisconnect.cs new file mode 100644 index 000000000..477f92ef2 --- /dev/null +++ b/Source/Services/InitiateDisconnect.cs @@ -0,0 +1,11 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Dolittle.Runtime.Services; + +public record InitiateDisconnect +{ + public required TimeSpan? GracePeriod { get; init; } +} diff --git a/Source/Services/InitiateReverseCallServices.cs b/Source/Services/InitiateReverseCallServices.cs index c3fe648c8..2c7bb8c41 100644 --- a/Source/Services/InitiateReverseCallServices.cs +++ b/Source/Services/InitiateReverseCallServices.cs @@ -76,7 +76,5 @@ public InitiateReverseCallServices(IReverseCallDispatchers reverseCallDispatcher dispatcher.Dispose(); throw; } - - } } diff --git a/Source/Services/Log.cs b/Source/Services/Log.cs index 036460a96..167384620 100644 --- a/Source/Services/Log.cs +++ b/Source/Services/Log.cs @@ -9,58 +9,64 @@ namespace Dolittle.Runtime.Services; static partial class Log { [LoggerMessage(0, LogLevel.Warning, "Received arguments, but ping interval was not set")] - internal static partial void ReceivedArgumentsButPingIntervalNotSet(ILogger logger); + internal static partial void ReceivedArgumentsButPingIntervalNotSet(this ILogger logger); [LoggerMessage(0, LogLevel.Warning, "Received arguments, but call execution context was not set.")] - internal static partial void ReceivedArgumentsButCallExecutionContextNotSet(ILogger logger); + internal static partial void ReceivedArgumentsButCallExecutionContextNotSet(this ILogger logger); [LoggerMessage(0, LogLevel.Warning, "Received invalid execution context.")] - internal static partial void ReceivedInvalidExecutionContext(ILogger logger, Exception exception); + internal static partial void ReceivedInvalidExecutionContext(this ILogger logger, Exception exception); [LoggerMessage(0, LogLevel.Warning, "Received initial message from client, but arguments was not set.")] - internal static partial void ReceivedInitialMessageByArgumentsNotSet(ILogger logger); + internal static partial void ReceivedInitialMessageByArgumentsNotSet(this ILogger logger); [LoggerMessage(0, LogLevel.Trace, "Received response.")] - internal static partial void ReceivedResponse(ILogger logger); + internal static partial void ReceivedResponse(this ILogger logger); + + [LoggerMessage(0, LogLevel.Debug, "Received InitiateDisconnect.")] + internal static partial void ReceivedInitiateDisconnect(this ILogger logger); [LoggerMessage(0, LogLevel.Warning, "Could not find the call id from the received response from the client. The message will be ignored.")] - internal static partial void CouldNotFindCallId(ILogger logger); + internal static partial void CouldNotFindCallId(this ILogger logger); [LoggerMessage(0, LogLevel.Warning, "Received response from reverse call client, but the call context was not set.")] - internal static partial void ReceivedResponseButCallContextNotSet(ILogger logger); + internal static partial void ReceivedResponseButCallContextNotSet(this ILogger logger); [LoggerMessage(0, LogLevel.Warning, "Received message from reverse call client, but it did not contain a response.")] - internal static partial void ReceivedMessageButDidNotContainResponse(ILogger logger); + internal static partial void ReceivedMessageButDidNotContainResponse(this ILogger logger); [LoggerMessage(0, LogLevel.Warning, "An error occurred during handling of client messages")] - internal static partial void ErrorWhileHandlingClientMessages(ILogger logger, Exception ex); + internal static partial void ErrorWhileHandlingClientMessages(this ILogger logger, Exception ex); + + [LoggerMessage(0, LogLevel.Information, "The client reset the request stream (client disconnected)")] + internal static partial void ClientDisconnected(this ILogger logger); [LoggerMessage(0, LogLevel.Debug, "Starting all endpoints")] - internal static partial void StartingAllEndpoints(ILogger logger); + internal static partial void StartingAllEndpoints(this ILogger logger); [LoggerMessage(0, LogLevel.Debug, "Preparing endpoint for {VisibilityType} visibility - running on port {Port}")] - internal static partial void PreparingEndpoint(ILogger logger, EndpointVisibility visibilityType, int port); + internal static partial void PreparingEndpoint(this ILogger logger, EndpointVisibility visibilityType, int port); [LoggerMessage(0, LogLevel.Debug, "{VisibilityType} endpoint is disabled")] - internal static partial void EndpointDisabled(ILogger logger, EndpointVisibility visibilityType); + internal static partial void EndpointDisabled(this ILogger logger, EndpointVisibility visibilityType); [LoggerMessage(0, LogLevel.Debug, "Bind services from {Implementation}")] - internal static partial void BindServicesFromImplementation(ILogger logger, string implementation); + internal static partial void BindServicesFromImplementation(this ILogger logger, string implementation); [LoggerMessage(0, LogLevel.Trace, "Service : {ServiceName}")] - internal static partial void BoundService(ILogger logger, string serviceName); + internal static partial void BoundService(this ILogger logger, string serviceName); [LoggerMessage(0, LogLevel.Trace, "Waiting for connection arguments")] - internal static partial void WaitingForConnectionArguments(ILogger logger); + internal static partial void WaitingForConnectionArguments(this ILogger logger); [LoggerMessage(0, LogLevel.Trace, "Received connection arguments")] - internal static partial void ReceivedConnectionArguments(ILogger logger); + internal static partial void ReceivedConnectionArguments(this ILogger logger); [LoggerMessage(0, LogLevel.Warning, "Connection arguments were not received")] - internal static partial void ConnectionArgumentsNotReceived(ILogger logger); + internal static partial void ConnectionArgumentsNotReceived(this ILogger logger); [LoggerMessage(0, LogLevel.Trace, "Connection arguments were not valid")] - internal static partial void ReceivedInvalidConnectionArguments(ILogger logger); + internal static partial void ReceivedInvalidConnectionArguments(this ILogger logger); diff --git a/Source/Services/ReverseCallDispatcher.cs b/Source/Services/ReverseCallDispatcher.cs index 7f05858fa..9c04f0a75 100644 --- a/Source/Services/ReverseCallDispatcher.cs +++ b/Source/Services/ReverseCallDispatcher.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; +using Dolittle.Runtime.DependencyInversion; using Dolittle.Runtime.Execution; using Dolittle.Runtime.Protobuf; using Dolittle.Runtime.Rudimentary; @@ -26,6 +27,7 @@ namespace Dolittle.Runtime.Services; /// Type of the response that is received after the initial Connect call. /// Type of the requests sent from the server to the client using . /// Type of the responses received from the client using . +[DisableAutoRegistration] public class ReverseCallDispatcher : IReverseCallDispatcher where TClientMessage : IMessage, new() @@ -51,6 +53,9 @@ public class ReverseCallDispatcher /// Initializes a new instance of the class. /// @@ -71,8 +76,16 @@ public ReverseCallDispatcher( _executionContextFactory = executionContextFactory; _metricsCollector = metricsCollector; _logger = logger; + if (messageConverter.SupportsGracefulShutdown) + { + _shutdownTokenSource = new CancellationTokenSource(); + _deadlineTokenSource = new CancellationTokenSource(); + } } + public CancellationToken? ShutdownToken => _shutdownTokenSource?.Token; + public CancellationToken? DeadlineToken => _deadlineTokenSource?.Token; + /// public TConnectArguments Arguments { get; private set; } @@ -111,7 +124,9 @@ public async Task ReceiveArguments(CancellationToken cancellationToken, bo return false; } - var createExecutionContext = notValidateExecutionContext? Try.Succeeded(callContext.ExecutionContext.ToExecutionContext()) : _executionContextFactory.TryCreateUsing(callContext.ExecutionContext); + var createExecutionContext = notValidateExecutionContext + ? Try.Succeeded(callContext.ExecutionContext.ToExecutionContext()) + : _executionContextFactory.TryCreateUsing(callContext.ExecutionContext); if (!createExecutionContext.Success) { Log.ReceivedInvalidExecutionContext(_logger, createExecutionContext.Exception); @@ -122,6 +137,7 @@ public async Task ReceiveArguments(CancellationToken cancellationToken, bo ExecutionContext = createExecutionContext.Result; return true; } + Log.ReceivedInitialMessageByArgumentsNotSet(_logger); return false; } @@ -199,6 +215,13 @@ public async Task Call(TRequest request, ExecutionContext executionCo } } + /// + public Task WriteMessage(TServerMessage message, CancellationToken cancellationToken) + { + // ReSharper disable once MethodSupportsCancellation + return _reverseCallConnection.ClientStream.WriteAsync(message); + } + /// public void Dispose() { @@ -216,9 +239,12 @@ protected virtual void Dispose(bool disposing) { return; } + if (disposing) { _reverseCallConnection.Dispose(); + _shutdownTokenSource?.Dispose(); + _deadlineTokenSource?.Dispose(); } _disposed = true; @@ -233,6 +259,32 @@ async Task HandleClientMessages(CancellationToken cancellationToken) while (!jointCts.IsCancellationRequested && await clientToRuntimeStream.MoveNext(jointCts.Token).ConfigureAwait(false)) { var message = clientToRuntimeStream.Current; + if (_messageConverter.SupportsGracefulShutdown) + { + var initiateDisconnect = _messageConverter.GetInitiateDisconnect(message); + if (initiateDisconnect is not null) + { + _logger.ReceivedInitiateDisconnect(); + _shutdownTokenSource!.Cancel(); + var gradePeriod = initiateDisconnect.GracePeriod ?? TimeSpan.FromSeconds(20); + _ = Task.Run(async () => + { + try + { + await Task.Delay(gradePeriod, cancellationToken); + _deadlineTokenSource!.Cancel(); + } + catch + { + // ignored + } + }, CancellationToken.None); + + continue; + } + } + + var response = _messageConverter.GetResponse(message); if (response != null) { @@ -279,8 +331,29 @@ async Task HandleClientMessages(CancellationToken cancellationToken) } catch { + // ignored } } + + try + { + _shutdownTokenSource?.Cancel(); + _shutdownTokenSource?.Dispose(); + } + catch + { + // ignored + } + + try + { + _deadlineTokenSource?.Cancel(); + _deadlineTokenSource?.Dispose(); + } + catch + { + // ignored + } } } @@ -298,6 +371,7 @@ void ThrowIfResponded() { throw new ReverseCallDispatcherAlreadyAccepted(); } + if (_rejected) { throw new ReverseCallDispatcherAlreadyRejected(); diff --git a/Source/Services/ReverseCallDispatchers.cs b/Source/Services/ReverseCallDispatchers.cs index 68c4e90f1..bef4d10fd 100644 --- a/Source/Services/ReverseCallDispatchers.cs +++ b/Source/Services/ReverseCallDispatchers.cs @@ -1,11 +1,16 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using Dolittle.Runtime.Actors; using Dolittle.Runtime.Execution; +using Dolittle.Runtime.Services.Actors; +using Dolittle.Runtime.Services.Configuration; using Dolittle.Runtime.Services.ReverseCalls; using Google.Protobuf; using Grpc.Core; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Proto; namespace Dolittle.Runtime.Services; @@ -14,6 +19,9 @@ namespace Dolittle.Runtime.Services; /// public class ReverseCallDispatchers : IReverseCallDispatchers { + readonly ActorSystem _actorSystem; + readonly ICreateProps _props; + readonly ReverseCallsConfiguration _reverseCallsConfig; readonly IIdentifyRequests _requestIdentifier; readonly ICreateExecutionContexts _executionContextCreator; readonly IMetricsCollector _metricsCollector; @@ -29,12 +37,18 @@ public class ReverseCallDispatchers : IReverseCallDispatchers /// The to use for creating instances of . /// The for creating pinged connections. public ReverseCallDispatchers( + ActorSystem actorSystem, + ICreateProps props, + IOptions reverseCallsConfig, IIdentifyRequests requestIdentifier, ICreateExecutionContexts executionContextCreator, IMetricsCollector metricsCollector, ILoggerFactory loggerFactory, IKeepConnectionsAlive pingedConnectionFactory) { + _actorSystem = actorSystem; + _props = props; + _reverseCallsConfig = reverseCallsConfig.Value; _requestIdentifier = requestIdentifier; _executionContextCreator = executionContextCreator; _metricsCollector = metricsCollector; @@ -54,10 +68,23 @@ public IReverseCallDispatcher new ReverseCallDispatcher( - _pingedConnectionFactory.CreatePingedReverseCallConnection(_requestIdentifier.GetRequestIdFor(context), clientStream, serverStream, context, messageConverter), + { + var requestId = _requestIdentifier.GetRequestIdFor(context); + var connection = _pingedConnectionFactory.CreatePingedReverseCallConnection(requestId, clientStream, serverStream, context, messageConverter); + if (_reverseCallsConfig.UseActors) + { + return new ReverseCallDispatcherActor.Wrapper( + _actorSystem, + _props, + requestId, + connection, + messageConverter); + } + return new ReverseCallDispatcher( + connection, messageConverter, _executionContextCreator, _metricsCollector, _loggerFactory.CreateLogger>()); + } } diff --git a/Source/Services/ReverseCalls/IReverseCallStreamWriter.cs b/Source/Services/ReverseCalls/IReverseCallStreamWriter.cs new file mode 100644 index 000000000..8f7b81981 --- /dev/null +++ b/Source/Services/ReverseCalls/IReverseCallStreamWriter.cs @@ -0,0 +1,17 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Google.Protobuf; +using Grpc.Core; + +namespace Dolittle.Runtime.Services.ReverseCalls; + +public interface IReverseCallStreamWriter : IAsyncStreamWriter, IDisposable + where TServerMessage : IMessage, new() +{ + /// + /// Writes a ping message synchronously if another write operation is not in progress. + /// + void MaybeWritePing(); +} diff --git a/Source/Services/ReverseCalls/IReverseCallStreamWriterFactory.cs b/Source/Services/ReverseCalls/IReverseCallStreamWriterFactory.cs new file mode 100644 index 000000000..7850c703b --- /dev/null +++ b/Source/Services/ReverseCalls/IReverseCallStreamWriterFactory.cs @@ -0,0 +1,25 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using Google.Protobuf; +using Grpc.Core; + +namespace Dolittle.Runtime.Services.ReverseCalls; + +public interface IReverseCallStreamWriterFactory +{ + IReverseCallStreamWriter CreateWriter( + RequestId requestId, + IAsyncStreamWriter originalStream, + IConvertReverseCallMessages messageConverter, + CancellationToken cancellationToken, + TimeSpan? pingTimeout) + where TClientMessage : IMessage, new() + where TServerMessage : IMessage, new() + where TConnectArguments : class + where TConnectResponse : class + where TRequest : class + where TResponse : class; +} diff --git a/Source/Services/ReverseCalls/PingedConnection.cs b/Source/Services/ReverseCalls/PingedConnection.cs index 80ddb31fb..31ea0d4dc 100644 --- a/Source/Services/ReverseCalls/PingedConnection.cs +++ b/Source/Services/ReverseCalls/PingedConnection.cs @@ -3,10 +3,12 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Threading; using Dolittle.Runtime.Services.Callbacks; using Dolittle.Services.Contracts; using Google.Protobuf; +using Google.Protobuf.WellKnownTypes; using Grpc.Core; using Microsoft.Extensions.Logging; @@ -31,47 +33,55 @@ public class PingedConnection _clientStream; + readonly IConvertReverseCallMessages _messageConverter; + readonly ICancelTokenIfDeadlineIsMissed _keepAlive; readonly ICallbackScheduler _pingScheduler; readonly IMetricsCollector _metrics; readonly WrappedAsyncStreamReader _wrappedReader; - readonly WrappedAsyncStreamWriter _wrappedWriter; readonly ILogger _logger; readonly CancellationTokenRegistration _keepAliveExpiredRegistration; - Stopwatch _waitForCallContextStopwatch; - TimeSpan _keepaliveTimeout; - IDisposable _scheduledPings; + IReverseCallStreamWriter? _reverseCallStreamWriter; + Stopwatch? _waitForCallContextStopwatch; + TimeSpan? _keepAliveTimeout; + IDisposable? _scheduledPings; bool _disposed; /// /// Initializes a new instance of the class. /// /// The request id for the gRPC method call. + /// /// The to read messages to the Runtime. /// The to write messages to the Client. /// The of the method call. /// The to use for decoding the connect arguments and reading the desired ping interval from. - /// The keepalive token canceller to use for keeping track of ping timeouts. + /// The keepAlive token canceller to use for keeping track of ping timeouts. /// The callback scheduler to use for scheduling accurate pings. /// The metrics collector to use for metrics about reverse calls. /// The logger factory to use to create loggers. public PingedConnection( RequestId requestId, + IReverseCallStreamWriterFactory reverseCallWriterFactory, IAsyncStreamReader runtimeStream, IAsyncStreamWriter clientStream, ServerCallContext context, IConvertReverseCallMessages messageConverter, - ICancelTokenIfDeadlineIsMissed keepalive, + ICancelTokenIfDeadlineIsMissed keepAlive, ICallbackScheduler pingScheduler, IMetricsCollector metrics, ILoggerFactory loggerFactory) { - _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(context.CancellationToken, keepalive.Token); - _requestId = requestId; - _keepalive = keepalive; + _reverseCallWriterFactory = reverseCallWriterFactory; + _clientStream = clientStream; + _messageConverter = messageConverter; + _keepAlive = keepAlive; _pingScheduler = pingScheduler; - + _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(context.CancellationToken, keepAlive.Token); + _metrics = metrics; + _logger = loggerFactory.CreateLogger>(); _wrappedReader = new WrappedAsyncStreamReader( requestId, runtimeStream, @@ -79,26 +89,16 @@ public PingedConnection( metrics, loggerFactory.CreateLogger>(), _cancellationTokenSource.Token); - _wrappedWriter = new WrappedAsyncStreamWriter( - requestId, - clientStream, - messageConverter, - metrics, - loggerFactory.CreateLogger>(), - _cancellationTokenSource.Token); - - _metrics = metrics; - _logger = loggerFactory.CreateLogger>(); - + WaitForCallContextInFirstMessageThenStartPinging(); - _keepAliveExpiredRegistration = keepalive.Token.Register(NotifyKeepaliveTimedOut); + _keepAliveExpiredRegistration = keepAlive.Token.Register(NotifyKeepAliveTimedOut); } /// public IAsyncStreamReader RuntimeStream => _wrappedReader; /// - public IAsyncStreamWriter ClientStream => _wrappedWriter; + public IAsyncStreamWriter ClientStream => _reverseCallStreamWriter ?? throw new ConnectArgumentsNotReceived(); /// public CancellationToken CancellationToken => _cancellationTokenSource.Token; @@ -120,15 +120,19 @@ protected virtual void Dispose(bool disposing) if (disposing) { _logger.DisposingPingedConnection(_requestId); - _cancellationTokenSource.Cancel(); + _cancellationTokenSource?.Cancel(); MaybeStopPinging(); _keepAliveExpiredRegistration.Dispose(); - _keepalive.Dispose(); + _keepAlive?.Dispose(); _wrappedReader.ReverseCallContextReceived -= OnReverseCallContextReceived; _wrappedReader.ReverseCallContextNotReceivedInFirstMessage -= OnReverseCallContextNotReceivedInFirstMessage; - _wrappedReader.MessageReceived -= ResetKeepaliveTokenCancellation; - _cancellationTokenSource.Dispose(); - _wrappedWriter.Dispose(); + if (_keepAliveTimeout.HasValue) + { + _wrappedReader.MessageReceived -= ResetKeepAliveTokenCancellation; + } + + _cancellationTokenSource?.Dispose(); + _reverseCallStreamWriter?.Dispose(); _logger.DisposedPingedConnection(_requestId); } @@ -145,25 +149,44 @@ void WaitForCallContextInFirstMessageThenStartPinging() void OnReverseCallContextReceived(ReverseCallArgumentsContext context) { - _waitForCallContextStopwatch.Stop(); - _metrics.AddToTotalWaitForFirstMessageTime(_waitForCallContextStopwatch.Elapsed); - _logger.ReceivedReverseCallContext(_requestId, _waitForCallContextStopwatch.Elapsed); + _waitForCallContextStopwatch?.Stop(); + _metrics.AddToTotalWaitForFirstMessageTime(_waitForCallContextStopwatch?.Elapsed ?? TimeSpan.Zero); + _logger.ReceivedReverseCallContext(_requestId, _waitForCallContextStopwatch?.Elapsed ?? TimeSpan.Zero); + var pingDuration = context.PingInterval; - var pingInterval = context.PingInterval.ToTimeSpan(); - StartPinging(pingInterval); - StartKeepaliveTokenTimeout(pingInterval); + if (ShouldStartPinging(pingDuration, out var pingInterval)) + { + _reverseCallStreamWriter = _reverseCallWriterFactory.CreateWriter( + _requestId, + _clientStream, + _messageConverter, + _cancellationTokenSource.Token, + pingInterval); + StartPinging(pingInterval.Value); + } + else + { + _reverseCallStreamWriter = _reverseCallWriterFactory.CreateWriter( + _requestId, + _clientStream, + _messageConverter, + _cancellationTokenSource.Token, + pingInterval); + } } + void OnReverseCallContextNotReceivedInFirstMessage() { _cancellationTokenSource.Cancel(); - _waitForCallContextStopwatch.Stop(); - _logger.FailedToStartPingAndTimeout(_requestId, _waitForCallContextStopwatch.Elapsed); + _waitForCallContextStopwatch?.Stop(); + _logger.FailedToStartPingAndTimeout(_requestId, _waitForCallContextStopwatch?.Elapsed ?? TimeSpan.Zero); } void StartPinging(TimeSpan pingInterval) { _logger.StartPings(_requestId, pingInterval); - _scheduledPings = _pingScheduler.ScheduleCallback(_wrappedWriter.MaybeWritePing, pingInterval); + _scheduledPings = _pingScheduler.ScheduleCallback(_reverseCallStreamWriter!.MaybeWritePing, pingInterval); + StartKeepAliveTokenTimeout(pingInterval); } void MaybeStopPinging() @@ -179,24 +202,42 @@ void MaybeStopPinging() } } - void StartKeepaliveTokenTimeout(TimeSpan pingInterval) + void StartKeepAliveTokenTimeout(TimeSpan pingInterval) { _logger.StartKeepaliveTokenTimeout(_requestId, pingInterval); - _keepaliveTimeout = pingInterval.Multiply(3); - _wrappedReader.MessageReceived += ResetKeepaliveTokenCancellation; - ResetKeepaliveTokenCancellation(); + _keepAliveTimeout = pingInterval.Multiply(3); + _wrappedReader.MessageReceived += ResetKeepAliveTokenCancellation; + ResetKeepAliveTokenCancellation(); } - void ResetKeepaliveTokenCancellation() + void ResetKeepAliveTokenCancellation() { - _keepalive.RefreshDeadline(_keepaliveTimeout); + _keepAlive.RefreshDeadline(_keepAliveTimeout!.Value); _metrics.IncrementTotalKeepaliveTokenResets(); _logger.ResettingKeepaliveToken(_requestId); } - void NotifyKeepaliveTimedOut() + void NotifyKeepAliveTimedOut() { _metrics.IncrementTotalKeepaliveTimeouts(); _logger.KeepaliveTimedOut(_requestId); } -} \ No newline at end of file + + static bool ShouldStartPinging(Duration pingDuration, [NotNullWhen(true)]out TimeSpan? pingInterval) + { + pingInterval = null; + if (pingDuration.Seconds == Duration.MaxSeconds) + { + return false; + } + + var timeSpan = pingDuration.ToTimeSpan(); + if (timeSpan < TimeSpan.FromSeconds(1)) + { + return false; + } + + pingInterval = timeSpan; + return true; + } +} diff --git a/Source/Services/ReverseCalls/PingedConnectionFactory.cs b/Source/Services/ReverseCalls/PingedConnectionFactory.cs index 41ba3bdb7..155093553 100644 --- a/Source/Services/ReverseCalls/PingedConnectionFactory.cs +++ b/Source/Services/ReverseCalls/PingedConnectionFactory.cs @@ -1,6 +1,7 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using Dolittle.Runtime.DependencyInversion.Lifecycle; using Dolittle.Runtime.Services.Callbacks; using Google.Protobuf; using Grpc.Core; @@ -11,8 +12,10 @@ namespace Dolittle.Runtime.Services.ReverseCalls; /// /// Represents an implementation of . /// +[Singleton] public class PingedConnectionFactory : IKeepConnectionsAlive { + readonly IReverseCallStreamWriterFactory _reverseCallWriterFactory; readonly ICallbackScheduler _callbackScheduler; readonly IMetricsCollector _metricsCollector; readonly ILoggerFactory _loggerFactory; @@ -20,11 +23,13 @@ public class PingedConnectionFactory : IKeepConnectionsAlive /// /// Initializes a new instance of the class. /// + /// /// The callback scheduler to use for scheduling pings. /// The metrics collector to use for metrics about pinged reverse call connections. /// The logger factory to use to create loggers. - public PingedConnectionFactory(ICallbackScheduler callbackScheduler, IMetricsCollector metricsCollector, ILoggerFactory loggerFactory) + public PingedConnectionFactory(IReverseCallStreamWriterFactory reverseCallWriterFactory, ICallbackScheduler callbackScheduler, IMetricsCollector metricsCollector, ILoggerFactory loggerFactory) { + _reverseCallWriterFactory = reverseCallWriterFactory; _callbackScheduler = callbackScheduler; _metricsCollector = metricsCollector; _loggerFactory = loggerFactory; @@ -45,6 +50,7 @@ public IPingedConnection CreatePingedReverseCall where TResponse : class => new PingedConnection( requestId, + _reverseCallWriterFactory, runtimeStream, clientStream, context, @@ -53,4 +59,4 @@ public IPingedConnection CreatePingedReverseCall _callbackScheduler, _metricsCollector, _loggerFactory); -} \ No newline at end of file +} diff --git a/Source/Services/ReverseCalls/WrappedAsyncStreamWriter.cs b/Source/Services/ReverseCalls/ReverseCallStreamWriter.cs similarity index 92% rename from Source/Services/ReverseCalls/WrappedAsyncStreamWriter.cs rename to Source/Services/ReverseCalls/ReverseCallStreamWriter.cs index d5304cffc..1331b42d2 100644 --- a/Source/Services/ReverseCalls/WrappedAsyncStreamWriter.cs +++ b/Source/Services/ReverseCalls/ReverseCallStreamWriter.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; +using Dolittle.Runtime.DependencyInversion; using Dolittle.Services.Contracts; using Google.Protobuf; using Grpc.Core; @@ -21,7 +22,8 @@ namespace Dolittle.Runtime.Services.ReverseCalls; /// Type of the response that is received after the initial Connect call. /// Type of the requests sent from the Runtime to the Client. /// Type of the responses sent from the Client to the Runtime. -public class WrappedAsyncStreamWriter : IAsyncStreamWriter, IDisposable +[DisableAutoRegistration] +public class ReverseCallStreamWriter : IReverseCallStreamWriter where TClientMessage : IMessage, new() where TServerMessage : IMessage, new() where TConnectArguments : class @@ -36,10 +38,11 @@ public class WrappedAsyncStreamWriter - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The request id for the gRPC method call. /// The original gRPC stream writer to wrap. @@ -47,7 +50,7 @@ public class WrappedAsyncStreamWriterThe metrics collector to use for metrics about reverse call stream writes. /// The logger to use. /// A cancellation token to use for cancelling pending and future writes. - public WrappedAsyncStreamWriter( + public ReverseCallStreamWriter( RequestId requestId, IAsyncStreamWriter originalStream, IConvertReverseCallMessages messageConverter, @@ -61,6 +64,7 @@ public WrappedAsyncStreamWriter( _metrics = metrics; _logger = logger; _cancellationToken = cancellationToken; + } /// @@ -80,7 +84,7 @@ public async Task WriteAsync(TServerMessage message) _logger.WritingMessage(_requestId, typeof(TServerMessage)); _cancellationToken.ThrowIfCancellationRequested(); - if (!_writeLock.Wait(0)) + if (IsWriting()) { var stopwatch = Stopwatch.StartNew(); @@ -121,6 +125,9 @@ public async Task WriteAsync(TServerMessage message) } } + bool IsWriting() => !_writeLock.Wait(0); + + /// /// Writes a ping message synchronously if another write operation is not in progress. /// @@ -129,7 +136,7 @@ public void MaybeWritePing() _logger.WritingPing(_requestId); _cancellationToken.ThrowIfCancellationRequested(); - if (!_writeLock.Wait(0)) + if (IsWriting()) { _logger.WritingPingSkipped(_requestId); return; @@ -183,4 +190,4 @@ protected virtual void Dispose(bool disposing) _disposed = true; } -} \ No newline at end of file +} diff --git a/Source/Services/ReverseCalls/ReverseCallStreamWriterFactory.cs b/Source/Services/ReverseCalls/ReverseCallStreamWriterFactory.cs new file mode 100644 index 000000000..0ba57a53c --- /dev/null +++ b/Source/Services/ReverseCalls/ReverseCallStreamWriterFactory.cs @@ -0,0 +1,72 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using Dolittle.Runtime.Actors; +using Dolittle.Runtime.DependencyInversion.Lifecycle; +using Dolittle.Runtime.Services.Configuration; +using Google.Protobuf; +using Grpc.Core; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Proto; + +namespace Dolittle.Runtime.Services.ReverseCalls; + +[Singleton] +public class ReverseCallStreamWriterFactory : IReverseCallStreamWriterFactory +{ + readonly ActorSystem _actorSystem; + readonly ICreateProps _props; + readonly IMetricsCollector _metrics; + readonly ILoggerFactory _loggerFactory; + readonly ReverseCallsConfiguration _reverseCallsConfig; + + public ReverseCallStreamWriterFactory( + ActorSystem actorSystem, + ICreateProps props, + IOptions reverseCallsConfig, + IMetricsCollector metrics, + ILoggerFactory loggerFactory) + { + _actorSystem = actorSystem; + _props = props; + _metrics = metrics; + _loggerFactory = loggerFactory; + _reverseCallsConfig = reverseCallsConfig.Value; + } + + public IReverseCallStreamWriter CreateWriter( + RequestId requestId, + IAsyncStreamWriter originalStream, + IConvertReverseCallMessages messageConverter, + CancellationToken cancellationToken, + TimeSpan? pingTimeout) + where TClientMessage : IMessage, new() + where TServerMessage : IMessage, new() + where TConnectArguments : class + where TConnectResponse : class + where TRequest : class + where TResponse : class + { + if (!_reverseCallsConfig.UseActors) + { + return new ReverseCallStreamWriter( + requestId, + originalStream, + messageConverter, + _metrics, + _loggerFactory.CreateLogger>(), + cancellationToken); + } + return new ReverseCallStreamWriterActor.Wrapper( + _actorSystem, + _props, + requestId, + messageConverter, + originalStream, + cancellationToken, + pingTimeout); + } +} diff --git a/Source/Services/ReverseCalls/WrappedAsyncStreamReader.cs b/Source/Services/ReverseCalls/WrappedAsyncStreamReader.cs index 2b00e40c3..1be3a8639 100644 --- a/Source/Services/ReverseCalls/WrappedAsyncStreamReader.cs +++ b/Source/Services/ReverseCalls/WrappedAsyncStreamReader.cs @@ -83,12 +83,9 @@ public WrappedAsyncStreamReader( public Task MoveNext(CancellationToken cancellationToken) { _logger.ReadingMessage(_requestId); - if (_firstMoveNextCalled) - { - return MoveNextSkippingPongsAndRecordMetrics(cancellationToken); - } - - return FirstMoveNext(cancellationToken); + return _firstMoveNextCalled + ? MoveNextSkippingPongsAndRecordMetrics(cancellationToken) + : FirstMoveNext(cancellationToken); } async Task FirstMoveNext(CancellationToken cancellationToken) @@ -147,9 +144,7 @@ async Task MoveNextSkippingPongsAndRecordMetrics(CancellationToken cancell } bool CurrentMessageIsPong() - { - return _messageConverter.GetPong(_originalStream.Current) != default; - } + => _messageConverter.GetPong(_originalStream.Current) != default; void FetchReverseCallArgumentsContextFromFirstMessage(TClientMessage message) { @@ -187,4 +182,4 @@ void ReverseCallArgumentsNotReceivedBecauseNoContextOnConnectArguments() ReverseCallContextNotReceivedInFirstMessage?.Invoke(); _logger.ReverseCallArgumentsNotReceivedBecauseNoFirstMessage(_requestId); } -} \ No newline at end of file +} diff --git a/Source/Services/RuntimeShuttingDown.cs b/Source/Services/RuntimeShuttingDown.cs new file mode 100644 index 000000000..da32182c7 --- /dev/null +++ b/Source/Services/RuntimeShuttingDown.cs @@ -0,0 +1,17 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Dolittle.Runtime.Services; + +public class RuntimeShuttingDown : OperationCanceledException +{ + public RuntimeShuttingDown() : base("Operation is unavailable: runtime is shutting down") + { + } + + public RuntimeShuttingDown(string message) : base(message) + { + } +} diff --git a/Source/Services/Services.csproj b/Source/Services/Services.csproj index 9b3dd99b4..5b4ed3985 100644 --- a/Source/Services/Services.csproj +++ b/Source/Services/Services.csproj @@ -12,6 +12,7 @@ + @@ -22,5 +23,6 @@ + diff --git a/Source/Tenancy/TenantActionPerformer.cs b/Source/Tenancy/TenantActionPerformer.cs index b3c414c8d..5ee1fc821 100644 --- a/Source/Tenancy/TenantActionPerformer.cs +++ b/Source/Tenancy/TenantActionPerformer.cs @@ -50,7 +50,7 @@ public Try TryPerform(Func callback) } } - return Try.Succeeded(); + return Try.Succeeded; } /// @@ -74,6 +74,6 @@ public async Task TryPerformAsync(FuncThis . /// The callback to call with the service for each tenant. /// The type of the service to get from the per-tenant service providers. - public static void PerformOn(this IPerformActionsForAllTenants performer, Action callback) + public static void PerformOn(this IPerformActionsForAllTenants performer, Action callback) where TService: notnull => performer.Perform((_, services) => callback(services.GetRequiredService())); /// @@ -30,7 +30,7 @@ public static void PerformOn(this IPerformActionsForAllTenants perform /// The callback to call with the service for each tenant. /// The type of the service to get from the per-tenant service providers. /// The first that failed, or success if all succeeded. - public static Try TryPerformOn(this IPerformActionsForAllTenants performer, Func callback) + public static Try TryPerformOn(this IPerformActionsForAllTenants performer, Func callback) where TService: notnull => performer.TryPerform((_, services) => callback(services.GetRequiredService())); /// /// Perform asynchronous an action on the for all tenants. @@ -40,7 +40,7 @@ public static Try TryPerformOn(this IPerformActionsForAllTenants perfo /// The callback to call with the service for each tenant. /// The type of the service to get from the per-tenant service providers. /// A that is resolved when the callback is called for all tenants. - public static Task PerformAsyncOn(this IPerformActionsForAllTenants performer, Func callback) + public static Task PerformAsyncOn(this IPerformActionsForAllTenants performer, Func callback) where TService: notnull => performer.PerformAsync((_, services) => callback(services.GetRequiredService())); /// @@ -51,7 +51,7 @@ public static Task PerformAsyncOn(this IPerformActionsForAllTenants pe /// The callback to call with the service, tenant and service provider for each tenant. /// The type of the service to get from the per-tenant service providers. /// A that is resolved when the callback is called for all tenants. - public static Task PerformAsyncOn(this IPerformActionsForAllTenants performer, Func callback) + public static Task PerformAsyncOn(this IPerformActionsForAllTenants performer, Func callback) where TService: notnull => performer.PerformAsync((tenant, services) => callback(services.GetRequiredService(), tenant, services)); @@ -63,7 +63,7 @@ public static Task PerformAsyncOn(this IPerformActionsForAllTenants pe /// The callback to call with the service for each tenant. /// The type of the service to get from the per-tenant service providers. /// A that, when resolved, returns the first that failed, or success if all succeeded. - public static Task TryPerformAsyncOn(this IPerformActionsForAllTenants performer, Func> callback) + public static Task TryPerformAsyncOn(this IPerformActionsForAllTenants performer, Func> callback) where TService: notnull => performer.TryPerformAsync((_, services) => callback(services.GetRequiredService())); /// @@ -74,6 +74,6 @@ public static Task TryPerformAsyncOn(this IPerformActionsForAllTe /// The callback to call with the service, tenant and service provider for each tenant. /// The type of the service to get from the per-tenant service providers. /// A that, when resolved, returns the first that failed, or success if all succeeded. - public static Task TryPerformAsyncOn(this IPerformActionsForAllTenants performer, Func> callback) + public static Task TryPerformAsyncOn(this IPerformActionsForAllTenants performer, Func> callback) where TService: notnull => performer.TryPerformAsync((tenant, services) => callback(services.GetRequiredService(), tenant, services)); } diff --git a/Specifications/.editorconfig b/Specifications/.editorconfig index dfa55023b..894128de0 100644 --- a/Specifications/.editorconfig +++ b/Specifications/.editorconfig @@ -1,4 +1,4 @@ -# this is to just supress the main editorconfig from applying here +# this is to just suppress the main editorconfig from applying here root = true [*.cs] @@ -12,8 +12,14 @@ file_header_template = Copyright (c) Dolittle. All rights reserved.\nLicensed un dotnet_diagnostic.IDE1006.severity = none dotnet_diagnostic.IDE0044.severity = none +dotnet_diagnostic.IDE0051.severity = none dotnet_diagnostic.IDE0052.severity = none dotnet_diagnostic.CA2211.severity = none +dotnet_diagnostic.CS0612.severity = none dotnet_diagnostic.RCS1169.severity = none dotnet_diagnostic.RCS1018.severity = none dotnet_diagnostic.RCS1213.severity = none + +resharper_check_namespace_highlighting = none +resharper_inconsistent_naming_highlighting = none +resharper_unused_type_highlighting = none \ No newline at end of file diff --git a/Specifications/Aggregates/Aggregates.csproj b/Specifications/Aggregates/Aggregates.csproj index 6eb13fce5..251cc9c58 100755 --- a/Specifications/Aggregates/Aggregates.csproj +++ b/Specifications/Aggregates/Aggregates.csproj @@ -8,7 +8,7 @@ - + diff --git a/Specifications/Domain/Domain.csproj b/Specifications/Domain/Domain.csproj index 842d7bbd8..bfb791ccc 100644 --- a/Specifications/Domain/Domain.csproj +++ b/Specifications/Domain/Domain.csproj @@ -8,10 +8,6 @@ - - - - diff --git a/Specifications/Embeddings.Processing/Embeddings.Processing.csproj b/Specifications/Embeddings.Processing/Embeddings.Processing.csproj index 265d61285..d2452e545 100755 --- a/Specifications/Embeddings.Processing/Embeddings.Processing.csproj +++ b/Specifications/Embeddings.Processing/Embeddings.Processing.csproj @@ -11,7 +11,6 @@ - diff --git a/Specifications/Embeddings.Processing/for_CompareProjectionDefinitionsForAllTenants/given/all_dependencies.cs b/Specifications/Embeddings.Processing/for_CompareProjectionDefinitionsForAllTenants/given/all_dependencies.cs index e6aeb703f..c5fefa91f 100644 --- a/Specifications/Embeddings.Processing/for_CompareProjectionDefinitionsForAllTenants/given/all_dependencies.cs +++ b/Specifications/Embeddings.Processing/for_CompareProjectionDefinitionsForAllTenants/given/all_dependencies.cs @@ -9,10 +9,8 @@ using Dolittle.Runtime.Embeddings.Store.Definition; using Dolittle.Runtime.Tenancy; using Machine.Specifications; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Moq; -using Version = Dolittle.Runtime.Domain.Platform.Version; namespace Dolittle.Runtime.Embeddings.Processing.for_CompareProjectionDefinitionsForAllTenants.given; diff --git a/Specifications/Embeddings.Processing/for_EmbeddingProcessor/given/all_dependencies.cs b/Specifications/Embeddings.Processing/for_EmbeddingProcessor/given/all_dependencies.cs index 9c7cb9d4f..6086f591c 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingProcessor/given/all_dependencies.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingProcessor/given/all_dependencies.cs @@ -2,16 +2,13 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Globalization; using System.Threading; using System.Threading.Tasks; -using Dolittle.Runtime.Domain.Platform; using Dolittle.Runtime.Domain.Tenancy; using Dolittle.Runtime.Embeddings.Store; using Dolittle.Runtime.Events.Contracts; using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Execution; using Dolittle.Runtime.Protobuf; using Dolittle.Runtime.Rudimentary; using Machine.Specifications; @@ -59,7 +56,7 @@ public class all_dependencies Mock.Of()); cancellation_token = CancellationToken.None; - state_updater.Setup(_ => _.TryUpdateAll(Moq.It.IsAny(), It.IsAny())).Returns(Task.FromResult(Try.Succeeded())); + state_updater.Setup(_ => _.TryUpdateAll(Moq.It.IsAny(), It.IsAny())).Returns(Task.FromResult(Try.Succeeded)); event_waiter.Setup(_ => _.WaitForEvent(ScopeId.Default, StreamId.EventLog, It.IsAny())).Returns((_scope, _stream, cancellationToken) => Task.Delay(Timeout.Infinite, cancellationToken)); }; diff --git a/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_deleting/and_committing_events_fails.cs b/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_deleting/and_committing_events_fails.cs index cce515583..fd3018879 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_deleting/and_committing_events_fails.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_deleting/and_committing_events_fails.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; using System.Threading; using System.Threading.Tasks; using Dolittle.Runtime.Embeddings.Store; @@ -9,7 +8,6 @@ using Dolittle.Runtime.Rudimentary; using Machine.Specifications; using Moq; -using CommittedAggregateEvents = Dolittle.Runtime.Events.Store.CommittedAggregateEvents; using It = Machine.Specifications.It; using UncommittedAggregateEvents = Dolittle.Runtime.Events.Store.UncommittedAggregateEvents; diff --git a/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_deleting/and_everything_works.cs b/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_deleting/and_everything_works.cs index 21551d394..f5c6ddf19 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_deleting/and_everything_works.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_deleting/and_everything_works.cs @@ -8,7 +8,6 @@ using Dolittle.Runtime.Rudimentary; using Machine.Specifications; using Moq; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; using It = Machine.Specifications.It; using UncommittedAggregateEvents = Dolittle.Runtime.Events.Store.UncommittedAggregateEvents; @@ -36,7 +35,7 @@ public class and_everything_works : given.all_dependencies_and_a_key .ReturnsAsync(SuccessfulCommitResponse(committed_events)); embedding_store .Setup(_ => _.TryRemove(embedding, key, aggregate_root_version, Moq.It.IsAny())) - .Returns(Task.FromResult(Try.Succeeded())); + .Returns(Task.FromResult(Try.Succeeded)); }; static Try result; diff --git a/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_deleting/and_request_is_sent_to_the_wrong_processor.cs b/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_deleting/and_request_is_sent_to_the_wrong_processor.cs index 3770ad821..4365e88c9 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_deleting/and_request_is_sent_to_the_wrong_processor.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_deleting/and_request_is_sent_to_the_wrong_processor.cs @@ -2,13 +2,8 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Globalization; using System.Threading.Tasks; -using Dolittle.Runtime.Domain.Platform; -using Dolittle.Runtime.Execution; using Machine.Specifications; -using Environment = Dolittle.Runtime.Domain.Platform.Environment; -using Version = Dolittle.Runtime.Domain.Platform.Version; namespace Dolittle.Runtime.Embeddings.Processing.for_EmbeddingProcessor.when_deleting; diff --git a/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_started/and_aggregate_events_are_committed/and_everything_works.cs b/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_started/and_aggregate_events_are_committed/and_everything_works.cs index f6f66bf8b..666e97cac 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_started/and_aggregate_events_are_committed/and_everything_works.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_started/and_aggregate_events_are_committed/and_everything_works.cs @@ -29,7 +29,7 @@ public class and_everything_works : given.all_dependencies _ => Task.Delay(Timeout.Infinite) }; }); - state_updater.Setup(_ => _.TryUpdateAll(execution_context, Moq.It.IsAny())).Returns(Task.FromResult(Try.Succeeded())); + state_updater.Setup(_ => _.TryUpdateAll(execution_context, Moq.It.IsAny())).Returns(Task.FromResult(Try.Succeeded)); }; Because of = () => diff --git a/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_updating/and_committing_events_fails.cs b/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_updating/and_committing_events_fails.cs index 795c86181..f0bd55278 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_updating/and_committing_events_fails.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_updating/and_committing_events_fails.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; using System.Threading; using System.Threading.Tasks; using Dolittle.Runtime.Embeddings.Store; diff --git a/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_updating/and_everything_works.cs b/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_updating/and_everything_works.cs index 708f0e27a..3f86a9381 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_updating/and_everything_works.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_updating/and_everything_works.cs @@ -9,7 +9,6 @@ using Dolittle.Runtime.Rudimentary; using Machine.Specifications; using Moq; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; using It = Machine.Specifications.It; using UncommittedAggregateEvents = Dolittle.Runtime.Events.Store.UncommittedAggregateEvents; @@ -36,7 +35,7 @@ public class and_everything_works : given.all_dependencies_and_a_desired_state .ReturnsAsync(SuccessfulCommitResponse(committed_events)); embedding_store .Setup(_ => _.TryReplace(embedding, key, aggregate_root_version, desired_state, Moq.It.IsAny())) - .Returns(Task.FromResult(Try.Succeeded())); + .Returns(Task.FromResult(Try.Succeeded)); }; static Try result; diff --git a/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_updating/and_request_is_sent_to_the_wrong_processor.cs b/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_updating/and_request_is_sent_to_the_wrong_processor.cs index b9b7cd25d..b1dfb0e8f 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_updating/and_request_is_sent_to_the_wrong_processor.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingProcessor/when_updating/and_request_is_sent_to_the_wrong_processor.cs @@ -2,13 +2,8 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Globalization; using System.Threading.Tasks; -using Dolittle.Runtime.Domain.Platform; -using Dolittle.Runtime.Execution; using Machine.Specifications; -using Environment = Dolittle.Runtime.Domain.Platform.Environment; -using Version = Dolittle.Runtime.Domain.Platform.Version; namespace Dolittle.Runtime.Embeddings.Processing.for_EmbeddingProcessor.when_updating; diff --git a/Specifications/Embeddings.Processing/for_EmbeddingProcessorFactory/given/all_dependencies.cs b/Specifications/Embeddings.Processing/for_EmbeddingProcessorFactory/given/all_dependencies.cs index 09f8c4a7b..221afbe9b 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingProcessorFactory/given/all_dependencies.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingProcessorFactory/given/all_dependencies.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; using Dolittle.Runtime.Domain.Tenancy; using Dolittle.Runtime.Embeddings.Store; using Dolittle.Runtime.Events.Store; @@ -9,9 +8,7 @@ using Machine.Specifications; using Microsoft.Extensions.Logging.Abstractions; using Moq; -using It = Moq.It; using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; -using Version = Dolittle.Runtime.Domain.Platform.Version; namespace Dolittle.Runtime.Embeddings.Processing.for_EmbeddingProcessorFactory.given; diff --git a/Specifications/Embeddings.Processing/for_EmbeddingProcessors/when_starting/two_processors/and_one_processor_completes.cs b/Specifications/Embeddings.Processing/for_EmbeddingProcessors/when_starting/two_processors/and_one_processor_completes.cs index 30398fb14..d741d9f2a 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingProcessors/when_starting/two_processors/and_one_processor_completes.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingProcessors/when_starting/two_processors/and_one_processor_completes.cs @@ -26,11 +26,11 @@ public class and_one_processor_completes : given.two_tenants_and_processors { await Task.Delay(10).ConfigureAwait(false); } - return Try.Succeeded(); + return Try.Succeeded; }); var processor_b = new Mock(); - processor_b.Setup(_ => _.Start(Moq.It.IsAny())).Returns(Task.FromResult(Try.Succeeded())); + processor_b.Setup(_ => _.Start(Moq.It.IsAny())).Returns(Task.FromResult(Try.Succeeded)); factory.Setup(_ => _(tenant_a)).Returns(processor_a.Object); factory.Setup(_ => _(tenant_b)).Returns(processor_b.Object); diff --git a/Specifications/Embeddings.Processing/for_EmbeddingProcessors/when_starting/two_processors/and_one_processor_fails.cs b/Specifications/Embeddings.Processing/for_EmbeddingProcessors/when_starting/two_processors/and_one_processor_fails.cs index 144ee2a78..56923e5c0 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingProcessors/when_starting/two_processors/and_one_processor_fails.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingProcessors/when_starting/two_processors/and_one_processor_fails.cs @@ -28,7 +28,7 @@ public class and_one_processor_fails : given.two_tenants_and_processors { await Task.Delay(10).ConfigureAwait(false); } - return Try.Succeeded(); + return Try.Succeeded; }); diff --git a/Specifications/Embeddings.Processing/for_EmbeddingProcessors/when_starting/two_processors/and_one_processor_is_cancelled.cs b/Specifications/Embeddings.Processing/for_EmbeddingProcessors/when_starting/two_processors/and_one_processor_is_cancelled.cs index 784d5971e..5bf5358b4 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingProcessors/when_starting/two_processors/and_one_processor_is_cancelled.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingProcessors/when_starting/two_processors/and_one_processor_is_cancelled.cs @@ -30,7 +30,7 @@ public class and_one_processor_is_cancelled : given.two_tenants_and_processors { await Task.Delay(10).ConfigureAwait(false); } - return Try.Succeeded(); + return Try.Succeeded; }); @@ -42,7 +42,7 @@ public class and_one_processor_is_cancelled : given.two_tenants_and_processors { await Task.Delay(10).ConfigureAwait(false); } - return Try.Succeeded(); + return Try.Succeeded; }); diff --git a/Specifications/Embeddings.Processing/for_EmbeddingProcessors/when_starting/two_processors/and_starting_them_again.cs b/Specifications/Embeddings.Processing/for_EmbeddingProcessors/when_starting/two_processors/and_starting_them_again.cs index 7eddd9a40..adc68e487 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingProcessors/when_starting/two_processors/and_starting_them_again.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingProcessors/when_starting/two_processors/and_starting_them_again.cs @@ -25,7 +25,7 @@ public class and_starting_them_again : given.two_tenants_and_processors { await Task.Delay(10).ConfigureAwait(false); } - return Try.Succeeded(); + return Try.Succeeded; }); @@ -36,7 +36,7 @@ public class and_starting_them_again : given.two_tenants_and_processors { await Task.Delay(10).ConfigureAwait(false); } - return Try.Succeeded(); + return Try.Succeeded; }); diff --git a/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/and_one_of_two_keys_fails.cs b/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/and_one_of_two_keys_fails.cs index 40c6c8391..24a984e91 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/and_one_of_two_keys_fails.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/and_one_of_two_keys_fails.cs @@ -72,7 +72,7 @@ public class and_one_of_two_keys_fails : given.all_dependencies .Returns(Task.FromResult>(projection_result_b)); embedding_store .Setup(_ => _.TryReplace(embedding, projection_key_b, projection_result_b.Version, projection_result_b.State, cancellation_token)) - .Returns(Task.FromResult(Try.Succeeded())); + .Returns(Task.FromResult(Try.Succeeded)); }; static Try result; diff --git a/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/and_projecting_partially_succeeds.cs b/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/and_projecting_partially_succeeds.cs index 21d6dcc8d..e29ecf098 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/and_projecting_partially_succeeds.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/and_projecting_partially_succeeds.cs @@ -41,7 +41,7 @@ public class and_projecting_partially_succeeds : given.all_dependencies .Returns(Task.FromResult>(current_state)); embedding_store .Setup(_ => _.TryReplace(embedding, projection_key, projection_result.Version, projection_result.State, cancellation_token)) - .Returns(Task.FromResult(Try.Succeeded())); + .Returns(Task.FromResult(Try.Succeeded)); committed_events_fetcher .Setup(_ => _.FetchForAggregateAfter(projection_key.Value, embedding.Value, current_state.Version, cancellation_token)) .Returns(Task.FromResult(unprocessed_events)); diff --git a/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/and_two_of_three_keys_fails.cs b/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/and_two_of_three_keys_fails.cs index 60a9fa5a4..8975454f2 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/and_two_of_three_keys_fails.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/and_two_of_three_keys_fails.cs @@ -81,7 +81,7 @@ public class and_two_of_three_keys_fails : given.all_dependencies .Returns(Task.FromResult>(projection_result_c)); embedding_store .Setup(_ => _.TryReplace(embedding, projection_key_c, projection_result_c.Version, projection_result_c.State, cancellation_token)) - .Returns(Task.FromResult(Try.Succeeded())); + .Returns(Task.FromResult(Try.Succeeded)); }; static Try result; diff --git a/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/from_many_events.cs b/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/from_many_events.cs index f1ef383af..31d5eb7ad 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/from_many_events.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/from_many_events.cs @@ -39,7 +39,7 @@ public class from_many_events : given.all_dependencies .Returns(Task.FromResult>(current_state)); embedding_store .Setup(_ => _.TryReplace(embedding, projection_key, projection_result.Version, projection_result.State, cancellation_token)) - .Returns(Task.FromResult(Try.Succeeded())); + .Returns(Task.FromResult(Try.Succeeded)); committed_events_fetcher .Setup(_ => _.FetchForAggregateAfter(projection_key.Value, embedding.Value, current_state.Version, cancellation_token)) .Returns(Task.FromResult(unprocessed_events)); diff --git a/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/two_keys.cs b/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/two_keys.cs index 13648710c..abaffad86 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/two_keys.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingStateUpdater/when_updating/two_keys.cs @@ -56,7 +56,7 @@ public class two_keys : given.all_dependencies .Returns(Task.FromResult>(projection_result_a)); embedding_store .Setup(_ => _.TryRemove(embedding, projection_key_a, projection_result_a.Version, cancellation_token)) - .Returns(Task.FromResult(Try.Succeeded())); + .Returns(Task.FromResult(Try.Succeeded)); embedding_store .Setup(_ => _.TryGet(embedding, projection_key_b, cancellation_token)) @@ -69,7 +69,7 @@ public class two_keys : given.all_dependencies .Returns(Task.FromResult>(projection_result_b)); embedding_store .Setup(_ => _.TryReplace(embedding, projection_key_b, projection_result_b.Version, projection_result_b.State, cancellation_token)) - .Returns(Task.FromResult(Try.Succeeded())); + .Returns(Task.FromResult(Try.Succeeded)); }; static Try result; diff --git a/Specifications/Embeddings.Processing/for_EmbeddingsService/given/all_dependencies.cs b/Specifications/Embeddings.Processing/for_EmbeddingsService/given/all_dependencies.cs index 4e1a35194..2318df621 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingsService/given/all_dependencies.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingsService/given/all_dependencies.cs @@ -19,13 +19,13 @@ using Dolittle.Runtime.Services; using Dolittle.Services.Contracts; using Grpc.Core; -using Grpc.Core.Testing; using Machine.Specifications; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Moq; using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; +using Status = Grpc.Core.Status; using Version = Dolittle.Runtime.Domain.Platform.Version; @@ -57,7 +57,7 @@ public class all_dependencies protected static EmbeddingDefinition embedding_definition; protected static CallRequestContext call_request_context; - Establish context = () => + private Establish context = () => { embedding_id = "814b9978-2a4c-44cb-a765-3a7caadc1ee4"; execution_context = new ExecutionContext( @@ -102,7 +102,7 @@ public class all_dependencies embedding_definition_persister = new Mock(); embedding_definition_persister .Setup(_ => _.TryPersist(Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(Try.Succeeded())); + .Returns(Task.FromResult(Try.Succeeded)); embedding_service = new EmbeddingsService( application_lifetime.Object, execution_context_creator.Object, @@ -116,18 +116,64 @@ public class all_dependencies dispatcher = new Mock>(); runtime_stream = new Mock>(); client_stream = new Mock>(); - call_context = TestServerCallContext.Create( - "method", - null, - DateTime.Now, - Metadata.Empty, - CancellationToken.None, - "peer", - null, - null, - _ => Task.CompletedTask, - () => WriteOptions.Default, - _ => { }); + + call_context = CallContext.Create(); }; + + +} + +public class CallContext : ServerCallContext +{ + readonly Metadata _requestHeaders; + readonly CancellationToken _cancellationToken; + readonly Metadata _responseTrailers; + readonly AuthContext _authContext; + readonly Dictionary _userState; + WriteOptions? _writeOptions; + + public Metadata? ResponseHeaders { get; private set; } + + private CallContext(Metadata requestHeaders, CancellationToken cancellationToken) + { + _requestHeaders = requestHeaders; + _cancellationToken = cancellationToken; + _responseTrailers = new Metadata(); + _authContext = new AuthContext(string.Empty, new Dictionary>()); + _userState = new Dictionary(); + } + + protected override string MethodCore => "MethodName"; + protected override string HostCore => "HostName"; + protected override string PeerCore => "PeerName"; + protected override DateTime DeadlineCore { get; } + protected override Metadata RequestHeadersCore => _requestHeaders; + protected override CancellationToken CancellationTokenCore => _cancellationToken; + protected override Metadata ResponseTrailersCore => _responseTrailers; + protected override Status StatusCore { get; set; } + protected override WriteOptions? WriteOptionsCore { get => _writeOptions; set { _writeOptions = value; } } + protected override AuthContext AuthContextCore => _authContext; + + protected override ContextPropagationToken CreatePropagationTokenCore(ContextPropagationOptions options) + { + throw new NotImplementedException(); + } + + protected override Task WriteResponseHeadersAsyncCore(Metadata responseHeaders) + { + if (ResponseHeaders != null) + { + throw new InvalidOperationException("Response headers have already been written."); + } + ResponseHeaders = responseHeaders; + return Task.CompletedTask; + } + + protected override IDictionary UserStateCore => _userState; + + public static CallContext Create(Metadata? requestHeaders = null, CancellationToken cancellationToken = default) + { + return new CallContext(requestHeaders ?? new Metadata(), cancellationToken); + } } \ No newline at end of file diff --git a/Specifications/Embeddings.Processing/for_EmbeddingsService/when_connecting/and_everything_works.cs b/Specifications/Embeddings.Processing/for_EmbeddingsService/when_connecting/and_everything_works.cs index 8df87c78a..4185bafde 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingsService/when_connecting/and_everything_works.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingsService/when_connecting/and_everything_works.cs @@ -78,6 +78,6 @@ public class and_everything_works : given.all_dependencies It should_not_reject_reverse_call = () => dispatcher.Verify( _ => _.Reject(IsAny(), IsAny()), Never); - Cleanup clean = () => processor_tcs.SetResult(Try.Succeeded()); + Cleanup clean = () => processor_tcs.SetResult(Try.Succeeded); } \ No newline at end of file diff --git a/Specifications/Embeddings.Processing/for_EmbeddingsService/when_deleting/and_deleting_fails.cs b/Specifications/Embeddings.Processing/for_EmbeddingsService/when_deleting/and_deleting_fails.cs index fb0aa0082..93e9a66ca 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingsService/when_deleting/and_deleting_fails.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingsService/when_deleting/and_deleting_fails.cs @@ -47,6 +47,7 @@ public class and_deleting_fails : given.all_dependencies { result = embedding_service.Delete(request, call_context).GetAwaiter().GetResult(); }; + It should_have_a_failure = () => result.Failure.ShouldNotBeNull(); It should_have_a_failure_with_correct_failure_id = () => result.Failure.Id.ShouldEqual(EmbeddingFailures.FailedToDeleteEmbedding.ToProtobuf()); } \ No newline at end of file diff --git a/Specifications/Embeddings.Processing/for_EmbeddingsService/when_deleting/and_everything_works.cs b/Specifications/Embeddings.Processing/for_EmbeddingsService/when_deleting/and_everything_works.cs index 0a13b490c..4b12fcaab 100644 --- a/Specifications/Embeddings.Processing/for_EmbeddingsService/when_deleting/and_everything_works.cs +++ b/Specifications/Embeddings.Processing/for_EmbeddingsService/when_deleting/and_everything_works.cs @@ -38,7 +38,7 @@ public class and_everything_works : given.all_dependencies embedding_processor .Setup(_ => _.Delete(key, execution_context, Moq.It.IsAny())) - .Returns(Task.FromResult(Try.Succeeded())); + .Returns(Task.FromResult(Try.Succeeded)); }; static DeleteResponse result; diff --git a/Specifications/Embeddings.Store.MongoDB/Embeddings.Store.MongoDB.csproj b/Specifications/Embeddings.Store.MongoDB/Embeddings.Store.MongoDB.csproj index 7a22ddd15..5f10e0133 100755 --- a/Specifications/Embeddings.Store.MongoDB/Embeddings.Store.MongoDB.csproj +++ b/Specifications/Embeddings.Store.MongoDB/Embeddings.Store.MongoDB.csproj @@ -7,12 +7,4 @@ - - - - - - - - diff --git a/Specifications/Embeddings.Store.Services.Grpc/Embeddings.Store.Services.Grpc.csproj b/Specifications/Embeddings.Store.Services.Grpc/Embeddings.Store.Services.Grpc.csproj index b56b21642..faca67fb5 100755 --- a/Specifications/Embeddings.Store.Services.Grpc/Embeddings.Store.Services.Grpc.csproj +++ b/Specifications/Embeddings.Store.Services.Grpc/Embeddings.Store.Services.Grpc.csproj @@ -1,17 +1,9 @@ - + Dolittle.Runtime.Embeddings.Store.Services.Grpc.Specs - - - - - - - - diff --git a/Specifications/Embeddings.Store.Services.Grpc/for_EmbeddingStoreGrpcService/given/the_service.cs b/Specifications/Embeddings.Store.Services.Grpc/for_EmbeddingStoreGrpcService/given/the_service.cs index e82522833..80160d7b0 100644 --- a/Specifications/Embeddings.Store.Services.Grpc/for_EmbeddingStoreGrpcService/given/the_service.cs +++ b/Specifications/Embeddings.Store.Services.Grpc/for_EmbeddingStoreGrpcService/given/the_service.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Threading; @@ -9,14 +10,68 @@ using Dolittle.Runtime.Execution; using Dolittle.Runtime.Projections.Store; using Grpc.Core; -using Grpc.Core.Testing; using Machine.Specifications; using Moq; using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; +using Status = Grpc.Core.Status; using Version = Dolittle.Runtime.Domain.Platform.Version; namespace Dolittle.Runtime.Embeddings.Store.Services.Grpc.for_EmbeddingStoreGrpcService.given; +public class CallContext : ServerCallContext +{ + readonly Metadata _requestHeaders; + readonly CancellationToken _cancellationToken; + readonly Metadata _responseTrailers; + readonly AuthContext _authContext; + readonly Dictionary _userState; + WriteOptions? _writeOptions; + + public Metadata? ResponseHeaders { get; private set; } + + private CallContext(Metadata requestHeaders, CancellationToken cancellationToken) + { + _requestHeaders = requestHeaders; + _cancellationToken = cancellationToken; + _responseTrailers = new Metadata(); + _authContext = new AuthContext(string.Empty, new Dictionary>()); + _userState = new Dictionary(); + } + + protected override string MethodCore => "MethodName"; + protected override string HostCore => "HostName"; + protected override string PeerCore => "PeerName"; + protected override DateTime DeadlineCore { get; } + protected override Metadata RequestHeadersCore => _requestHeaders; + protected override CancellationToken CancellationTokenCore => _cancellationToken; + protected override Metadata ResponseTrailersCore => _responseTrailers; + protected override Status StatusCore { get; set; } + protected override WriteOptions? WriteOptionsCore { get => _writeOptions; set { _writeOptions = value; } } + protected override AuthContext AuthContextCore => _authContext; + + protected override ContextPropagationToken CreatePropagationTokenCore(ContextPropagationOptions options) + { + throw new NotImplementedException(); + } + + protected override Task WriteResponseHeadersAsyncCore(Metadata responseHeaders) + { + if (ResponseHeaders != null) + { + throw new InvalidOperationException("Response headers have already been written."); + } + + ResponseHeaders = responseHeaders; + return Task.CompletedTask; + } + + protected override IDictionary UserStateCore => _userState; + + public static CallContext Create(Metadata? requestHeaders = null, CancellationToken cancellationToken = default) + { + return new CallContext(requestHeaders ?? new Metadata(), cancellationToken); + } +} public class the_service { protected static EmbeddingId embedding; @@ -28,7 +83,7 @@ public class the_service protected static EmbeddingStoreGrpcService grpc_service; protected static ServerCallContext call_context; - Establish context = () => + private Establish context = () => { embedding = "d6f99bc8-2430-4131-95d5-ea1540b260c3"; key = "some key"; @@ -44,18 +99,7 @@ public class the_service cancellation_token = CancellationToken.None; a_current_state = new EmbeddingCurrentState(3, EmbeddingCurrentStateType.Persisted, "some state", "some key"); embeddings_service = new Mock(); - call_context = TestServerCallContext.Create( - "method", - null, - DateTime.Now, - Metadata.Empty, - CancellationToken.None, - "peer", - null, - null, - _ => Task.CompletedTask, - () => WriteOptions.Default, - _ => { }); + call_context = CallContext.Create(); grpc_service = new EmbeddingStoreGrpcService(embeddings_service.Object); }; } \ No newline at end of file diff --git a/Specifications/Embeddings.Store.Services/Embeddings.Store.Services.csproj b/Specifications/Embeddings.Store.Services/Embeddings.Store.Services.csproj index 7c5ed7644..a608d5d66 100755 --- a/Specifications/Embeddings.Store.Services/Embeddings.Store.Services.csproj +++ b/Specifications/Embeddings.Store.Services/Embeddings.Store.Services.csproj @@ -1,17 +1,9 @@ - + Dolittle.Runtime.Embeddings.Store.Services.Specs - - - - - - - - diff --git a/Specifications/Embeddings.Store.Services/for_EmbeddingsService/when_getting_all_states.cs b/Specifications/Embeddings.Store.Services/for_EmbeddingsService/when_getting_all_states.cs index 1e2a1f56a..4c083757c 100644 --- a/Specifications/Embeddings.Store.Services/for_EmbeddingsService/when_getting_all_states.cs +++ b/Specifications/Embeddings.Store.Services/for_EmbeddingsService/when_getting_all_states.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using Dolittle.Runtime.Rudimentary; using Machine.Specifications; -using static Moq.It; using static Moq.Times; namespace Dolittle.Runtime.Embeddings.Store.Services.for_EmbeddingsService; diff --git a/Specifications/Embeddings.Store.Services/for_EmbeddingsService/when_getting_keys.cs b/Specifications/Embeddings.Store.Services/for_EmbeddingsService/when_getting_keys.cs index 2ec6f9eb8..43aad7cb3 100644 --- a/Specifications/Embeddings.Store.Services/for_EmbeddingsService/when_getting_keys.cs +++ b/Specifications/Embeddings.Store.Services/for_EmbeddingsService/when_getting_keys.cs @@ -6,7 +6,6 @@ using Dolittle.Runtime.Projections.Store; using Dolittle.Runtime.Rudimentary; using Machine.Specifications; -using static Moq.It; using static Moq.Times; namespace Dolittle.Runtime.Embeddings.Store.Services.for_EmbeddingsService; diff --git a/Specifications/Embeddings.Store.Services/for_EmbeddingsService/when_getting_one_state.cs b/Specifications/Embeddings.Store.Services/for_EmbeddingsService/when_getting_one_state.cs index 08d411213..742e09c95 100644 --- a/Specifications/Embeddings.Store.Services/for_EmbeddingsService/when_getting_one_state.cs +++ b/Specifications/Embeddings.Store.Services/for_EmbeddingsService/when_getting_one_state.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using Dolittle.Runtime.Rudimentary; using Machine.Specifications; -using static Moq.It; using static Moq.Times; namespace Dolittle.Runtime.Embeddings.Store.Services.for_EmbeddingsService; diff --git a/Specifications/Embeddings.Store/Embeddings.Store.csproj b/Specifications/Embeddings.Store/Embeddings.Store.csproj index a2948e1ca..4704f4756 100755 --- a/Specifications/Embeddings.Store/Embeddings.Store.csproj +++ b/Specifications/Embeddings.Store/Embeddings.Store.csproj @@ -1,17 +1,9 @@ - + Dolittle.Runtime.Embeddings.Store.Specs - - - - - - - - diff --git a/Specifications/EventHorizon/Consumer/Connections/for_EventHorizonConnection/when_starting_receiving_events_into/given/all_dependencies.cs b/Specifications/EventHorizon/Consumer/Connections/for_EventHorizonConnection/when_starting_receiving_events_into/given/all_dependencies.cs index 8f87bdeb5..1f0f4250c 100644 --- a/Specifications/EventHorizon/Consumer/Connections/for_EventHorizonConnection/when_starting_receiving_events_into/given/all_dependencies.cs +++ b/Specifications/EventHorizon/Consumer/Connections/for_EventHorizonConnection/when_starting_receiving_events_into/given/all_dependencies.cs @@ -12,7 +12,6 @@ using Dolittle.Runtime.Services.Clients; using Dolittle.Runtime.EventHorizon.Contracts; using System.Threading.Tasks; -using Dolittle.Runtime.Events.Contracts; using Dolittle.Runtime.Protobuf; using Google.Protobuf.WellKnownTypes; using Dolittle.Artifacts.Contracts; diff --git a/Specifications/EventHorizon/Consumer/Processing/for_EventProcessor/given/all_dependencies.cs b/Specifications/EventHorizon/Consumer/Processing/for_EventProcessor/given/all_dependencies.cs index eb37ad389..b8202c402 100644 --- a/Specifications/EventHorizon/Consumer/Processing/for_EventProcessor/given/all_dependencies.cs +++ b/Specifications/EventHorizon/Consumer/Processing/for_EventProcessor/given/all_dependencies.cs @@ -3,7 +3,6 @@ using System; using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Actors; using Dolittle.Runtime.Events.Store.EventHorizon; using Dolittle.Runtime.Events.Store.Streams; using Dolittle.Runtime.Execution; @@ -11,8 +10,6 @@ using Machine.Specifications; using Moq; using Microsoft.Extensions.Logging.Abstractions; -using Proto; -using Proto.Cluster; namespace Dolittle.Runtime.EventHorizon.Consumer.Processing.for_EventProcessor.given; diff --git a/Specifications/EventHorizon/Consumer/Processing/for_EventProcessor/when_processing/an_event.cs b/Specifications/EventHorizon/Consumer/Processing/for_EventProcessor/when_processing/an_event.cs index 532b0cb95..b28778bc2 100644 --- a/Specifications/EventHorizon/Consumer/Processing/for_EventProcessor/when_processing/an_event.cs +++ b/Specifications/EventHorizon/Consumer/Processing/for_EventProcessor/when_processing/an_event.cs @@ -1,7 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Threading; using Dolittle.Runtime.Events.Processing; using Dolittle.Runtime.Events.Store; using Machine.Specifications; diff --git a/Specifications/EventHorizon/Consumer/Processing/for_GetNextEventToReceiveForSubscription/given/all_dependencies.cs b/Specifications/EventHorizon/Consumer/Processing/for_GetNextEventToReceiveForSubscription/given/all_dependencies.cs index f7701121a..03bd68506 100644 --- a/Specifications/EventHorizon/Consumer/Processing/for_GetNextEventToReceiveForSubscription/given/all_dependencies.cs +++ b/Specifications/EventHorizon/Consumer/Processing/for_GetNextEventToReceiveForSubscription/given/all_dependencies.cs @@ -13,7 +13,7 @@ public class all_dependencies { protected static SubscriptionId subscription_id; protected static CancellationToken cancellation_token; - protected static Mock stream_processor_states; + protected static Mock stream_processor_states; protected static GetNextEventToReceiveForSubscription get_next_event; Establish context = () => @@ -27,7 +27,7 @@ public class all_dependencies "064749fc-8d13-4b12-a3c4-584e34596b99" ); cancellation_token = CancellationToken.None; - stream_processor_states = new Mock(); + stream_processor_states = new Mock(); get_next_event = new GetNextEventToReceiveForSubscription(stream_processor_states.Object); }; } \ No newline at end of file diff --git a/Specifications/EventHorizon/Consumer/Processing/for_GetNextEventToReceiveForSubscription/when_getting_event_to_receive/and_state_is_persisted.cs b/Specifications/EventHorizon/Consumer/Processing/for_GetNextEventToReceiveForSubscription/when_getting_event_to_receive/and_state_is_persisted.cs index 06793325b..ceeae09af 100644 --- a/Specifications/EventHorizon/Consumer/Processing/for_GetNextEventToReceiveForSubscription/when_getting_event_to_receive/and_state_is_persisted.cs +++ b/Specifications/EventHorizon/Consumer/Processing/for_GetNextEventToReceiveForSubscription/when_getting_event_to_receive/and_state_is_persisted.cs @@ -15,7 +15,7 @@ public class and_state_is_persisted : given.all_dependencies static IStreamProcessorState subscription_state; Establish context = () => { - subscription_state = new StreamProcessorState(4, DateTimeOffset.UtcNow); + subscription_state = new StreamProcessorState(4, 10, DateTimeOffset.UtcNow); stream_processor_states .Setup(_ => _.TryGetFor(subscription_id, cancellation_token)) .Returns(Task.FromResult(Try.Succeeded(subscription_state))); @@ -23,5 +23,5 @@ public class and_state_is_persisted : given.all_dependencies static StreamPosition result; Because of = () => result = get_next_event.GetNextEventToReceiveFor(subscription_id, cancellation_token).GetAwaiter().GetResult(); - It should_return_the_subscription_state_position = () => result.ShouldEqual(subscription_state.Position); + It should_return_the_subscription_state_position = () => result.ShouldEqual(subscription_state.Position.StreamPosition); } \ No newline at end of file diff --git a/Specifications/EventHorizon/Consumer/Processing/for_StreamProcessor/given/all_dependencies.cs b/Specifications/EventHorizon/Consumer/Processing/for_StreamProcessor/given/all_dependencies.cs index 3660f39f5..15576cdd1 100644 --- a/Specifications/EventHorizon/Consumer/Processing/for_StreamProcessor/given/all_dependencies.cs +++ b/Specifications/EventHorizon/Consumer/Processing/for_StreamProcessor/given/all_dependencies.cs @@ -21,7 +21,7 @@ public class all_dependencies protected static Mock event_processor; protected static EventsFromEventHorizonFetcher event_fetcher; protected static AsyncProducerConsumerQueue event_queue; - protected static Mock stream_processor_states; + protected static Mock stream_processor_states; protected static StreamProcessor stream_processor; protected static ExecutionContext execution_context; @@ -40,7 +40,7 @@ public class all_dependencies event_processor = new Mock(); event_queue = new AsyncProducerConsumerQueue(); event_fetcher = new EventsFromEventHorizonFetcher(event_queue, Mock.Of()); - stream_processor_states = new Mock(); + stream_processor_states = new Mock(); stream_processor = new StreamProcessor( subscription_id, execution_context, diff --git a/Specifications/EventHorizon/Consumer/for_Subscription/given/all_dependencies.cs b/Specifications/EventHorizon/Consumer/for_Subscription/given/all_dependencies.cs index 3a951de9f..2b3220967 100644 --- a/Specifications/EventHorizon/Consumer/for_Subscription/given/all_dependencies.cs +++ b/Specifications/EventHorizon/Consumer/for_Subscription/given/all_dependencies.cs @@ -12,7 +12,6 @@ using Dolittle.Runtime.Events.Store.Streams; using Dolittle.Runtime.Events.Store.EventHorizon; using Microservices; -using Microsoft.Extensions.Logging.Abstractions; using Nito.AsyncEx; using Polly; using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; diff --git a/Specifications/EventHorizon/UnBreaking/for_ProtobufExtensions/when_setting_partition_id/and_partition_id_is_not_guid.cs b/Specifications/EventHorizon/UnBreaking/for_ProtobufExtensions/when_setting_partition_id/and_partition_id_is_not_guid.cs index 27572ae87..d618df78d 100644 --- a/Specifications/EventHorizon/UnBreaking/for_ProtobufExtensions/when_setting_partition_id/and_partition_id_is_not_guid.cs +++ b/Specifications/EventHorizon/UnBreaking/for_ProtobufExtensions/when_setting_partition_id/and_partition_id_is_not_guid.cs @@ -1,10 +1,8 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; using Dolittle.Runtime.EventHorizon.Contracts; using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Protobuf; using Machine.Specifications; namespace Dolittle.Runtime.EventHorizon.UnBreaking.for_ProtobufExtensions.when_setting_partition_id; diff --git a/Specifications/Events.Processing.Tests/Events.Processing.Tests.csproj b/Specifications/Events.Processing.Tests/Events.Processing.Tests.csproj new file mode 100644 index 000000000..daa3b96b6 --- /dev/null +++ b/Specifications/Events.Processing.Tests/Events.Processing.Tests.csproj @@ -0,0 +1,33 @@ + + + + + + + net7.0 + enable + enable + + false + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/Specifications/Events.Processing.Tests/Fixtures/cluster_fixture.cs b/Specifications/Events.Processing.Tests/Fixtures/cluster_fixture.cs new file mode 100644 index 000000000..fe5d1aef8 --- /dev/null +++ b/Specifications/Events.Processing.Tests/Fixtures/cluster_fixture.cs @@ -0,0 +1,17 @@ +// // Copyright (c) Dolittle. All rights reserved. +// // Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// using Dolittle.Runtime.Events.Store.Streams; +// +// namespace Events.Processing.Tests.Fixtures; +// +// public class cluster_fixture +// { +// public IServiceProvider CreateFixture() +// { +// +// } +// +// public IStreamProcessorStates StreamProcessorStates { get; } +// +// } \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/Fixtures/committed_events.cs b/Specifications/Events.Processing.Tests/Fixtures/committed_events.cs new file mode 100644 index 000000000..fee09f791 --- /dev/null +++ b/Specifications/Events.Processing.Tests/Fixtures/committed_events.cs @@ -0,0 +1,23 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Artifacts; +using Dolittle.Runtime.Events.Store; + +namespace Dolittle.Runtime.Events.Processing; + +public static class committed_events +{ + public static CommittedEvent single() => single(EventLogSequenceNumber.Initial); + + public static CommittedEvent single(EventLogSequenceNumber event_log_sequence_number) => single(event_log_sequence_number, "{\"something\":42}"); + public static CommittedEvent single(string content) => single(EventLogSequenceNumber.Initial, content); + public static CommittedEvent single(EventLogSequenceNumber event_log_sequence_number, string content) => new( + event_log_sequence_number, + DateTimeOffset.UtcNow, + "event source///", + execution_contexts.create(), + new Artifact(ArtifactId.New(), ArtifactGeneration.First), + false, + content); +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/Fixtures/execution_contexts.cs b/Specifications/Events.Processing.Tests/Fixtures/execution_contexts.cs new file mode 100644 index 000000000..d15b5e9f1 --- /dev/null +++ b/Specifications/Events.Processing.Tests/Fixtures/execution_contexts.cs @@ -0,0 +1,24 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Globalization; +using Dolittle.Runtime.Execution; +using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; +using Version = Dolittle.Runtime.Domain.Platform.Version; + +namespace Dolittle.Runtime.Events.Store; + +public static class execution_contexts +{ + public static ExecutionContext create() => + new( + Guid.NewGuid(), + Guid.NewGuid(), + Version.NotSet, + "", + Guid.NewGuid(), + ActivitySpanId.CreateRandom(), + Claims.Empty, + CultureInfo.InvariantCulture); +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/PartitionedProcessorTests.cs b/Specifications/Events.Processing.Tests/PartitionedProcessorTests.cs new file mode 100644 index 000000000..2f55ad486 --- /dev/null +++ b/Specifications/Events.Processing.Tests/PartitionedProcessorTests.cs @@ -0,0 +1,56 @@ +// using System.Threading.Channels; +// using Dolittle.Runtime.Events.Processing; +// using Dolittle.Runtime.Events.Processing.EventHandlers.Actors; +// using Dolittle.Runtime.Events.Processing.Streams; +// using Dolittle.Runtime.Events.Store; +// using Dolittle.Runtime.Events.Store.Streams; +// using Moq; +// +// namespace Events.Processing.Tests; +// +// public class PartitionedProcessorTests +// { +// const string reason = "some reason"; +// PartitionId first_partition_id = "first partition"; +// PartitionId second_partition_id = "second partition"; +// StreamEvent first_event; +// StreamEvent second_event; +// StreamEvent third_event; +// StreamEvent fourth_event; +// Mock event_processor; +// private Channel event_stream; +// +// PartitionedProcessorTests() +// { +// first_event = new StreamEvent(committed_events.single(), StreamPosition.Start, Guid.NewGuid(), first_partition_id, true); +// second_event = new StreamEvent(committed_events.single(), 1u, Guid.NewGuid(), second_partition_id, true); +// third_event = new StreamEvent(committed_events.single(), 2u, Guid.NewGuid(), second_partition_id, true); +// fourth_event = new StreamEvent(committed_events.single(), 3u, Guid.NewGuid(), second_partition_id, true); +// event_processor = new Mock(); +// event_processor +// .Setup(_ => _.Process(Moq.It.IsAny(), second_partition_id, Moq.It.IsAny(), Moq.It.IsAny())) +// .Returns(Task.FromResult(SuccessfulProcessing.Instance)); +// event_processor +// .Setup(_ => _.Process(Moq.It.IsAny(), first_partition_id, Moq.It.IsAny(), Moq.It.IsAny())) +// .Returns(Task.FromResult(new FailedProcessing(reason, true, TimeSpan.FromMilliseconds(1)))); +// event_stream = Channel.CreateUnbounded(); +// var writer = event_stream.Writer; +// writer.WriteAsync(first_event).GetAwaiter().GetResult(); +// writer.WriteAsync(second_event).GetAwaiter().GetResult(); +// writer.WriteAsync(third_event).GetAwaiter().GetResult(); +// writer.WriteAsync(fourth_event).GetAwaiter().GetResult(); +// } +// +// static readonly EventProcessorId eventProcessorId = new EventProcessorId(Guid.NewGuid()); +// static readonly StreamProcessorId streamProcessorId = new StreamProcessorId(ScopeId.Default, eventProcessorId.Value, eventProcessorId.Value); +// +// +// [Fact] +// public void ShouldRetryFailedEvents() +// { +// // new PartitionedProcessor(streamProcessorId, event_processor.Object, ) +// +// +// +// } +// } \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/Usings.cs b/Specifications/Events.Processing.Tests/Usings.cs new file mode 100644 index 000000000..8c927eb74 --- /dev/null +++ b/Specifications/Events.Processing.Tests/Usings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/concurrent/ConcurrentPartitionedProcessorTests.cs b/Specifications/Events.Processing.Tests/concurrent/ConcurrentPartitionedProcessorTests.cs new file mode 100644 index 000000000..5f170e7ce --- /dev/null +++ b/Specifications/Events.Processing.Tests/concurrent/ConcurrentPartitionedProcessorTests.cs @@ -0,0 +1,190 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; +using System.Diagnostics; +using System.Globalization; +using System.Threading.Channels; +using Dolittle.Runtime.Domain.Platform; +using Dolittle.Runtime.Domain.Tenancy; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; +using Dolittle.Runtime.Execution; +using FluentAssertions; +using Proto; +using static Dolittle.Runtime.Events.Processing.EventHandlers.Actors.ConcurrentPartitionedProcessor; +using Artifact = Dolittle.Runtime.Artifacts.Artifact; +using Environment = Dolittle.Runtime.Domain.Platform.Environment; +using Version = Dolittle.Runtime.Domain.Platform.Version; + +namespace Events.Processing.Tests.concurrent; + +public class ConcurrentPartitionedProcessorTests +{ + private static readonly Dolittle.Runtime.Execution.ExecutionContext ExecutionContext = new(MicroserviceId.New(), TenantId.Development, Version.NotSet, + Environment.Development, CorrelationId.Empty, ActivitySpanId.CreateRandom(), Claims.Empty, CultureInfo.CurrentCulture); + + private static readonly CommittedEvent SomeEvent = new( + EventLogSequenceNumber.Initial, + DateTimeOffset.Now, + "some-partition", + ExecutionContext, + Artifact.New(), false, "{}"); + + private static readonly StreamEvent FirstStreamEvent = new(SomeEvent, StreamPosition.Start, StreamId.EventLog, new PartitionId("some-partition"), true); + + [Fact] + public async Task ShouldReturnNoActionWhenNoInput() + { + var state = new State(StreamProcessorState.New, NoWaitingReceipts()); + + using var cancellationTokenSource = new CancellationTokenSource(100); + await state.Invoking(async _ => { await WaitForNextAction(ChannelWithoutEvents(), state, cancellationTokenSource!.Token); }).Should() + .ThrowAsync(); + } + + [Fact] + public async Task ShouldReturnProcessNextEventWhenMessageAvailable() + { + var state = new State(StreamProcessorState.New, NoWaitingReceipts()); + + var (nextAction, _) = await WaitForNextAction(ChannelWithEvent(), state, CancellationTokens.FromSeconds(1)); + + nextAction.Should().Be(NextAction.ProcessNextEvent); + } + + [Fact] + public async Task ShouldReturnRetryFailedActionWhenRetryAvailable() + { + var state = new State(FailingProcessorStateWithRetryIn(TimeSpan.Zero, "failing-partition"), + NoWaitingReceipts()); + + var (nextAction, _) = await WaitForNextAction(ChannelWithEvent(), state, CancellationTokens.FromSeconds(1)); + + nextAction.Should().Be(NextAction.ProcessFailedEvent); + } + + [Fact] + public async Task ShouldReturnProcessNextWhenRetryNotAvailableYet() + { + var state = new State(FailingProcessorStateWithRetryIn(TimeSpan.FromSeconds(1), "failing-partition"), + NoWaitingReceipts()); + + var (nextAction, _) = await WaitForNextAction(ChannelWithEvent(), state, CancellationTokens.FromSeconds(1)); + + nextAction.Should().Be(NextAction.ProcessNextEvent); + } + + [Fact] + public async Task ShouldReturnProcessNextWhenWaitingForReceipt() + { + var state = new State(FailingProcessorStateWithRetryIn(TimeSpan.FromSeconds(1), "failing-partition"), + NoWaitingReceipts()); + + var (nextAction, _) = await WaitForNextAction(ChannelWithEvent(), state, CancellationTokens.FromSeconds(1)); + + nextAction.Should().Be(NextAction.ProcessNextEvent); + } + + [Fact] + public async Task ShouldReturnReceiveResultWhenReceiptReady() + { + var state = new State(FailingProcessorStateWithRetryIn(TimeSpan.FromSeconds(1), "failing-partition"), + WithWaitingReceipt()); + + var (nextAction, _) = await WaitForNextAction(ChannelWithEvent(), state, CancellationTokens.FromSeconds(1)); + + nextAction.Should().Be(NextAction.ReceiveResult); + } + + [Fact] + public async Task ShouldReturnReceiveResultWhenActiveRequestsCompletedAndNoRetryAndNoMessageAvailable() + { + var state = new State(StreamProcessorState.New, WithWaitingReceipt()); + + var (nextAction, partitionId) = await WaitForNextAction(ChannelWithoutEvents(), state, CancellationTokens.FromSeconds(1)); + + nextAction.Should().Be(NextAction.ReceiveResult); + partitionId.Should().BeNull(); + } + + [Fact] + public async Task ShouldReturnProcessFailedEventWhenRetryTimeExpiredAndMessageAvailable() + { + var state = new State(FailingProcessorStateWithRetryIn(TimeSpan.Zero, "failing-partition"), NoWaitingReceipts()); + + var (nextAction, partitionId) = await WaitForNextAction(ChannelWithEvent(), state, CancellationTokens.FromSeconds(1)); + + nextAction.Should().Be(NextAction.ProcessFailedEvent); + partitionId.Should().Be(new PartitionId("failing-partition")); + } + + [Fact] + public async Task ShouldReturnProcessNextEventWhenRetryTimeNotExpiredAndMessageAvailable() + { + var state = new State(FailingProcessorStateWithRetryIn(TimeSpan.FromSeconds(1), "failing-partition"), NoWaitingReceipts()); + + var (nextAction, partitionId) = await WaitForNextAction(ChannelWithEvent(), state, CancellationTokens.FromSeconds(2)); + + nextAction.Should().Be(NextAction.ProcessNextEvent); + partitionId.Should().BeNull(); + } + + [Fact] + public async Task ShouldReturnProcessNextEventWhenRetryTimeNotExpiredAndMessageAvailableAfterDelay() + { + var state = new State(FailingProcessorStateWithRetryIn(TimeSpan.FromSeconds(1), "failing-partition"), NoWaitingReceipts()); + + var (nextAction, partitionId) = + await WaitForNextAction(ChannelWithEventAvailableAfter(TimeSpan.FromMicroseconds(50)), state, CancellationTokens.FromSeconds(2)); + + nextAction.Should().Be(NextAction.ProcessNextEvent); + partitionId.Should().BeNull(); + } + + private static ActiveRequests NoWaitingReceipts() => new(5); + + private static ActiveRequests WithWaitingReceipt() + { + var activeRequests = new ActiveRequests(5); + var completedResult = Task.FromResult(current => current); + activeRequests.Add("waiting-partition", completedResult); + return activeRequests; + } + + private static StreamProcessorState FailingProcessorStateWithRetryIn(TimeSpan timeSpan, PartitionId partitionId) + { + var processingPosition = new ProcessingPosition(5, 5); + var failingPosition = new ProcessingPosition(3, 3); + + var retryTime = DateTimeOffset.UtcNow.Add(timeSpan); + + var failingPartition = new FailingPartitionState(failingPosition, retryTime, "#reasons", 1, DateTimeOffset.Now - TimeSpan.FromSeconds(10)); + + return new StreamProcessorState(processingPosition, new Dictionary() + { + { partitionId, failingPartition } + }.ToImmutableDictionary(), DateTimeOffset.UtcNow); + } + + private static Channel ChannelWithEvent() + { + var events = Channel.CreateBounded(100); + events.Writer.WriteAsync(FirstStreamEvent).GetAwaiter().GetResult(); + return events; + } + + private static Channel ChannelWithEventAvailableAfter(TimeSpan timeSpan) + { + var events = Channel.CreateBounded(100); + Task.Run(async () => + { + await Task.Delay(timeSpan); + events.Writer.WriteAsync(FirstStreamEvent).GetAwaiter().GetResult(); + }); + return events; + } + + private static Channel ChannelWithoutEvents() => Channel.CreateBounded(100); +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/linear/with_failing_state/given/failing_state.cs b/Specifications/Events.Processing.Tests/linear/with_failing_state/given/failing_state.cs new file mode 100644 index 000000000..815ec041a --- /dev/null +++ b/Specifications/Events.Processing.Tests/linear/with_failing_state/given/failing_state.cs @@ -0,0 +1,36 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store.Streams; + +namespace Events.Processing.Tests.given; + +public class failing_state +{ + protected const string partition = "partition"; + protected const string failure_reason = "Something went wrong"; + protected const string failure_reason_2 = "Something went wrong again"; + protected static readonly DateTimeOffset original_failure_time = DateTimeOffset.UtcNow - TimeSpan.FromSeconds(20); + protected static readonly DateTimeOffset original_retry_time = DateTimeOffset.UtcNow - TimeSpan.FromSeconds(1); + protected static readonly DateTimeOffset last_successful_processing = DateTimeOffset.UtcNow - TimeSpan.FromSeconds(10); + protected static readonly DateTimeOffset now = DateTimeOffset.UtcNow; + + protected static readonly TimeSpan retry_timeout = TimeSpan.FromSeconds(5); + protected static readonly DateTimeOffset after_retry = now.Add(retry_timeout); + + protected static readonly ProcessingPosition CurrentProcessingPosition = new(22, 42); + protected static readonly ProcessingPosition NextProcessingPosition = CurrentProcessingPosition.IncrementWithStream(); + + protected static readonly StreamEvent current_event = new( + committed_events.single(CurrentProcessingPosition.EventLogPosition), + CurrentProcessingPosition.StreamPosition, + StreamId.EventLog, + partition, + true); + + + protected static readonly StreamProcessorState before_state = new(CurrentProcessingPosition, failure_reason, original_retry_time, 1, + last_successful_processing, true); +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/linear/with_failing_state/when_failing_again.cs b/Specifications/Events.Processing.Tests/linear/with_failing_state/when_failing_again.cs new file mode 100644 index 000000000..3d61177b2 --- /dev/null +++ b/Specifications/Events.Processing.Tests/linear/with_failing_state/when_failing_again.cs @@ -0,0 +1,56 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams; +using Events.Processing.Tests.given; +using FluentAssertions; + +namespace Events.Processing.Tests.with_failing_state; + +public class when_failing_again : failing_state +{ + readonly StreamProcessorState after_state; + + public when_failing_again() + { + after_state = before_state.WithResult(new FailedProcessing(failure_reason_2, true, retry_timeout), current_event, now); + } + + + [Fact] + public void ShouldNotIncrementStreamPositionOnFailedRetry() + { + after_state.Position.Should().BeEquivalentTo(CurrentProcessingPosition); + } + + [Fact] + public void ShouldUpdateProcessingAttempts() + { + after_state.ProcessingAttempts.Should().Be(before_state.ProcessingAttempts + 1); + } + + [Fact] + public void ShouldSetRetryTimeout() + { + after_state.RetryTime.Should().Be(after_retry); + } + + [Fact] + public void ShouldUpdateFailureReason() + { + after_state.FailureReason.Should().Be(failure_reason_2); + } + + [Fact] + public void ShouldBeFailing() + { + after_state.IsFailing.Should().BeTrue(); + } + + [Fact] + public void ShouldNotUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(last_successful_processing); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/linear/with_failing_state/when_retry_successful.cs b/Specifications/Events.Processing.Tests/linear/with_failing_state/when_retry_successful.cs new file mode 100644 index 000000000..a7083b92e --- /dev/null +++ b/Specifications/Events.Processing.Tests/linear/with_failing_state/when_retry_successful.cs @@ -0,0 +1,50 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams; +using Events.Processing.Tests.given; +using FluentAssertions; + +namespace Events.Processing.Tests.with_failing_state; + +public class when_retry_successful : failing_state +{ + readonly StreamProcessorState after_state; + + public when_retry_successful() + { + after_state = before_state.WithResult(SuccessfulProcessing.Instance, current_event, now); + } + + [Fact] + public void ShouldIncrementStreamPositionOnSuccessfulRetry() + { + after_state.Position.Should().BeEquivalentTo(NextProcessingPosition); + } + + + [Fact] + public void ShouldNotBeFailing() + { + after_state.IsFailing.Should().BeFalse(); + } + + [Fact] + public void ShouldClearReason() + { + after_state.FailureReason.Should().BeNullOrEmpty(); + } + + [Fact] + public void ShouldClearProcessingAttempts() + { + after_state.ProcessingAttempts.Should().Be(0); + } + + [Fact] + public void ShouldUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(now); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/linear/with_failing_state/without_retries/when_failing_again.cs b/Specifications/Events.Processing.Tests/linear/with_failing_state/without_retries/when_failing_again.cs new file mode 100644 index 000000000..e5c4530f1 --- /dev/null +++ b/Specifications/Events.Processing.Tests/linear/with_failing_state/without_retries/when_failing_again.cs @@ -0,0 +1,62 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams; +using Events.Processing.Tests.given; +using FluentAssertions; + +namespace Events.Processing.Tests.with_failing_state.without_retries; + +public class when_failing_again : failing_state +{ + readonly StreamProcessorState after_state; + + public when_failing_again() + { + after_state = before_state.WithResult(new FailedProcessing(failure_reason_2), current_event, now); + } + + + [Fact] + public void ShouldNotIncrementStreamPositionOnFailedRetry() + { + after_state.Position.Should().BeEquivalentTo(CurrentProcessingPosition); + } + + [Fact] + public void ShouldUpdateProcessingAttempts() + { + after_state.ProcessingAttempts.Should().Be(before_state.ProcessingAttempts + 1); + } + + [Fact] + public void ShouldSetRetryTimeout() + { + after_state.RetryTime.Should().Be(DateTimeOffset.MaxValue); + } + + [Fact] + public void ShouldBeNotRetryable() + { + after_state.TryGetTimespanToRetry(out _).Should().BeFalse(); + } + + [Fact] + public void ShouldSetFailureReason() + { + after_state.FailureReason.Should().Be(failure_reason_2); + } + + [Fact] + public void ShouldBeFailing() + { + after_state.IsFailing.Should().BeTrue(); + } + + [Fact] + public void ShouldNotUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(last_successful_processing); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/linear/with_nonfailing_state/given/non_failing_state.cs b/Specifications/Events.Processing.Tests/linear/with_nonfailing_state/given/non_failing_state.cs new file mode 100644 index 000000000..09d57231c --- /dev/null +++ b/Specifications/Events.Processing.Tests/linear/with_nonfailing_state/given/non_failing_state.cs @@ -0,0 +1,30 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store.Streams; + +namespace Events.Processing.Tests.given; + +public class non_failing_state +{ + protected const string partition = "partition"; + protected static readonly DateTimeOffset last_successful_processing = DateTimeOffset.UtcNow - TimeSpan.FromSeconds(10); + protected static readonly DateTimeOffset now = DateTimeOffset.UtcNow; + + protected static readonly TimeSpan retry_timeout = TimeSpan.FromSeconds(5); + protected static readonly DateTimeOffset after_timeout = now.Add(retry_timeout); + + protected static readonly ProcessingPosition CurrentProcessingPosition = new(22, 42); + protected static readonly ProcessingPosition NextProcessingPosition = CurrentProcessingPosition.IncrementWithStream(); + + protected static readonly StreamEvent Evt = new( + committed_events.single(CurrentProcessingPosition.EventLogPosition), + CurrentProcessingPosition.StreamPosition, + StreamId.EventLog, + partition, + true); + + protected static readonly StreamProcessorState before_state = new StreamProcessorState(CurrentProcessingPosition, last_successful_processing); +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/linear/with_nonfailing_state/when_successfully_processed.cs b/Specifications/Events.Processing.Tests/linear/with_nonfailing_state/when_successfully_processed.cs new file mode 100644 index 000000000..4e874f59f --- /dev/null +++ b/Specifications/Events.Processing.Tests/linear/with_nonfailing_state/when_successfully_processed.cs @@ -0,0 +1,49 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams; +using FluentAssertions; + +namespace Events.Processing.Tests; + +public class when_successfully_processed: given.non_failing_state +{ + readonly StreamProcessorState after_state; + + public when_successfully_processed() + { + after_state = before_state.WithResult(SuccessfulProcessing.Instance, Evt, now); + } + + [Fact] + public void ShouldIncrementStreamPositionOnSuccessfulRetry() + { + after_state.Position.Should().BeEquivalentTo(NextProcessingPosition); + } + + + [Fact] + public void ShouldNotBeFailing() + { + after_state.IsFailing.Should().BeFalse(); + } + + [Fact] + public void ShouldClearReason() + { + after_state.FailureReason.Should().BeNullOrEmpty(); + } + + [Fact] + public void ShouldClearProcessingAttempts() + { + after_state.ProcessingAttempts.Should().Be(0); + } + + [Fact] + public void ShouldUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(now); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/linear/with_nonfailing_state/with_new_failure_processed.cs b/Specifications/Events.Processing.Tests/linear/with_nonfailing_state/with_new_failure_processed.cs new file mode 100644 index 000000000..cebdf7e06 --- /dev/null +++ b/Specifications/Events.Processing.Tests/linear/with_nonfailing_state/with_new_failure_processed.cs @@ -0,0 +1,55 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams; +using FluentAssertions; + +namespace Events.Processing.Tests; + +public class with_new_failure_processed : given.non_failing_state +{ + private const string failure_reason = "Something went wrong"; + readonly StreamProcessorState after_state; + + public with_new_failure_processed() + { + after_state = before_state.WithResult(new FailedProcessing(failure_reason, true, retry_timeout), Evt, now); + } + + [Fact] + public void ShouldNotIncrementStreamPositionOnFailedRetry() + { + after_state.Position.Should().BeEquivalentTo(CurrentProcessingPosition); + } + + [Fact] + public void ShouldSetProcessingAttempts() + { + after_state.ProcessingAttempts.Should().Be(1); + } + + [Fact] + public void ShouldSetRetryTimeout() + { + after_state.RetryTime.Should().Be(after_timeout); + } + + [Fact] + public void ShouldSetFailureReason() + { + after_state.FailureReason.Should().Be(failure_reason); + } + + [Fact] + public void ShouldBeFailing() + { + after_state.IsFailing.Should().BeTrue(); + } + + [Fact] + public void ShouldNotUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(last_successful_processing); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/linear/with_nonfailing_state/without_retries/with_new_failure_processed.cs b/Specifications/Events.Processing.Tests/linear/with_nonfailing_state/without_retries/with_new_failure_processed.cs new file mode 100644 index 000000000..ac2c37a68 --- /dev/null +++ b/Specifications/Events.Processing.Tests/linear/with_nonfailing_state/without_retries/with_new_failure_processed.cs @@ -0,0 +1,62 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams; +using FluentAssertions; + +namespace Events.Processing.Tests.with_failing_state.without_retries; + +public class with_new_failure_processed : given.non_failing_state +{ + private const string failure_reason = "Something went wrong"; + readonly StreamProcessorState after_state; + + public with_new_failure_processed() + { + after_state = before_state.WithResult(new FailedProcessing(failure_reason), Evt, now); + } + + + [Fact] + public void ShouldNotIncrementStreamPositionOnFailedRetry() + { + after_state.Position.Should().BeEquivalentTo(CurrentProcessingPosition); + } + + [Fact] + public void ShouldSetProcessingAttempts() + { + after_state.ProcessingAttempts.Should().Be(1); + } + + [Fact] + public void ShouldSetRetryTimeout() + { + after_state.RetryTime.Should().Be(DateTimeOffset.MaxValue); + } + + [Fact] + public void ShouldBeNotRetryable() + { + after_state.TryGetTimespanToRetry(out _).Should().BeFalse(); + } + + [Fact] + public void ShouldSetFailureReason() + { + after_state.FailureReason.Should().Be(failure_reason); + } + + [Fact] + public void ShouldBeFailing() + { + after_state.IsFailing.Should().BeTrue(); + } + + [Fact] + public void ShouldNotUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(last_successful_processing); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/partitioned/with_failing_state/given/state_with_failing_partititons.cs b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/given/state_with_failing_partititons.cs new file mode 100644 index 000000000..e1321c932 --- /dev/null +++ b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/given/state_with_failing_partititons.cs @@ -0,0 +1,55 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Immutable; +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Events.Store.Streams; + +namespace Events.Processing.Tests.Partitioned.given; + +public class state_with_failing_partititons +{ + protected const string partition = "partition"; + protected const string partition2 = "partition2"; + protected const string partition3 = "partition3"; + protected const string failure_reason = "Something went wrong"; + protected const string failure_reason_2 = "Something went wrong again"; + protected static readonly DateTimeOffset original_failure_time = DateTimeOffset.UtcNow - TimeSpan.FromSeconds(20); + protected static readonly DateTimeOffset failure_time2 = DateTimeOffset.UtcNow - TimeSpan.FromSeconds(15); + protected static readonly DateTimeOffset last_successful_processing = DateTimeOffset.UtcNow - TimeSpan.FromSeconds(10); + protected static readonly DateTimeOffset now = DateTimeOffset.UtcNow; + + protected static readonly TimeSpan retry_timeout = TimeSpan.FromSeconds(5); + protected static readonly DateTimeOffset after_retry = now.Add(retry_timeout); + + protected static readonly ProcessingPosition FailingProcessingPosition = new(18, 36); + protected static readonly ProcessingPosition FailingProcessingPosition2 = new(20, 38); + protected static readonly ProcessingPosition CurrentProcessingPosition = new(22, 42); + protected static readonly ProcessingPosition NextProcessingPosition = CurrentProcessingPosition.IncrementWithStream(); + + protected static readonly StreamEvent retry_event = new( + committed_events.single(FailingProcessingPosition.EventLogPosition), + FailingProcessingPosition.StreamPosition, + StreamId.EventLog, + partition, + true); + + protected static readonly StreamEvent next_event = new( + committed_events.single(CurrentProcessingPosition.EventLogPosition), + CurrentProcessingPosition.StreamPosition, + StreamId.EventLog, + partition3, + true); + + protected static readonly ImmutableDictionary failing_partitions = new Dictionary() + { + { partition, new FailingPartitionState(FailingProcessingPosition, after_retry, failure_reason, 1, original_failure_time) }, + { partition2, new FailingPartitionState(FailingProcessingPosition2, after_retry, failure_reason_2, 1, failure_time2) } + }.ToImmutableDictionary(); + + protected static readonly StreamProcessorState before_state = new StreamProcessorState(CurrentProcessingPosition, failing_partitions, last_successful_processing); + + + +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/partitioned/with_failing_state/when_failing_again.cs b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/when_failing_again.cs new file mode 100644 index 000000000..d7ee11672 --- /dev/null +++ b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/when_failing_again.cs @@ -0,0 +1,54 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Events.Processing.Tests.Partitioned.given; +using FluentAssertions; + +namespace Events.Processing.Tests.Partitioned.with_failing_state; + +public class when_failing_again : state_with_failing_partititons +{ + const string reason = "Something went wrong"; + readonly StreamProcessorState after_state; + + + public when_failing_again() + { + after_state = before_state.WithResult(new FailedProcessing(reason, true, retry_timeout), retry_event, now); + } + + + [Fact] + public void ShouldNotIncrementStreamPositionOnFailedRetry() + { + after_state.Position.Should().BeEquivalentTo(CurrentProcessingPosition); + } + + [Fact] + public void ShouldPopulateFailingPartitions() + { + after_state.FailingPartitions.Should().HaveCount(2); + } + + [Fact] + public void ShouldUpdateCorrectFailingPartition() + { + var failing_partition = after_state.FailingPartitions[partition]; + failing_partition.Should().BeEquivalentTo(new FailingPartitionState(retry_event.CurrentProcessingPosition, after_retry, reason, 2, now)); + } + + [Fact] + public void ShouldNotUpdateOtherFailingPartition() + { + var failing_partition = after_state.FailingPartitions[partition2]; + failing_partition.Should().BeSameAs(failing_partitions[partition2]); + } + + [Fact] + public void ShouldNotUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(last_successful_processing); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/partitioned/with_failing_state/when_failing_on_next_event.cs b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/when_failing_on_next_event.cs new file mode 100644 index 000000000..01acbb406 --- /dev/null +++ b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/when_failing_on_next_event.cs @@ -0,0 +1,48 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Events.Processing.Tests.Partitioned.given; +using FluentAssertions; + +namespace Events.Processing.Tests.Partitioned.with_failing_state; + +public class when_failing_on_next_event: state_with_failing_partititons +{ + private const string reason = "Something went wrong"; + readonly StreamProcessorState after_state; + + public when_failing_on_next_event() + { + after_state = before_state.WithResult(new FailedProcessing(reason, true, retry_timeout), next_event, now); + } + + + [Fact] + public void ShouldIncrementStreamPositionFailedProcessing() + { + after_state.Position.Should().BeEquivalentTo(CurrentProcessingPosition.IncrementWithStream()); + } + + [Fact] + public void ShouldHaveAndAdditionalFailedPartition() + { + after_state.FailingPartitions.Should().HaveCount(before_state.FailingPartitions.Count + 1); + + } + + [Fact] + public void ShouldAddNewFailedPartition() + { + var failing_partition = after_state.FailingPartitions[partition3]; + failing_partition.Should().BeEquivalentTo(new FailingPartitionState(next_event.CurrentProcessingPosition, after_retry, reason, 1, now)); + + } + + [Fact] + public void ShouldNotUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(last_successful_processing); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/partitioned/with_failing_state/when_processing_next_event.cs b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/when_processing_next_event.cs new file mode 100644 index 000000000..02118683a --- /dev/null +++ b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/when_processing_next_event.cs @@ -0,0 +1,40 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Events.Processing.Tests.Partitioned.given; +using FluentAssertions; + +namespace Events.Processing.Tests.Partitioned.with_failing_state; + +public class when_processing_next_event: state_with_failing_partititons +{ + private const string reason = "Something went wrong"; + readonly StreamProcessorState after_state; + + public when_processing_next_event() + { + after_state = before_state.WithResult(SuccessfulProcessing.Instance, next_event, now); + } + + + [Fact] + public void ShouldIncrementStreamPositionOnSuccessFulProcessing() + { + after_state.Position.Should().BeEquivalentTo(CurrentProcessingPosition.IncrementWithStream()); + } + + [Fact] + public void ShouldNotChangeFailingPartitions() + { + after_state.FailingPartitions.Should().BeSameAs(before_state.FailingPartitions); + + } + + [Fact] + public void ShouldUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(now); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/partitioned/with_failing_state/when_retry_successful.cs b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/when_retry_successful.cs new file mode 100644 index 000000000..a37d8fae2 --- /dev/null +++ b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/when_retry_successful.cs @@ -0,0 +1,54 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Events.Processing.Tests.Partitioned.given; +using FluentAssertions; + +namespace Events.Processing.Tests.Partitioned.with_failing_state; + +public class when_retry_successful: state_with_failing_partititons +{ + private const string reason = "Something went wrong"; + readonly StreamProcessorState after_state; + private DateTimeOffset later = now.AddSeconds(10); + + public when_retry_successful() + { + after_state = before_state.WithResult(SuccessfulProcessing.Instance, retry_event, now); + } + + + [Fact] + public void ShouldNotIncrementStreamPositionOnSuccessfulRetry() + { + after_state.Position.Should().BeEquivalentTo(CurrentProcessingPosition); + } + + [Fact] + public void ShouldPopulateFailingPartitions() + { + after_state.FailingPartitions.Should().HaveCount(2); + } + + [Fact] + public void ShouldUpdateCorrectFailingPartition() + { + var failing_partition = after_state.FailingPartitions[partition]; + failing_partition.Should().BeEquivalentTo(new FailingPartitionState(retry_event.NextProcessingPosition, now, "behind", 0, original_failure_time)); + } + + [Fact] + public void ShouldNotUpdateOtherFailingPartition() + { + var failing_partition = after_state.FailingPartitions[partition2]; + failing_partition.Should().BeSameAs(failing_partitions[partition2]); + } + + [Fact] + public void ShouldUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(now); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/partitioned/with_failing_state/when_skipping_event.cs b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/when_skipping_event.cs new file mode 100644 index 000000000..edf6e52a6 --- /dev/null +++ b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/when_skipping_event.cs @@ -0,0 +1,55 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Events.Processing.Tests.Partitioned.given; +using FluentAssertions; + +namespace Events.Processing.Tests.Partitioned.with_failing_state; + +public class when_skipping_event : state_with_failing_partititons +{ + const string reason = "Something went wrong"; + readonly StreamProcessorState after_state; + + + public when_skipping_event() + { + after_state = before_state.WithResult(SkippedProcessing.Instance, next_event, now); + } + + + [Fact] + public void ShouldIncrementStreamPositionOnSkip() + { + after_state.Position.Should().BeEquivalentTo(NextProcessingPosition); + } + + [Fact] + public void ShouldPopulateFailingPartitions() + { + after_state.FailingPartitions.Should().HaveCount(2); + } + + [Fact] + public void ShouldNotUpdateFailingPartition() + { + var existing = before_state.FailingPartitions[partition]; + var failing_partition = after_state.FailingPartitions[partition]; + failing_partition.Should().BeSameAs(existing); + } + + [Fact] + public void ShouldNotUpdateOtherFailingPartition() + { + var failing_partition = after_state.FailingPartitions[partition2]; + failing_partition.Should().BeSameAs(failing_partitions[partition2]); + } + + [Fact] + public void ShouldNotUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(last_successful_processing); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/partitioned/with_failing_state/without_retries/when_failing_again.cs b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/without_retries/when_failing_again.cs new file mode 100644 index 000000000..145fa424f --- /dev/null +++ b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/without_retries/when_failing_again.cs @@ -0,0 +1,54 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Events.Processing.Tests.Partitioned.given; +using FluentAssertions; + +namespace Events.Processing.Tests.Partitioned.with_failing_state.without_retries; + +public class when_failing_again: state_with_failing_partititons +{ + private const string reason = "Something went wrong"; + readonly StreamProcessorState after_state; + private DateTimeOffset later = now.AddSeconds(10); + + public when_failing_again() + { + after_state = before_state.WithResult(new FailedProcessing(reason), retry_event, now); + } + + + [Fact] + public void ShouldNotIncrementStreamPositionOnFailedRetry() + { + after_state.Position.Should().BeEquivalentTo(CurrentProcessingPosition); + } + + [Fact] + public void ShouldPopulateFailingPartitions() + { + after_state.FailingPartitions.Should().HaveCount(2); + } + + [Fact] + public void ShouldUpdateCorrectFailingPartition() + { + var failing_partition = after_state.FailingPartitions[partition]; + failing_partition.Should().BeEquivalentTo(new FailingPartitionState(retry_event.CurrentProcessingPosition, DateTimeOffset.MaxValue, reason, 2, now)); + } + + [Fact] + public void ShouldNotUpdateOtherFailingPartition() + { + var failing_partition = after_state.FailingPartitions[partition2]; + failing_partition.Should().BeSameAs(failing_partitions[partition2]); + } + + [Fact] + public void ShouldNotUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(last_successful_processing); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/partitioned/with_failing_state/without_retries/when_failing_on_next_event.cs b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/without_retries/when_failing_on_next_event.cs new file mode 100644 index 000000000..7568f0538 --- /dev/null +++ b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/without_retries/when_failing_on_next_event.cs @@ -0,0 +1,48 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Events.Processing.Tests.Partitioned.given; +using FluentAssertions; + +namespace Events.Processing.Tests.Partitioned.with_failing_state.without_retries; + +public class when_failing_on_next_event: state_with_failing_partititons +{ + private const string reason = "Something went wrong"; + readonly StreamProcessorState after_state; + + public when_failing_on_next_event() + { + after_state = before_state.WithResult(new FailedProcessing(reason), next_event, now); + } + + + [Fact] + public void ShouldIncrementStreamPositionFailedProcessing() + { + after_state.Position.Should().BeEquivalentTo(CurrentProcessingPosition.IncrementWithStream()); + } + + [Fact] + public void ShouldHaveAndAdditionalFailedPartition() + { + after_state.FailingPartitions.Should().HaveCount(before_state.FailingPartitions.Count + 1); + + } + + [Fact] + public void ShouldAddNewFailedPartition() + { + var failing_partition = after_state.FailingPartitions[partition3]; + failing_partition.Should().BeEquivalentTo(new FailingPartitionState(next_event.CurrentProcessingPosition, DateTimeOffset.MaxValue, reason, 1, now)); + + } + + [Fact] + public void ShouldNotUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(last_successful_processing); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/partitioned/with_failing_state/without_retries/when_processing_next_event.cs b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/without_retries/when_processing_next_event.cs new file mode 100644 index 000000000..911dd14b4 --- /dev/null +++ b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/without_retries/when_processing_next_event.cs @@ -0,0 +1,40 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Events.Processing.Tests.Partitioned.given; +using FluentAssertions; + +namespace Events.Processing.Tests.Partitioned.with_failing_state.without_retries; + +public class when_processing_next_event: state_with_failing_partititons +{ + private const string reason = "Something went wrong"; + readonly StreamProcessorState after_state; + + public when_processing_next_event() + { + after_state = before_state.WithResult(SuccessfulProcessing.Instance, next_event, now); + } + + + [Fact] + public void ShouldIncrementStreamPositionOnSuccessFulProcessing() + { + after_state.Position.Should().BeEquivalentTo(CurrentProcessingPosition.IncrementWithStream()); + } + + [Fact] + public void ShouldNotChangeFailingPartitions() + { + after_state.FailingPartitions.Should().BeSameAs(before_state.FailingPartitions); + + } + + [Fact] + public void ShouldUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(now); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/partitioned/with_failing_state/without_retries/when_retry_successful.cs b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/without_retries/when_retry_successful.cs new file mode 100644 index 000000000..4c1aa7bc3 --- /dev/null +++ b/Specifications/Events.Processing.Tests/partitioned/with_failing_state/without_retries/when_retry_successful.cs @@ -0,0 +1,54 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Events.Processing.Tests.Partitioned.given; +using FluentAssertions; + +namespace Events.Processing.Tests.Partitioned.with_failing_state.without_retries; + +public class when_retry_successful: state_with_failing_partititons +{ + private const string reason = "Something went wrong"; + readonly StreamProcessorState after_state; + private DateTimeOffset later = now.AddSeconds(10); + + public when_retry_successful() + { + after_state = before_state.WithResult(SuccessfulProcessing.Instance, retry_event, now); + } + + + [Fact] + public void ShouldNotIncrementStreamPositionOnSuccessfulRetry() + { + after_state.Position.Should().BeEquivalentTo(CurrentProcessingPosition); + } + + [Fact] + public void ShouldPopulateFailingPartitions() + { + after_state.FailingPartitions.Should().HaveCount(2); + } + + [Fact] + public void ShouldUpdateCorrectFailingPartition() + { + var failing_partition = after_state.FailingPartitions[partition]; + failing_partition.Should().BeEquivalentTo(new FailingPartitionState(retry_event.NextProcessingPosition, now, "behind", 0, original_failure_time)); + } + + [Fact] + public void ShouldNotUpdateOtherFailingPartition() + { + var failing_partition = after_state.FailingPartitions[partition2]; + failing_partition.Should().BeSameAs(failing_partitions[partition2]); + } + + [Fact] + public void ShouldUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(now); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/partitioned/with_nonfailing_state/given/non_failing_state.cs b/Specifications/Events.Processing.Tests/partitioned/with_nonfailing_state/given/non_failing_state.cs new file mode 100644 index 000000000..7ab0f5d5f --- /dev/null +++ b/Specifications/Events.Processing.Tests/partitioned/with_nonfailing_state/given/non_failing_state.cs @@ -0,0 +1,29 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Events.Store.Streams; + +namespace Events.Processing.Tests.Partitioned.given; + +public class non_failing_state +{ + protected const string partition = "partition"; + protected static readonly DateTimeOffset last_successful_processing = DateTimeOffset.UtcNow - TimeSpan.FromSeconds(10); + protected static readonly DateTimeOffset now = DateTimeOffset.UtcNow; + + protected static readonly TimeSpan retry_timeout = TimeSpan.FromSeconds(5); + protected static readonly DateTimeOffset after_timeout = now.Add(retry_timeout); + + protected static readonly ProcessingPosition CurrentProcessingPosition = new(22, 42); + + protected static readonly StreamEvent Evt = new( + committed_events.single(CurrentProcessingPosition.EventLogPosition), + CurrentProcessingPosition.StreamPosition, + StreamId.EventLog, + partition, + true); + + protected static readonly StreamProcessorState before_state = new StreamProcessorState(CurrentProcessingPosition, last_successful_processing); +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/partitioned/with_nonfailing_state/when_successfully_processed.cs b/Specifications/Events.Processing.Tests/partitioned/with_nonfailing_state/when_successfully_processed.cs new file mode 100644 index 000000000..57b797f52 --- /dev/null +++ b/Specifications/Events.Processing.Tests/partitioned/with_nonfailing_state/when_successfully_processed.cs @@ -0,0 +1,37 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using FluentAssertions; + +namespace Events.Processing.Tests.Partitioned; + +public class when_successfully_processed: given.non_failing_state +{ + readonly StreamProcessorState after_state; + + public when_successfully_processed() + { + after_state = before_state.WithResult(SuccessfulProcessing.Instance, Evt, now); + } + + + [Fact] + public void ShouldIncrementStreamPositionOnSuccessFulProcessing() + { + after_state.Position.Should().BeEquivalentTo(CurrentProcessingPosition.IncrementWithStream()); + } + + [Fact] + public void ShouldNotPopulateFailingPartitions() + { + after_state.FailingPartitions.Should().BeEmpty(); + } + + [Fact] + public void ShouldUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(now); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/partitioned/with_nonfailing_state/with_new_failure_processed.cs b/Specifications/Events.Processing.Tests/partitioned/with_nonfailing_state/with_new_failure_processed.cs new file mode 100644 index 000000000..9b4e6d3dc --- /dev/null +++ b/Specifications/Events.Processing.Tests/partitioned/with_nonfailing_state/with_new_failure_processed.cs @@ -0,0 +1,45 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using FluentAssertions; + +namespace Events.Processing.Tests.Partitioned; + +public class with_new_failure_processed : given.non_failing_state +{ + private const string reason = "Something went wrong"; + readonly StreamProcessorState after_state; + + public with_new_failure_processed() + { + after_state = before_state.WithResult(new FailedProcessing(reason, true, retry_timeout), Evt, now); + } + + + [Fact] + public void ShouldIncrementStreamPositionOnFailedProcessing() + { + after_state.Position.Should().BeEquivalentTo(CurrentProcessingPosition.IncrementWithStream()); + } + + [Fact] + public void ShouldPopulateFailingPartitions() + { + after_state.FailingPartitions.Should().HaveCount(1); + } + + [Fact] + public void ShouldPopulateCorrectFailingPartition() + { + var failing_partition = after_state.FailingPartitions[partition]; + failing_partition.Should().BeEquivalentTo(new FailingPartitionState(Evt.CurrentProcessingPosition, after_timeout, reason, 1, now)); + } + + [Fact] + public void ShouldNotUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(last_successful_processing); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/partitioned/with_nonfailing_state/without_retries/with_new_failure_processed.cs b/Specifications/Events.Processing.Tests/partitioned/with_nonfailing_state/without_retries/with_new_failure_processed.cs new file mode 100644 index 000000000..ed7552e27 --- /dev/null +++ b/Specifications/Events.Processing.Tests/partitioned/with_nonfailing_state/without_retries/with_new_failure_processed.cs @@ -0,0 +1,46 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using FluentAssertions; + +namespace Events.Processing.Tests.Partitioned.with_failing_state.without_retries; + +public class with_new_failure_processed : given.non_failing_state +{ + private const string reason = "Something went wrong"; + readonly StreamProcessorState after_state; + private DateTimeOffset later = now.AddSeconds(10); + + public with_new_failure_processed() + { + after_state = before_state.WithResult(new FailedProcessing(reason), Evt, now); + } + + + [Fact] + public void ShouldIncrementStreamPositionOnFailedProcessing() + { + after_state.Position.Should().BeEquivalentTo(CurrentProcessingPosition.IncrementWithStream()); + } + + [Fact] + public void ShouldPopulateFailingPartitions() + { + after_state.FailingPartitions.Should().HaveCount(1); + } + + [Fact] + public void ShouldPopulateCorrectFailingPartition() + { + var failing_partition = after_state.FailingPartitions[partition]; + failing_partition.Should().BeEquivalentTo(new FailingPartitionState(Evt.CurrentProcessingPosition, DateTimeOffset.MaxValue, reason, 1, now)); + } + + [Fact] + public void ShouldNotUpdateLastSuccessfulTimestamp() + { + after_state.LastSuccessfullyProcessed.Should().Be(last_successful_processing); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/reg/StreamProcessorStateTests.cs b/Specifications/Events.Processing.Tests/reg/StreamProcessorStateTests.cs new file mode 100644 index 000000000..4f240ad77 --- /dev/null +++ b/Specifications/Events.Processing.Tests/reg/StreamProcessorStateTests.cs @@ -0,0 +1,32 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; +using FluentAssertions; + +namespace Events.Processing.Tests.NonPartitioned; + +public class StreamProcessorStateTests +{ + private const string Partition = "partition"; + readonly DateTimeOffset Now = DateTimeOffset.UtcNow; + + static readonly StreamEvent Evt = new( + committed_events.single(EventLogSequenceNumber.Initial), + StreamPosition.Start, + StreamId.EventLog, + Partition, + true); + + [Fact] + public void ShouldIncrementStreamPositionOnSuccessFulProcessing() + { + var before = StreamProcessorState.New; + var afterState = before.WithSuccessfullyProcessed(Evt, Now); + + afterState.Should().BeEquivalentTo(new StreamProcessorState(Evt.NextProcessingPosition, Now)); + } +} \ No newline at end of file diff --git a/Specifications/Events.Processing.Tests/reg/given/NonFailingState.cs b/Specifications/Events.Processing.Tests/reg/given/NonFailingState.cs new file mode 100644 index 000000000..f66fa59f3 --- /dev/null +++ b/Specifications/Events.Processing.Tests/reg/given/NonFailingState.cs @@ -0,0 +1,26 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store.Streams; + +namespace Events.Processing.Tests.NonPartitioned.given; + +public class NonFailingState +{ + protected const string Partition = "partition"; + protected static readonly DateTimeOffset before = DateTimeOffset.UtcNow; + protected static readonly DateTimeOffset now = DateTimeOffset.UtcNow; + + protected static readonly ProcessingPosition CurrentProcessingPosition = new(22, 42); + + protected static readonly StreamEvent Evt = new( + committed_events.single(CurrentProcessingPosition.EventLogPosition), + CurrentProcessingPosition.StreamPosition, + StreamId.EventLog, + Partition, + false); + + protected static readonly StreamProcessorState before_state = new(CurrentProcessingPosition, before); +} \ No newline at end of file diff --git a/Specifications/Events.Processing/EventHandlers/for_EventHandler/given/all_dependencies.cs b/Specifications/Events.Processing/EventHandlers/for_EventHandler/given/all_dependencies.cs index d3f5bedd5..01be39370 100644 --- a/Specifications/Events.Processing/EventHandlers/for_EventHandler/given/all_dependencies.cs +++ b/Specifications/Events.Processing/EventHandlers/for_EventHandler/given/all_dependencies.cs @@ -2,9 +2,11 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Threading; +using Dolittle.Runtime.Actors.Hosting; using Dolittle.Runtime.Artifacts; using Dolittle.Runtime.Domain.Platform; using Dolittle.Runtime.Domain.Tenancy; @@ -13,23 +15,29 @@ using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; using Dolittle.Runtime.Execution; -using Dolittle.Runtime.Protobuf; using Machine.Specifications; using Microsoft.Extensions.Logging; using Moq; using Environment = Dolittle.Runtime.Domain.Platform.Environment; using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; using ReverseCallDispatcherType = Dolittle.Runtime.Services.IReverseCallDispatcher< - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerClientToRuntimeMessage, - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRuntimeToClientMessage, - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRegistrationRequest, - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRegistrationResponse, - Dolittle.Runtime.Events.Processing.Contracts.HandleEventRequest, - Dolittle.Runtime.Events.Processing.Contracts.EventHandlerResponse>; + Dolittle.Runtime.Events.Processing.Contracts.EventHandlerClientToRuntimeMessage, + Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRuntimeToClientMessage, + Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRegistrationRequest, + Dolittle.Runtime.Events.Processing.Contracts.EventHandlerRegistrationResponse, + Dolittle.Runtime.Events.Processing.Contracts.HandleEventRequest, + Dolittle.Runtime.Events.Processing.Contracts.EventHandlerResponse>; using Version = Dolittle.Runtime.Domain.Platform.Version; using static Moq.It; using Dolittle.Runtime.Events.Processing.Contracts; +using Dolittle.Runtime.Events.Processing.EventHandlers.Actors; +using Dolittle.Runtime.Events.Store.Streams.Filters; +using Dolittle.Runtime.Events.Store.Streams.Legacy; +using Dolittle.Runtime.Tenancy; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using Proto; +using Failure = Dolittle.Runtime.Protobuf.Failure; namespace Dolittle.Runtime.Events.Processing.EventHandlers.for_EventHandler.given; @@ -56,10 +64,20 @@ public class all_dependencies protected static ActivitySpanId span_id = ActivitySpanId.CreateRandom(); protected static Claims claims = Claims.Empty; protected static CultureInfo culture_info = CultureInfo.InvariantCulture; + protected static ActorSystem actor_system; + protected static CreateStreamProcessorActorProps create_processor_props; + protected static CreateTenantScopedStreamProcessorProps create_scoped_processor_props; + protected static in_memory_stream_processor_states stream_processor_states; + + protected static ITenants tenants = + new Tenants(Options.Create(new TenantsConfiguration(new Dictionary + { + { tenant, new TenantConfiguration() } + }))); protected static Failure failure; - Establish context = () => + private Establish context = () => { stream_processors = new Mock(MockBehavior.Strict); filter_validation = new Mock(MockBehavior.Strict); @@ -68,7 +86,7 @@ public class all_dependencies reverse_call_dispatcher.Setup( _ => _.Reject(IsAny(), IsAny()) ).Callback((EventHandlerRegistrationResponse e, CancellationToken ct) => failure = e.Failure); - + stream_writer = new Mock(MockBehavior.Strict); metrics_collector = new Mock(); logger_factory = new NullLoggerFactory(); @@ -91,5 +109,63 @@ public class all_dependencies "alias"); factory_for_stream_writer = (tenant_id) => stream_writer.Object; + + actor_system = new ActorSystem(); + + stream_processor_states = new in_memory_stream_processor_states(); + + var eventSubscriber = new Mock(); + var eventLogPositionEnricher = new Mock().Object; + + create_scoped_processor_props = (StreamProcessorId streamProcessorId, + TypeFilterWithEventSourcePartitionDefinition filterDefinition, + IEventProcessor processor, + ExecutionContext executionContext, + ScopedStreamProcessorProcessedEvent onProcessed, + ScopedStreamProcessorFailedToProcessEvent onFailedToProcess, + EventHandlerInfo EventHandlerInfo, + TenantId tenantId) => Props.FromProducer(() => new TenantScopedStreamProcessorActor( + streamProcessorId, + filterDefinition, + processor, + eventSubscriber.Object, + stream_processor_states, + executionContext, + eventLogPositionEnricher, + NullLogger.Instance, + onProcessed, + onFailedToProcess, + Mock.Of(), + EventHandlerInfo, + tenantId, + new ApplicationLifecycleHooks() + )); + + create_processor_props = ( + StreamProcessorId streamProcessorId, + IStreamDefinition streamDefinition, + Func createEventProcessorFor, + StreamProcessorProcessedEvent processedEvent, + StreamProcessorFailedToProcessEvent failedToProcessEvent, + ExecutionContext executionContext, + EventHandlerInfo eventHandlerInfo, + CancellationTokenSource cancellationTokenSource) => Props.FromProducer(() => + { + return new EventHandlerProcessorActor(streamProcessorId, + streamDefinition, + createEventProcessorFor, + executionContext, + new Mock().Object, + processedEvent, + failedToProcessEvent, + NullLogger.Instance, + tenant => create_scoped_processor_props, + tenants, + tenant => stream_processor_states, + eventHandlerInfo, + cancellationTokenSource); + }); }; + + private Cleanup cleanup = () => { _ = actor_system.ShutdownAsync(); }; } \ No newline at end of file diff --git a/Specifications/Events.Processing/EventHandlers/for_EventHandler/given/an_event_handler.cs b/Specifications/Events.Processing/EventHandlers/for_EventHandler/given/an_event_handler.cs index e4fb3a47b..735854d3a 100644 --- a/Specifications/Events.Processing/EventHandlers/for_EventHandler/given/an_event_handler.cs +++ b/Specifications/Events.Processing/EventHandlers/for_EventHandler/given/an_event_handler.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Dolittle.Runtime.Events.Processing.Contracts; +using Dolittle.Runtime.Events.Processing.EventHandlers.Actors; using Dolittle.Runtime.Events.Processing.Filters; using Dolittle.Runtime.Events.Store.Streams.Filters; using Dolittle.Runtime.Protobuf; @@ -13,7 +14,7 @@ namespace Dolittle.Runtime.Events.Processing.EventHandlers.for_EventHandler.give public class an_event_handler : all_dependencies { - protected static EventHandler event_handler; + protected static ActorEventHandler event_handler; protected static Mock> filter_processor; protected static Mock event_processor; @@ -21,18 +22,17 @@ public class an_event_handler : all_dependencies { filter_processor = new Mock>(); event_processor = new Mock(); - event_handler = new EventHandler( - stream_processors.Object, - filter_validation.Object, - stream_definitions.Object, + event_handler = new ActorEventHandler(stream_definitions.Object, arguments, - tenant => filter_processor.Object, tenant => event_processor.Object, cancellation => reverse_call_dispatcher.Object.Accept(new EventHandlerRegistrationResponse(), cancellation), (failure, cancellation) => reverse_call_dispatcher.Object.Reject(new EventHandlerRegistrationResponse{Failure = failure.ToProtobuf()}, cancellation), metrics_collector.Object, - logger_factory.CreateLogger(), + logger_factory.CreateLogger(), execution_context, + actor_system, + tenants, + create_processor_props, cancellation_token ); }; diff --git a/Specifications/Events.Processing/EventHandlers/for_EventHandler/given/an_event_handler_with_non_writeable_target_stream.cs b/Specifications/Events.Processing/EventHandlers/for_EventHandler/given/an_event_handler_with_non_writeable_target_stream.cs index 17d8bf181..b63a6511a 100644 --- a/Specifications/Events.Processing/EventHandlers/for_EventHandler/given/an_event_handler_with_non_writeable_target_stream.cs +++ b/Specifications/Events.Processing/EventHandlers/for_EventHandler/given/an_event_handler_with_non_writeable_target_stream.cs @@ -4,6 +4,7 @@ using System; using Dolittle.Runtime.Artifacts; using Dolittle.Runtime.Events.Processing.Contracts; +using Dolittle.Runtime.Events.Processing.EventHandlers.Actors; using Dolittle.Runtime.Events.Processing.Filters; using Dolittle.Runtime.Events.Store.Streams; using Dolittle.Runtime.Events.Store.Streams.Filters; @@ -16,7 +17,7 @@ namespace Dolittle.Runtime.Events.Processing.EventHandlers.for_EventHandler.give public class an_event_handler_with_non_writeable_target_stream : all_dependencies { - protected static EventHandler event_handler; + protected static ActorEventHandler event_handler; protected static Mock> filter_processor; protected static Mock event_processor; @@ -32,12 +33,8 @@ public class an_event_handler_with_non_writeable_target_stream : all_dependencie filter_processor = new Mock>(); event_processor = new Mock(); - event_handler = new EventHandler( - stream_processors.Object, - filter_validation.Object, - stream_definitions.Object, + event_handler = new ActorEventHandler(stream_definitions.Object, arguments, - tenant => filter_processor.Object, tenant => event_processor.Object, cancellation => reverse_call_dispatcher.Object.Accept(new EventHandlerRegistrationResponse(), cancellation), (failure, cancellation) => reverse_call_dispatcher.Object.Reject(new EventHandlerRegistrationResponse @@ -47,6 +44,10 @@ public class an_event_handler_with_non_writeable_target_stream : all_dependencie metrics_collector.Object, logger_factory.CreateLogger(), execution_context, - cancellation_token); + actor_system, + tenants, + create_processor_props, + cancellation_token + ); }; } \ No newline at end of file diff --git a/Specifications/Events.Processing/EventHandlers/for_EventHandler/when_disposing/and_it_fails_registering_filter_processor.cs b/Specifications/Events.Processing/EventHandlers/for_EventHandler/when_disposing/and_it_fails_registering_filter_processor.cs index a37e1752e..10bc7c94c 100644 --- a/Specifications/Events.Processing/EventHandlers/for_EventHandler/when_disposing/and_it_fails_registering_filter_processor.cs +++ b/Specifications/Events.Processing/EventHandlers/for_EventHandler/when_disposing/and_it_fails_registering_filter_processor.cs @@ -1,58 +1,58 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Threading; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Events.Processing.Contracts; -using Dolittle.Runtime.Events.Store.Streams; -using Machine.Specifications; -using static Moq.It; -using static Moq.Times; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; - -namespace Dolittle.Runtime.Events.Processing.EventHandlers.for_EventHandler; - -public class and_it_fails_registering_filter_processor : given.an_event_handler -{ - Establish context = () => - { - stream_processors.Setup(_ => _ - .TryCreateAndRegister( - event_handler.Scope, - event_handler.EventProcessor, - IsAny(), - IsAny(), - IsAny>(), - IsAny(), - IsAny() - )).Returns(new Exception("")); - }; - - Because of = () => event_handler.RegisterAndStart().GetAwaiter().GetResult(); - - It should_reject = () => reverse_call_dispatcher.Verify(_ => _.Reject(IsAny(), IsAny()), Once); - It should_not_accept_event_handler = () => reverse_call_dispatcher.Verify(_ => _.Accept(IsAny(), IsAny()), Never); - - It should_reject_with_failed_to_register_filter = () => failure.Id.ShouldEqual(EventHandlersFailures.FailedToRegisterEventHandler); - - It should_try_to_register_filter_processor = () => stream_processors.Verify(_ => _ - .TryCreateAndRegister( - event_handler.Scope, - event_handler.EventProcessor, - IsAny(), - IsAny(), - IsAny>(), - IsAny(), - IsAny()), Moq.Times.Once()); - - It should_skip_trying_to_register_event_processor = () => stream_processors.Verify(_ => _ - .TryCreateAndRegister( - event_handler.Scope, - event_handler.EventProcessor, - IsAny(), - event_handler.FilteredStreamDefinition, - IsAny>(), - IsAny(), - IsAny()), Moq.Times.Never()); -} +// // Copyright (c) Dolittle. All rights reserved. +// // Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// using System; +// using System.Threading; +// using Dolittle.Runtime.Domain.Tenancy; +// using Dolittle.Runtime.Events.Processing.Contracts; +// using Dolittle.Runtime.Events.Store.Streams; +// using Machine.Specifications; +// using static Moq.It; +// using static Moq.Times; +// using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; +// +// namespace Dolittle.Runtime.Events.Processing.EventHandlers.for_EventHandler; +// +// public class and_it_fails_registering_filter_processor : given.an_event_handler +// { +// Establish context = () => +// { +// stream_processors.Setup(_ => _ +// .TryCreateAndRegister( +// event_handler.Scope, +// event_handler.EventProcessor, +// IsAny(), +// IsAny(), +// IsAny>(), +// IsAny(), +// IsAny() +// )).Returns(new Exception("")); +// }; +// +// Because of = () => event_handler.RegisterAndStart().GetAwaiter().GetResult(); +// +// It should_reject = () => reverse_call_dispatcher.Verify(_ => _.Reject(IsAny(), IsAny()), Once); +// It should_not_accept_event_handler = () => reverse_call_dispatcher.Verify(_ => _.Accept(IsAny(), IsAny()), Never); +// +// It should_reject_with_failed_to_register_filter = () => failure.Id.ShouldEqual(EventHandlersFailures.FailedToRegisterEventHandler); +// +// It should_try_to_register_filter_processor = () => stream_processors.Verify(_ => _ +// .TryCreateAndRegister( +// event_handler.Scope, +// event_handler.EventProcessor, +// IsAny(), +// IsAny(), +// IsAny>(), +// IsAny(), +// IsAny()), Moq.Times.Once()); +// +// It should_skip_trying_to_register_event_processor = () => stream_processors.Verify(_ => _ +// .TryCreateAndRegister( +// event_handler.Scope, +// event_handler.EventProcessor, +// IsAny(), +// event_handler.FilteredStreamDefinition, +// IsAny>(), +// IsAny(), +// IsAny()), Moq.Times.Never()); +// } diff --git a/Specifications/Events.Processing/EventHandlers/for_EventHandler/when_disposing/and_it_is_given_a_non_writeable_stream.cs b/Specifications/Events.Processing/EventHandlers/for_EventHandler/when_disposing/and_it_is_given_a_non_writeable_stream.cs index bb10856d0..8aefee723 100644 --- a/Specifications/Events.Processing/EventHandlers/for_EventHandler/when_disposing/and_it_is_given_a_non_writeable_stream.cs +++ b/Specifications/Events.Processing/EventHandlers/for_EventHandler/when_disposing/and_it_is_given_a_non_writeable_stream.cs @@ -1,34 +1,34 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Threading; -using Dolittle.Runtime.Domain.Tenancy; -using Dolittle.Runtime.Events.Processing.Contracts; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Machine.Specifications; -using static Moq.It; -using static Moq.Times; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; - -namespace Dolittle.Runtime.Events.Processing.EventHandlers.for_EventHandler; - -public class and_it_is_given_a_non_writeable_stream : given.an_event_handler_with_non_writeable_target_stream -{ - Because of = () => event_handler.RegisterAndStart().GetAwaiter().GetResult(); - - - It should_reject = () => reverse_call_dispatcher.Verify(_ => _.Reject(IsAny(), IsAny()), Once); - It should_not_accept_event_handler = () => reverse_call_dispatcher.Verify(_ => _.Accept(IsAny(), IsAny()), Never); - It should_reject_with_cannot_register_event_handler_on_writeable_stream = () => failure.Id.ShouldEqual(EventHandlersFailures.CannotRegisterEventHandlerOnNonWriteableStream); - It should_not_register_any_stream_processors = () => stream_processors.Verify(_ => _ - .TryCreateAndRegister( - IsAny(), - IsAny(), - IsAny(), - IsAny(), - IsAny>(), - IsAny(), - IsAny()), Moq.Times.Never()); -} +// // Copyright (c) Dolittle. All rights reserved. +// // Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// using System; +// using System.Threading; +// using Dolittle.Runtime.Domain.Tenancy; +// using Dolittle.Runtime.Events.Processing.Contracts; +// using Dolittle.Runtime.Events.Store; +// using Dolittle.Runtime.Events.Store.Streams; +// using Machine.Specifications; +// using static Moq.It; +// using static Moq.Times; +// using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; +// +// namespace Dolittle.Runtime.Events.Processing.EventHandlers.for_EventHandler; +// +// public class and_it_is_given_a_non_writeable_stream : given.an_event_handler_with_non_writeable_target_stream +// { +// Because of = () => event_handler.RegisterAndStart().GetAwaiter().GetResult(); +// +// +// It should_reject = () => reverse_call_dispatcher.Verify(_ => _.Reject(IsAny(), IsAny()), Once); +// It should_not_accept_event_handler = () => reverse_call_dispatcher.Verify(_ => _.Accept(IsAny(), IsAny()), Never); +// It should_reject_with_cannot_register_event_handler_on_writeable_stream = () => failure.Id.ShouldEqual(EventHandlersFailures.CannotRegisterEventHandlerOnNonWriteableStream); +// It should_not_register_any_stream_processors = () => stream_processors.Verify(_ => _ +// .TryCreateAndRegister( +// IsAny(), +// IsAny(), +// IsAny(), +// IsAny(), +// IsAny>(), +// IsAny(), +// IsAny()), Moq.Times.Never()); +// } diff --git a/Specifications/Events.Processing/Events.Processing.csproj b/Specifications/Events.Processing/Events.Processing.csproj index 95a3eacbd..243a49ff3 100755 --- a/Specifications/Events.Processing/Events.Processing.csproj +++ b/Specifications/Events.Processing/Events.Processing.csproj @@ -4,10 +4,14 @@ Dolittle.Runtime.Events.Processing.Specs - + + + - + + + diff --git a/Specifications/Events.Processing/Filters/for_AbstractFilterProcessor/when_processing/and_writing_filtered_event_fails.cs b/Specifications/Events.Processing/Filters/for_AbstractFilterProcessor/when_processing/and_writing_filtered_event_fails.cs index b17ce3940..c5b3b85d0 100644 --- a/Specifications/Events.Processing/Filters/for_AbstractFilterProcessor/when_processing/and_writing_filtered_event_fails.cs +++ b/Specifications/Events.Processing/Filters/for_AbstractFilterProcessor/when_processing/and_writing_filtered_event_fails.cs @@ -9,7 +9,6 @@ using Moq; using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; using It = Machine.Specifications.It; -using ReturnsExtensions = Moq.ReturnsExtensions; namespace Dolittle.Runtime.Events.Processing.Filters.for_AbstractFilterProcessor.when_processing; diff --git a/Specifications/Events.Processing/Filters/for_FilterValidators/given/all_dependencies.cs b/Specifications/Events.Processing/Filters/for_FilterValidators/given/all_dependencies.cs index 5da7d8dc8..1012049d7 100644 --- a/Specifications/Events.Processing/Filters/for_FilterValidators/given/all_dependencies.cs +++ b/Specifications/Events.Processing/Filters/for_FilterValidators/given/all_dependencies.cs @@ -2,12 +2,9 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; - -using System.Globalization; using System.Threading; using System.Threading.Tasks; using Autofac; -using Autofac.Core; using Autofac.Extensions.DependencyInjection; using Dolittle.Runtime.Artifacts; using Dolittle.Runtime.Domain.Tenancy; @@ -15,15 +12,10 @@ using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; using Dolittle.Runtime.Events.Store.Streams.Filters; -using Dolittle.Runtime.Execution; using Dolittle.Runtime.Rudimentary; -using Dolittle.Runtime.Tenancy.Contracts; using Machine.Specifications; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Moq; -using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; -using Version = Dolittle.Runtime.Domain.Platform.Version; namespace Dolittle.Runtime.Events.Processing.Filters.for_FilterValidators.given; @@ -42,7 +34,7 @@ public class all_dependencies protected static StreamProcessorState stream_processor_state; // protected static Mock container; - protected static Mock stream_processor_state_repository; + protected static Mock stream_processor_state_repository; protected static Mock filter_definitions; protected static Mock definition_comparer; protected static CancellationToken cancellation_token; @@ -77,9 +69,9 @@ public class all_dependencies filter_validator = mocks.Create>(); - stream_processor_state = new StreamProcessorState(10, DateTimeOffset.Now); + stream_processor_state = new StreamProcessorState(10, 13, DateTimeOffset.Now); - stream_processor_state_repository = mocks.Create(); + stream_processor_state_repository = mocks.Create(); stream_processor_state_repository .Setup(_ => _.TryGetFor(stream_processor_id, cancellation_token)) .Returns(Task.FromResult(Try.Succeeded(stream_processor_state))); diff --git a/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_definition_has_changed_but_filter_has_not_processed_any_events.cs b/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_definition_has_changed_but_filter_has_not_processed_any_events.cs index a31eae687..3298d7260 100644 --- a/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_definition_has_changed_but_filter_has_not_processed_any_events.cs +++ b/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_definition_has_changed_but_filter_has_not_processed_any_events.cs @@ -1,37 +1,36 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading.Tasks; -using Autofac; -using Dolittle.Runtime.Rudimentary; -using Dolittle.Runtime.Events.Processing.Streams; -using Machine.Specifications; -using Dolittle.Runtime.Events.Store.Streams.Filters; -using Dolittle.Runtime.Events.Store.Streams; -using Microsoft.Extensions.DependencyInjection; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_FilterValidators.when_validating; - -public class and_definition_has_changed_but_filter_has_not_processed_any_events : given.all_dependencies -{ - - Establish context = () => - { - stream_processor_state_repository - .Setup(_ => _.TryGetFor(stream_processor_id, cancellation_token)) - .Returns(Task.FromResult(Try.Succeeded(StreamProcessorState.New))); - - filter_definitions - .Setup(_ => _.TryGetFromStream(scope_id, filter_target_stream, cancellation_token)) - .Returns(Task.FromResult(Try.Succeeded(different_filter_definition))); - - filter_validator - .Setup(_ => _.Validate(filter_definition, filter_processor, StreamPosition.Start, cancellation_token)) - .Returns(Task.FromResult(FilterValidationResult.Failed("something went wrong"))); - }; - - static FilterValidationResult result; - Because of = () => result = filter_validators_with_services(_ => _.RegisterInstance(filter_validator.Object)).Validate(filter_processor, cancellation_token).GetAwaiter().GetResult(); - - It should_not_fail_validation = () => result.Success.ShouldBeTrue(); -} \ No newline at end of file +// // Copyright (c) Dolittle. All rights reserved. +// // Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// using System.Threading.Tasks; +// using Autofac; +// using Dolittle.Runtime.Rudimentary; +// using Dolittle.Runtime.Events.Processing.Streams; +// using Machine.Specifications; +// using Dolittle.Runtime.Events.Store.Streams.Filters; +// using Dolittle.Runtime.Events.Store.Streams; +// +// namespace Dolittle.Runtime.Events.Processing.Filters.for_FilterValidators.when_validating; +// +// public class and_definition_has_changed_but_filter_has_not_processed_any_events : given.all_dependencies +// { +// +// Establish context = () => +// { +// stream_processor_state_repository +// .Setup(_ => _.TryGetFor(stream_processor_id, cancellation_token)) +// .Returns(Task.FromResult(Try.Succeeded(StreamProcessorState.New))); +// +// filter_definitions +// .Setup(_ => _.TryGetFromStream(scope_id, filter_target_stream, cancellation_token)) +// .Returns(Task.FromResult(Try.Succeeded(different_filter_definition))); +// +// filter_validator +// .Setup(_ => _.Validate(filter_definition, filter_processor, StreamPosition.Start, cancellation_token)) +// .Returns(Task.FromResult(FilterValidationResult.Failed("something went wrong"))); +// }; +// +// static FilterValidationResult result; +// Because of = () => result = filter_validators_with_services(_ => _.RegisterInstance(filter_validator.Object)).Validate(filter_processor, cancellation_token).GetAwaiter().GetResult(); +// +// It should_not_fail_validation = () => result.Success.ShouldBeTrue(); +// } \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_everything_is_fine.cs b/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_everything_is_fine.cs index bdcc41461..039c4e829 100644 --- a/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_everything_is_fine.cs +++ b/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_everything_is_fine.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using Autofac; using Machine.Specifications; -using Microsoft.Extensions.DependencyInjection; namespace Dolittle.Runtime.Events.Processing.Filters.for_FilterValidators.when_validating; diff --git a/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_filter_definitions_are_not_equal.cs b/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_filter_definitions_are_not_equal.cs index 8b0f6a8d4..0a38193ac 100644 --- a/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_filter_definitions_are_not_equal.cs +++ b/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_filter_definitions_are_not_equal.cs @@ -3,7 +3,6 @@ using Autofac; using Machine.Specifications; -using Microsoft.Extensions.DependencyInjection; namespace Dolittle.Runtime.Events.Processing.Filters.for_FilterValidators.when_validating; diff --git a/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_getting_the_persisted_filter_definition_fails.cs b/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_getting_the_persisted_filter_definition_fails.cs index 90fb8106f..3ab96ce12 100644 --- a/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_getting_the_persisted_filter_definition_fails.cs +++ b/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_getting_the_persisted_filter_definition_fails.cs @@ -7,7 +7,6 @@ using Dolittle.Runtime.Events.Store.Streams.Filters; using Dolittle.Runtime.Rudimentary; using Machine.Specifications; -using Microsoft.Extensions.DependencyInjection; namespace Dolittle.Runtime.Events.Processing.Filters.for_FilterValidators.when_validating; diff --git a/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_getting_the_stream_processor_state_fails.cs b/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_getting_the_stream_processor_state_fails.cs index 377ace01a..cdb2ab83e 100644 --- a/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_getting_the_stream_processor_state_fails.cs +++ b/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_getting_the_stream_processor_state_fails.cs @@ -7,7 +7,6 @@ using Dolittle.Runtime.Rudimentary; using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; -using Microsoft.Extensions.DependencyInjection; namespace Dolittle.Runtime.Events.Processing.Filters.for_FilterValidators.when_validating; diff --git a/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_the_filter_definition_type_has_changed.cs b/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_the_filter_definition_type_has_changed.cs index dace3b68c..987a5f573 100644 --- a/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_the_filter_definition_type_has_changed.cs +++ b/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_the_filter_definition_type_has_changed.cs @@ -6,7 +6,6 @@ using Dolittle.Runtime.Events.Store.Streams.Filters; using Dolittle.Runtime.Rudimentary; using Machine.Specifications; -using Microsoft.Extensions.DependencyInjection; namespace Dolittle.Runtime.Events.Processing.Filters.for_FilterValidators.when_validating; diff --git a/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_there_is_no_persisted_filter_definition.cs b/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_there_is_no_persisted_filter_definition.cs index 8e07664a0..33fdc5559 100644 --- a/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_there_is_no_persisted_filter_definition.cs +++ b/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_there_is_no_persisted_filter_definition.cs @@ -7,7 +7,6 @@ using Dolittle.Runtime.Events.Store.Streams.Filters; using Dolittle.Runtime.Rudimentary; using Machine.Specifications; -using Microsoft.Extensions.DependencyInjection; namespace Dolittle.Runtime.Events.Processing.Filters.for_FilterValidators.when_validating; diff --git a/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_there_is_no_persisted_stream_processor_state.cs b/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_there_is_no_persisted_stream_processor_state.cs index 39d4f8963..f4646ea25 100644 --- a/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_there_is_no_persisted_stream_processor_state.cs +++ b/Specifications/Events.Processing/Filters/for_FilterValidators/when_validating/and_there_is_no_persisted_stream_processor_state.cs @@ -6,7 +6,6 @@ using Dolittle.Runtime.Rudimentary; using Machine.Specifications; using Dolittle.Runtime.Events.Store.Streams; -using Microsoft.Extensions.DependencyInjection; namespace Dolittle.Runtime.Events.Processing.Filters.for_FilterValidators.when_validating; diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/given/all_dependencies.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/given/all_dependencies.cs deleted file mode 100644 index 0b3944ebe..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/given/all_dependencies.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Artifacts; -using Dolittle.Runtime.Events.Processing.Streams; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Events.Store.Streams.Filters; -using Machine.Specifications; -using Moq; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingEventTypes.given; - -public class all_dependencies -{ - protected static StreamId source_stream; - protected static StreamId target_stream; - protected static EventProcessorId event_processor_id; - protected static ScopeId scope_id; - protected static StreamProcessorId stream_processor_id; - protected static Artifact filter_definition_event_type_one; - protected static Artifact filter_definition_event_type_two; - protected static Artifact filter_definition_event_type_three; - protected static Artifact event_type_four; - protected static TypeFilterWithEventSourcePartitionDefinition filter_definition; - protected static IFilterProcessor filter_processor; - - protected static Mock types_fetcher; - protected static Mock events_fetchers; - protected static ValidateFilterByComparingEventTypes validator; - protected static CancellationToken cancellation_token; - - Establish context = () => - { - var mocks = new MockRepository(MockBehavior.Strict); - - source_stream = StreamId.EventLog; - target_stream = Guid.Parse("b057ebb0-23db-4180-9d77-e2c957dc20f2"); - event_processor_id = target_stream.Value; - scope_id = Guid.Parse("4d55b68b-4925-4a59-8a1e-0e8228637014"); - stream_processor_id = new StreamProcessorId(scope_id, event_processor_id, source_stream); - filter_definition_event_type_one = new Artifact("32d9142b-44fd-474c-bb1c-b302c4f9ea15", ArtifactGeneration.First); - filter_definition_event_type_two = new Artifact("091160c2-3a0b-4d51-b81c-1a31a8f49037", ArtifactGeneration.First); - filter_definition_event_type_three = new Artifact("738ac8bc-bc23-42c3-86df-89a0d7d221d3", ArtifactGeneration.First); - event_type_four = new Artifact("3a8816c9-f6ee-487e-85af-4199fcfe210c", ArtifactGeneration.First); - filter_definition = new TypeFilterWithEventSourcePartitionDefinition( - source_stream, - target_stream, - new[] { - filter_definition_event_type_one.Id, - filter_definition_event_type_two.Id, - filter_definition_event_type_three.Id, - }, - false); - - var filter_processor_mock = mocks.Create>(); - filter_processor_mock.SetupGet(_ => _.Definition).Returns(filter_definition); - filter_processor_mock.SetupGet(_ => _.Identifier).Returns(event_processor_id); - filter_processor_mock.SetupGet(_ => _.Scope).Returns(scope_id); - filter_processor = filter_processor_mock.Object; - - types_fetcher = mocks.Create(); - - events_fetchers = mocks.Create(); - events_fetchers - .Setup(_ => _.GetTypeFetcherFor(scope_id, new EventLogStreamDefinition(), cancellation_token)) - .Returns(Task.FromResult(types_fetcher.Object)); - - validator = new ValidateFilterByComparingEventTypes(events_fetchers.Object); - - cancellation_token = CancellationToken.None; - }; -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_fetching_the_event_types_from_the_stream_fails.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_fetching_the_event_types_from_the_stream_fails.cs deleted file mode 100644 index 4bc742400..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_fetching_the_event_types_from_the_stream_fails.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Artifacts; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Events.Store.Streams.Filters; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingEventTypes.when_validating; - -public class and_fetching_the_event_types_from_the_stream_fails : given.all_dependencies -{ - protected static TypeFilterWithEventSourcePartitionDefinition new_filter_definition; - - Establish context = () => - { - new_filter_definition = new TypeFilterWithEventSourcePartitionDefinition( - source_stream, - target_stream, - new[] { - filter_definition_event_type_one.Id, - filter_definition_event_type_two.Id, - filter_definition_event_type_three.Id, - event_type_four.Id, - }, - false); - - types_fetcher - .Setup(_ => _.FetchInRange(new StreamPositionRange(0, 42), cancellation_token)) - .Returns(Task.FromException>(new Exception())); - }; - - static FilterValidationResult result; - Because of = () => result = validator.Validate(new_filter_definition, filter_processor, 42, CancellationToken.None).GetAwaiter().GetResult(); - - It should_fail_validation = () => result.Success.ShouldBeFalse(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_filter_definition_has_not_changed.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_filter_definition_has_not_changed.cs deleted file mode 100644 index 8d8611c41..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_filter_definition_has_not_changed.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingEventTypes.when_validating; - -public class and_filter_definition_has_not_changed : given.all_dependencies -{ - static FilterValidationResult result; - Because of = () => result = validator.Validate(filter_definition, filter_processor, 43, cancellation_token).GetAwaiter().GetResult(); - - It should_not_fail_validation = () => result.Success.ShouldBeTrue(); - It should_not_fetch_event_types = () => events_fetchers.VerifyNoOtherCalls(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_getting_the_event_type_fetcher_fails.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_getting_the_event_type_fetcher_fails.cs deleted file mode 100644 index acdaffeae..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_getting_the_event_type_fetcher_fails.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Events.Store.Streams.Filters; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingEventTypes.when_validating; - -public class and_getting_the_event_type_fetcher_fails : given.all_dependencies -{ - protected static TypeFilterWithEventSourcePartitionDefinition new_filter_definition; - - Establish context = () => - { - new_filter_definition = new TypeFilterWithEventSourcePartitionDefinition( - source_stream, - target_stream, - new[] { - filter_definition_event_type_one.Id, - filter_definition_event_type_two.Id, - filter_definition_event_type_three.Id, - event_type_four.Id, - }, - false); - - events_fetchers - .Setup(_ => _.GetTypeFetcherFor(scope_id, new EventLogStreamDefinition(), cancellation_token)) - .Returns(Task.FromException(new Exception())); - }; - - static FilterValidationResult result; - Because of = () => result = validator.Validate(new_filter_definition, filter_processor, 87, CancellationToken.None).GetAwaiter().GetResult(); - - It should_fail_validation = () => result.Success.ShouldBeFalse(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_source_stream_contains_one_of_the_removed_event_types.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_source_stream_contains_one_of_the_removed_event_types.cs deleted file mode 100644 index b6da3dc05..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_source_stream_contains_one_of_the_removed_event_types.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Artifacts; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Events.Store.Streams.Filters; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingEventTypes.when_validating; - -public class and_source_stream_contains_one_of_the_removed_event_types : given.all_dependencies -{ - protected static TypeFilterWithEventSourcePartitionDefinition new_filter_definition; - - Establish context = () => - { - new_filter_definition = new TypeFilterWithEventSourcePartitionDefinition( - source_stream, - target_stream, - new[] { - filter_definition_event_type_one.Id, - }, - false); - - types_fetcher - .Setup(_ => _.FetchInRange(new StreamPositionRange(0, 7), cancellation_token)) - .Returns(Task.FromResult>(new HashSet(new[] { filter_definition_event_type_one, filter_definition_event_type_three, event_type_four }))); - }; - - static FilterValidationResult result; - Because of = () => result = validator.Validate(new_filter_definition, filter_processor, 7, CancellationToken.None).GetAwaiter().GetResult(); - - It should_fail_validation = () => result.Success.ShouldBeFalse(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_source_stream_contains_the_added_event_type.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_source_stream_contains_the_added_event_type.cs deleted file mode 100644 index 644a79586..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_source_stream_contains_the_added_event_type.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Artifacts; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Events.Store.Streams.Filters; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingEventTypes.when_validating; - -public class and_source_stream_contains_the_added_event_type : given.all_dependencies -{ - protected static TypeFilterWithEventSourcePartitionDefinition new_filter_definition; - - Establish context = () => - { - new_filter_definition = new TypeFilterWithEventSourcePartitionDefinition( - source_stream, - target_stream, - new[] { - filter_definition_event_type_one.Id, - filter_definition_event_type_two.Id, - filter_definition_event_type_three.Id, - event_type_four.Id, - }, - false); - - types_fetcher - .Setup(_ => _.FetchInRange(new StreamPositionRange(0, 5), cancellation_token)) - .Returns(Task.FromResult>(new HashSet(new[] { filter_definition_event_type_one, filter_definition_event_type_three, event_type_four }))); - }; - - static FilterValidationResult result; - Because of = () => result = validator.Validate(new_filter_definition, filter_processor, 5, CancellationToken.None).GetAwaiter().GetResult(); - - It should_fail_validation = () => result.Success.ShouldBeFalse(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_source_stream_does_not_contain_the_added_event_type.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_source_stream_does_not_contain_the_added_event_type.cs deleted file mode 100644 index 1900caf75..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_source_stream_does_not_contain_the_added_event_type.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Artifacts; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Events.Store.Streams.Filters; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingEventTypes.when_validating; - -public class and_source_stream_does_not_contain_the_added_event_type : given.all_dependencies -{ - protected static TypeFilterWithEventSourcePartitionDefinition new_filter_definition; - - Establish context = () => - { - new_filter_definition = new TypeFilterWithEventSourcePartitionDefinition( - source_stream, - target_stream, - new[] { - filter_definition_event_type_one.Id, - filter_definition_event_type_two.Id, - filter_definition_event_type_three.Id, - event_type_four.Id, - }, - false); - - types_fetcher - .Setup(_ => _.FetchInRange(new StreamPositionRange(0, 32), cancellation_token)) - .Returns(Task.FromResult>(new HashSet(new[] { filter_definition_event_type_one, filter_definition_event_type_three }))); - }; - - static FilterValidationResult result; - Because of = () => result = validator.Validate(new_filter_definition, filter_processor, 32, CancellationToken.None).GetAwaiter().GetResult(); - - It should_not_fail_validation = () => result.Success.ShouldBeTrue(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_source_stream_does_not_contain_the_removed_event_type.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_source_stream_does_not_contain_the_removed_event_type.cs deleted file mode 100644 index 9feba7890..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingEventTypes/when_validating/and_source_stream_does_not_contain_the_removed_event_type.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Artifacts; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Events.Store.Streams.Filters; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingEventTypes.when_validating; - -public class and_source_stream_does_not_contain_the_removed_event_type : given.all_dependencies -{ - protected static TypeFilterWithEventSourcePartitionDefinition new_filter_definition; - - Establish context = () => - { - new_filter_definition = new TypeFilterWithEventSourcePartitionDefinition( - source_stream, - target_stream, - new[] { - filter_definition_event_type_one.Id, - filter_definition_event_type_two.Id, - }, - false); - - types_fetcher - .Setup(_ => _.FetchInRange(new StreamPositionRange(0, 10), cancellation_token)) - .Returns(Task.FromResult>(new HashSet(new[] { filter_definition_event_type_one, event_type_four }))); - }; - - static FilterValidationResult result; - Because of = () => result = validator.Validate(new_filter_definition, filter_processor, 10, CancellationToken.None).GetAwaiter().GetResult(); - - It should_not_fail_validation = () => result.Success.ShouldBeTrue(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/given/all_dependencies.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/given/all_dependencies.cs deleted file mode 100644 index 7fc5952ab..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/given/all_dependencies.cs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Events.Processing.Streams; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Events.Store.Streams.Filters; -using Machine.Specifications; -using Moq; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingStreams.given; - -public class all_dependencies -{ - protected static StreamId source_stream; - protected static StreamId target_stream; - protected static EventProcessorId event_processor_id; - protected static ScopeId scope_id; - protected static StreamProcessorId stream_processor_id; - protected static Mock> filter_processor; - protected static Mock events_fetchers; - protected static FilterDefinition filter_definition; - protected static ValidateFilterByComparingStreams validator; - protected static Mock events_from_event_log_fetcher; - protected static Mock events_from_filtered_stream_fetcher; - protected static IList events_in_event_log; - protected static IList events_in_filtered_stream; - protected static CancellationToken cancellation_token; - - Establish context = () => - { - var mocks = new MockRepository(MockBehavior.Strict); - - source_stream = Guid.Parse("ad154c87-e62d-4bca-a3b7-dab069220447"); - target_stream = Guid.Parse("e8534fc4-a0be-4782-bdba-df6c22a26901"); - event_processor_id = target_stream.Value; - scope_id = Guid.Parse("411fd266-cfc7-4871-a90d-699cff2c5d2f"); - stream_processor_id = new StreamProcessorId(scope_id, event_processor_id, source_stream); - filter_processor = mocks.Create>(); - filter_definition = new FilterDefinition(source_stream, target_stream, true); - filter_processor.SetupGet(_ => _.Definition).Returns(filter_definition); - filter_processor.SetupGet(_ => _.Identifier).Returns(event_processor_id); - filter_processor.SetupGet(_ => _.Scope).Returns(scope_id); - events_fetchers = mocks.Create(); - validator = new ValidateFilterByComparingStreams(events_fetchers.Object); - events_from_event_log_fetcher = mocks.Create(); - events_from_filtered_stream_fetcher = mocks.Create(); - events_in_event_log = new List(); - events_in_filtered_stream = new List(); - - events_from_event_log_fetcher - .Setup(_ => _.FetchRange(Moq.It.IsAny(), cancellation_token)) - .Returns((range, _) => events_in_event_log.Where(_ => _.Position >= range.From && _.Position < range.From + range.Length).ToAsyncEnumerable()); - events_from_filtered_stream_fetcher - .Setup(_ => _.FetchRange(Moq.It.IsAny(), cancellation_token)) - .Returns((range, _) => events_in_filtered_stream.Where(_ => _.Position >= range.From && _.Position < range.From + range.Length).ToAsyncEnumerable()); - - events_fetchers - .Setup(_ => _.GetRangeFetcherFor(scope_id, new EventLogStreamDefinition(), cancellation_token)) - .Returns(Task.FromResult(events_from_event_log_fetcher.Object)); - events_fetchers - .Setup(_ => _.GetRangeFetcherFor(scope_id, new StreamDefinition(filter_definition), cancellation_token)) - .Returns(Task.FromResult(events_from_filtered_stream_fetcher.Object)); - - cancellation_token = CancellationToken.None; - }; - - protected static void add_event_to_event_log(uint num_events_to_create) - { - var end = events_in_event_log.Count + num_events_to_create; - for (int i = events_in_event_log.Count; i < end; i++) - { - events_in_event_log.Add(new StreamEvent(committed_events.single((uint)i), (uint)i, StreamId.EventLog, PartitionId.None, true)); - } - } - - protected static void add_event_to_filtered_stream(uint num_events_to_create, PartitionId partition = default) - { - var end = events_in_filtered_stream.Count + num_events_to_create; - for (int i = events_in_filtered_stream.Count; i < end; i++) - { - events_in_filtered_stream.Add(new StreamEvent(committed_events.single((uint)i), (uint)i, target_stream, partition == default ? PartitionId.None : partition, true)); - } - } - - protected static void add_event_to_event_log(CommittedEvent @event) - { - var end = events_in_event_log.Count + 1; - for (int i = events_in_event_log.Count; i < end; i++) - { - events_in_event_log.Add(new StreamEvent(@event, (uint)i, StreamId.EventLog, PartitionId.None, true)); - } - } - - protected static void add_event_to_filtered_stream(CommittedEvent @event, PartitionId partition = default) - { - var end = events_in_filtered_stream.Count + 1; - for (int i = events_in_filtered_stream.Count; i < end; i++) - { - events_in_filtered_stream.Add(new StreamEvent(@event, (uint)i, target_stream, partition == default ? PartitionId.None : partition, true)); - } - } -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_both_old_and_new_filter_did_not_include_any_events.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_both_old_and_new_filter_did_not_include_any_events.cs deleted file mode 100644 index 674d34c7e..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_both_old_and_new_filter_did_not_include_any_events.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading.Tasks; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Execution; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingStreams.when_validating; - -public class and_both_old_and_new_filter_did_not_include_any_events : given.all_dependencies -{ - Establish context = () => - { - add_event_to_event_log(1); - filter_processor - .Setup(_ => _.Filter(Moq.It.IsAny(), Moq.It.IsAny(), event_processor_id, Moq.It.IsAny(), cancellation_token)) - .Returns(Task.FromResult(new SuccessfulFiltering(false))); - }; - - static FilterValidationResult result; - Because of = () => result = validator.Validate(filter_definition, filter_processor.Object, 1, cancellation_token).GetAwaiter().GetResult(); - - It should_not_fail_validation = () => result.Success.ShouldBeTrue(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_fetching_the_old_stream_events_fails.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_fetching_the_old_stream_events_fails.cs deleted file mode 100644 index 4bf8c1231..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_fetching_the_old_stream_events_fails.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Events.Store.Streams; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingStreams.when_validating; - -public class and_fetching_the_old_stream_events_fails : given.all_dependencies -{ - Establish context = () => - { - events_from_filtered_stream_fetcher - .Setup(_ => _.FetchRange(new StreamPositionRange(StreamPosition.Start, ulong.MaxValue), cancellation_token)) - .Throws(new Exception()); - }; - - static FilterValidationResult result; - Because of = () => result = validator.Validate(filter_definition, filter_processor.Object, 10, CancellationToken.None).GetAwaiter().GetResult(); - - It should_fail_validation = () => result.Success.ShouldBeFalse(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_fetching_the_source_stream_events_fails.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_fetching_the_source_stream_events_fails.cs deleted file mode 100644 index d751a3f1c..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_fetching_the_source_stream_events_fails.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Events.Store.Streams; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingStreams.when_validating; - -public class and_fetching_the_source_stream_events_fails : given.all_dependencies -{ - Establish context = () => - { - events_from_event_log_fetcher - .Setup(_ => _.FetchRange(new StreamPositionRange(StreamPosition.Start, 10), cancellation_token)) - .Throws(new Exception()); - }; - - static FilterValidationResult result; - Because of = () => result = validator.Validate(filter_definition, filter_processor.Object, 10, CancellationToken.None).GetAwaiter().GetResult(); - - It should_fail_validation = () => result.Success.ShouldBeFalse(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_filter_has_not_processed_any_events.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_filter_has_not_processed_any_events.cs deleted file mode 100644 index 598bf73cc..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_filter_has_not_processed_any_events.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingStreams.when_validating; - -public class and_filter_has_not_processed_any_events : given.all_dependencies -{ - static FilterValidationResult result; - - Because of = () => result = validator.Validate(filter_definition, filter_processor.Object, 0, CancellationToken.None).GetAwaiter().GetResult(); - It should_not_fail_validation = () => result.Success.ShouldBeTrue(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_filtering_fails.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_filtering_fails.cs deleted file mode 100644 index cfe2cfc77..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_filtering_fails.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading.Tasks; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Execution; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingStreams.when_validating; - -public class and_filtering_fails : given.all_dependencies -{ - Establish context = () => - { - var @event = committed_events.single(0); - add_event_to_event_log(@event); - filter_processor - .Setup(_ => _.Filter(Moq.It.IsAny(), Moq.It.IsAny(), event_processor_id, Moq.It.IsAny(), cancellation_token)) - .Returns(Task.FromResult(new FailedFiltering("something went wrong"))); - }; - - static FilterValidationResult result; - Because of = () => result = validator.Validate(filter_definition, filter_processor.Object, 1, cancellation_token).GetAwaiter().GetResult(); - - It should_fail_validation = () => result.Success.ShouldBeFalse(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_getting_the_source_stream_event_fetcher_fails.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_getting_the_source_stream_event_fetcher_fails.cs deleted file mode 100644 index bc2446fae..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_getting_the_source_stream_event_fetcher_fails.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Events.Store.Streams; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingStreams.when_validating; - -public class and_getting_the_source_stream_event_fetcher_fails : given.all_dependencies -{ - Establish context = () => - { - events_fetchers - .Setup(_ => _.GetRangeFetcherFor(scope_id, new EventLogStreamDefinition(), cancellation_token)) - .Returns(Task.FromException(new Exception())); - }; - - static FilterValidationResult result; - Because of = () => result = validator.Validate(filter_definition, filter_processor.Object, 10, CancellationToken.None).GetAwaiter().GetResult(); - - It should_fail_validation = () => result.Success.ShouldBeFalse(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_getting_the_target_stream_event_fetcher_fails.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_getting_the_target_stream_event_fetcher_fails.cs deleted file mode 100644 index 6c548b931..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_getting_the_target_stream_event_fetcher_fails.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Threading; -using System.Threading.Tasks; -using Dolittle.Runtime.Events.Store.Streams; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingStreams.when_validating; - -public class and_getting_the_target_stream_event_fetcher_fails : given.all_dependencies -{ - Establish context = () => - { - events_fetchers - .Setup(_ => _.GetRangeFetcherFor(scope_id, new StreamDefinition(filter_definition), cancellation_token)) - .Returns(Task.FromException(new Exception())); - }; - - static FilterValidationResult result; - Because of = () => result = validator.Validate(filter_definition, filter_processor.Object, 10, CancellationToken.None).GetAwaiter().GetResult(); - - It should_fail_validation = () => result.Success.ShouldBeFalse(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_old_and_new_filter_includes_the_same_events.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_old_and_new_filter_includes_the_same_events.cs deleted file mode 100644 index e122efc4b..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_old_and_new_filter_includes_the_same_events.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading.Tasks; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Execution; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingStreams.when_validating; - -public class and_old_and_new_filter_includes_the_same_events : given.all_dependencies -{ - Establish context = () => - { - var @event = committed_events.single(0); - add_event_to_event_log(@event); - add_event_to_filtered_stream(@event); - filter_processor - .Setup(_ => _.Filter(Moq.It.IsAny(), Moq.It.IsAny(), event_processor_id, Moq.It.IsAny(), cancellation_token)) - .Returns(Task.FromResult(new SuccessfulFiltering(true))); - }; - - static FilterValidationResult result; - Because of = () => result = validator.Validate(filter_definition, filter_processor.Object, 1, cancellation_token).GetAwaiter().GetResult(); - - It should_not_fail_validation = () => result.Success.ShouldBeTrue(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_old_and_new_filter_includes_the_same_events_in_different_partitions.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_old_and_new_filter_includes_the_same_events_in_different_partitions.cs deleted file mode 100644 index 6804abd70..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_old_and_new_filter_includes_the_same_events_in_different_partitions.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading.Tasks; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Execution; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingStreams.when_validating; - -public class and_old_and_new_filter_includes_the_same_events_in_different_partitions : given.all_dependencies -{ - Establish context = () => - { - var @event = committed_events.single(0); - add_event_to_event_log(1); - add_event_to_filtered_stream(1, "partition"); - filter_processor - .Setup(_ => _.Filter(Moq.It.IsAny(), Moq.It.IsAny(), event_processor_id, Moq.It.IsAny(), cancellation_token)) - .Returns(Task.FromResult(new SuccessfulFiltering(true, "a partition"))); - }; - - static FilterValidationResult result; - Because of = () => result = validator.Validate(filter_definition, filter_processor.Object, 1, cancellation_token).GetAwaiter().GetResult(); - - It should_fail_validation = () => result.Success.ShouldBeFalse(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_old_and_new_filter_includes_the_same_number_of_different_events.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_old_and_new_filter_includes_the_same_number_of_different_events.cs deleted file mode 100644 index cfd771b64..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_old_and_new_filter_includes_the_same_number_of_different_events.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading.Tasks; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Execution; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingStreams.when_validating; - -public class and_old_and_new_filter_includes_the_same_number_of_different_events : given.all_dependencies -{ - Establish context = () => - { - add_event_to_event_log(committed_events.single(0)); - add_event_to_filtered_stream(committed_events.single(1)); - filter_processor - .Setup(_ => _.Filter(Moq.It.IsAny(), Moq.It.IsAny(), event_processor_id, Moq.It.IsAny(), cancellation_token)) - .Returns(Task.FromResult(new SuccessfulFiltering(true))); - }; - - static FilterValidationResult result; - Because of = () => result = validator.Validate(filter_definition, filter_processor.Object, 1, cancellation_token).GetAwaiter().GetResult(); - - It should_fail_validation = () => result.Success.ShouldBeFalse(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_old_filter_included_more_events_than_new_filter.cs b/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_old_filter_included_more_events_than_new_filter.cs deleted file mode 100644 index 8d3c1419f..000000000 --- a/Specifications/Events.Processing/Filters/for_ValidateFilterByComparingStreams/when_validating/and_old_filter_included_more_events_than_new_filter.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading.Tasks; -using Dolittle.Runtime.Events.Store; -using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Execution; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Processing.Filters.for_ValidateFilterByComparingStreams.when_validating; - -public class and_old_filter_included_more_events_than_new_filter : given.all_dependencies -{ - static int num_times_filtered = 0; - - Establish context = () => - { - add_event_to_event_log(3); - add_event_to_filtered_stream(3); - filter_processor - .Setup(_ => _.Filter(Moq.It.IsAny(), Moq.It.IsAny(), event_processor_id, Moq.It.IsAny(), cancellation_token)) - .Returns(() => num_times_filtered++ > 1 ? Task.FromResult(new SuccessfulFiltering(false)) : Task.FromResult(new SuccessfulFiltering(true))); - }; - - static FilterValidationResult result; - Because of = () => result = validator.Validate(filter_definition, filter_processor.Object, 1, cancellation_token).GetAwaiter().GetResult(); - - It should_fail_validation = () => result.Success.ShouldBeFalse(); -} \ No newline at end of file diff --git a/Specifications/Events.Processing/Mappings/streamprocessorstate/nonpartitioned/failing/mapping_is_correct.cs b/Specifications/Events.Processing/Mappings/streamprocessorstate/nonpartitioned/failing/mapping_is_correct.cs new file mode 100644 index 000000000..25c9e2d6a --- /dev/null +++ b/Specifications/Events.Processing/Mappings/streamprocessorstate/nonpartitioned/failing/mapping_is_correct.cs @@ -0,0 +1,28 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store.Actors; +using FluentAssertions; +using Machine.Specifications; + +namespace Dolittle.Runtime.Events.Processing.Mappings; + +public class mapping_a_failing_state : given.a_streamprocessorstate +{ + static StreamProcessorState before; + static Bucket as_protobuf; + static StreamProcessorState after; + + + private Establish context = () => + { + before = stream_processor_state; + as_protobuf = stream_processor_state.ToProtobuf(); + after = (StreamProcessorState)as_protobuf.FromProtobuf(); + }; + + It should_not_be_lossy = () => after.Should().BeEquivalentTo(before); + + It should_have_the_correct_type = () => after.ShouldBeOfExactType(before.GetType()); +} \ No newline at end of file diff --git a/Specifications/Events.Processing/Mappings/streamprocessorstate/nonpartitioned/given/a_failing_streamprocessorstate.cs b/Specifications/Events.Processing/Mappings/streamprocessorstate/nonpartitioned/given/a_failing_streamprocessorstate.cs new file mode 100644 index 000000000..a2844f878 --- /dev/null +++ b/Specifications/Events.Processing/Mappings/streamprocessorstate/nonpartitioned/given/a_failing_streamprocessorstate.cs @@ -0,0 +1,18 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store.Streams; + + +namespace Dolittle.Runtime.Events.Processing.Mappings.given; + +public class a_failing_streamprocessorstate +{ + protected static readonly DateTimeOffset last_successfully_processed = DateTimeOffset.Now - TimeSpan.FromSeconds(10); + protected static readonly DateTimeOffset retry_time = last_successfully_processed + TimeSpan.FromSeconds(30); + + protected static readonly StreamProcessorState stream_processor_state = + new(new ProcessingPosition(10, 15), "testing", retry_time, 2, last_successfully_processed, true); +} \ No newline at end of file diff --git a/Specifications/Events.Processing/Mappings/streamprocessorstate/nonpartitioned/given/a_streamprocessorstate.cs b/Specifications/Events.Processing/Mappings/streamprocessorstate/nonpartitioned/given/a_streamprocessorstate.cs new file mode 100644 index 000000000..9e01c5a46 --- /dev/null +++ b/Specifications/Events.Processing/Mappings/streamprocessorstate/nonpartitioned/given/a_streamprocessorstate.cs @@ -0,0 +1,14 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store.Streams; + + +namespace Dolittle.Runtime.Events.Processing.Mappings.given; + +public class a_streamprocessorstate +{ + protected static readonly StreamProcessorState stream_processor_state = new(new StreamPosition(10), 15, DateTimeOffset.Now); +} \ No newline at end of file diff --git a/Specifications/Events.Processing/Mappings/streamprocessorstate/nonpartitioned/mapping_is_correct.cs b/Specifications/Events.Processing/Mappings/streamprocessorstate/nonpartitioned/mapping_is_correct.cs new file mode 100644 index 000000000..d815c7abc --- /dev/null +++ b/Specifications/Events.Processing/Mappings/streamprocessorstate/nonpartitioned/mapping_is_correct.cs @@ -0,0 +1,29 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing.Streams; +using Dolittle.Runtime.Events.Store.Actors; +using FluentAssertions; +using Machine.Specifications; + +namespace Dolittle.Runtime.Events.Processing.Mappings; + +public class mapping_a_state : given.a_failing_streamprocessorstate +{ + static StreamProcessorState before; + static Bucket as_protobuf; + static StreamProcessorState after; + + + private Establish context = () => + { + before = stream_processor_state; + as_protobuf = stream_processor_state.ToProtobuf(); + after = (StreamProcessorState)as_protobuf.FromProtobuf(); + }; + + It should_not_be_lossy = () => after.Should().BeEquivalentTo(before); + + It should_have_the_correct_type = () => after.ShouldBeOfExactType(before.GetType()); + +} \ No newline at end of file diff --git a/Specifications/Events.Processing/Mappings/streamprocessorstate/partitioned/failing/mapping_is_correct.cs b/Specifications/Events.Processing/Mappings/streamprocessorstate/partitioned/failing/mapping_is_correct.cs new file mode 100644 index 000000000..80065121a --- /dev/null +++ b/Specifications/Events.Processing/Mappings/streamprocessorstate/partitioned/failing/mapping_is_correct.cs @@ -0,0 +1,29 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Events.Store.Actors; +using FluentAssertions; +using Machine.Specifications; + +namespace Dolittle.Runtime.Events.Processing.Mappings; + +public class mapping_a_failing_partitioned_state : given.a_failing_partitioned_streamprocessorstate +{ + static StreamProcessorState before; + static Bucket as_protobuf; + static StreamProcessorState after; + + + private Establish context = () => + { + before = stream_processor_state; + as_protobuf = stream_processor_state.ToProtobuf(); + after = (StreamProcessorState)as_protobuf.FromProtobuf(); + }; + + It should_not_be_lossy = () => after.Should().BeEquivalentTo(before); + + It should_have_the_correct_type = () => after.ShouldBeOfExactType(before.GetType()); +} \ No newline at end of file diff --git a/Specifications/Events.Processing/Mappings/streamprocessorstate/partitioned/given/a_failing_partitioned_streamprocessorstate.cs b/Specifications/Events.Processing/Mappings/streamprocessorstate/partitioned/given/a_failing_partitioned_streamprocessorstate.cs new file mode 100644 index 000000000..6da3ab391 --- /dev/null +++ b/Specifications/Events.Processing/Mappings/streamprocessorstate/partitioned/given/a_failing_partitioned_streamprocessorstate.cs @@ -0,0 +1,30 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; + + +namespace Dolittle.Runtime.Events.Processing.Mappings.given; + +public class a_failing_partitioned_streamprocessorstate +{ + protected static readonly ScopeId scope_id = Guid.Parse("abef5f64-9916-4762-a234-527990bc6c7c"); + protected static readonly Guid event_processor_id = Guid.Parse("07f1ee20-ec03-41a1-8bf5-c66cf6359cdf"); + protected static readonly Guid source_stream_id = Guid.Parse("c9294a5d-2e85-4ae2-8411-878d5d4fb4ac"); + + protected static readonly PartitionId failing_partition_id = new("some-partition"); + protected static readonly DateTimeOffset last_failed = DateTimeOffset.Now - TimeSpan.FromSeconds(10); + protected static readonly DateTimeOffset retry_time = last_failed + TimeSpan.FromSeconds(30); + + private static readonly ImmutableDictionary FailingPartitionStates = new Dictionary + { + { failing_partition_id, new FailingPartitionState(new StreamPosition(5), 7, retry_time, "testing", 2, last_failed) } + }.ToImmutableDictionary(); + + protected static readonly StreamProcessorState stream_processor_state = new(new ProcessingPosition(10, 20), FailingPartitionStates, DateTimeOffset.Now); +} \ No newline at end of file diff --git a/Specifications/Events.Processing/Mappings/streamprocessorstate/partitioned/given/a_partitioned_streamprocessorstate.cs b/Specifications/Events.Processing/Mappings/streamprocessorstate/partitioned/given/a_partitioned_streamprocessorstate.cs new file mode 100644 index 000000000..bb05387ef --- /dev/null +++ b/Specifications/Events.Processing/Mappings/streamprocessorstate/partitioned/given/a_partitioned_streamprocessorstate.cs @@ -0,0 +1,21 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Immutable; +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Events.Store.Streams; + + +namespace Dolittle.Runtime.Events.Processing.Mappings.given; + +public class a_partitioned_streamprocessorstate +{ + protected static readonly ScopeId scope_id = Guid.Parse("abef5f64-9916-4762-a234-527990bc6c7c"); + protected static readonly Guid event_processor_id = Guid.Parse("07f1ee20-ec03-41a1-8bf5-c66cf6359cdf"); + protected static readonly Guid source_stream_id = Guid.Parse("c9294a5d-2e85-4ae2-8411-878d5d4fb4ac"); + protected static readonly DateTimeOffset last_failed = DateTimeOffset.Now - TimeSpan.FromSeconds(10); + protected static readonly StreamProcessorState stream_processor_state = + new(new ProcessingPosition(10, 11), ImmutableDictionary.Empty, DateTimeOffset.Now); +} \ No newline at end of file diff --git a/Specifications/Events.Processing/Mappings/streamprocessorstate/partitioned/mapping_is_correct.cs b/Specifications/Events.Processing/Mappings/streamprocessorstate/partitioned/mapping_is_correct.cs new file mode 100644 index 000000000..7a60b7618 --- /dev/null +++ b/Specifications/Events.Processing/Mappings/streamprocessorstate/partitioned/mapping_is_correct.cs @@ -0,0 +1,29 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Events.Processing.Streams.Partitioned; +using Dolittle.Runtime.Events.Store.Actors; +using FluentAssertions; +using Machine.Specifications; + +namespace Dolittle.Runtime.Events.Processing.Mappings; + +public class mapping_a_partitioned_state : given.a_failing_partitioned_streamprocessorstate +{ + static StreamProcessorState before; + static Bucket as_protobuf; + static StreamProcessorState after; + + + private Establish context = () => + { + before = stream_processor_state; + as_protobuf = stream_processor_state.ToProtobuf(); + after = (StreamProcessorState)as_protobuf.FromProtobuf(); + }; + + It should_not_be_lossy = () => after.Should().BeEquivalentTo(before); + + It should_have_the_correct_type = () => after.ShouldBeOfExactType(before.GetType()); + +} \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_definition_is_not_persisted.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_definition_is_not_persisted.cs index ec449f69a..63eba8a6e 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_definition_is_not_persisted.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_definition_is_not_persisted.cs @@ -38,6 +38,6 @@ public class and_definition_is_not_persisted : given.all_dependencies }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeTrue(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_definition_is_persisted.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_definition_is_persisted.cs index be6c9a595..65f8603af 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_definition_is_persisted.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_definition_is_persisted.cs @@ -38,6 +38,6 @@ public class and_definition_is_persisted : given.all_dependencies }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeTrue(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_initial_state_differs.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_initial_state_differs.cs index d24fcb297..63c52d595 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_initial_state_differs.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_initial_state_differs.cs @@ -38,6 +38,6 @@ public class and_initial_state_differs : given.all_dependencies }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/by_adding_a_conversion.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/by_adding_a_conversion.cs index 1d72af2d6..5d20c4f36 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/by_adding_a_conversion.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/by_adding_a_conversion.cs @@ -57,6 +57,6 @@ public class by_adding_a_conversion : given.all_dependencies }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/by_removing_a_conversion.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/by_removing_a_conversion.cs index b607f813f..22069365d 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/by_removing_a_conversion.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/by_removing_a_conversion.cs @@ -57,6 +57,6 @@ public class by_removing_a_conversion : given.all_dependencies }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/conversion_type_for_nested_property.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/conversion_type_for_nested_property.cs index 5e656f37d..7f106bfb6 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/conversion_type_for_nested_property.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/conversion_type_for_nested_property.cs @@ -70,6 +70,6 @@ public class conversion_type_for_nested_property : given.all_dependencies }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/conversion_type_for_one_property.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/conversion_type_for_one_property.cs index 114bbb479..fe11b8e2b 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/conversion_type_for_one_property.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/conversion_type_for_one_property.cs @@ -58,6 +58,6 @@ public class conversion_type_for_one_property : given.all_dependencies }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/rename_to_for_nested_property.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/rename_to_for_nested_property.cs index 67734dcca..c409c692e 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/rename_to_for_nested_property.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/rename_to_for_nested_property.cs @@ -70,6 +70,6 @@ public class rename_to_for_nested_property : given.all_dependencies }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/rename_to_for_one_property.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/rename_to_for_one_property.cs index 12a01f98d..c60cd130c 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/rename_to_for_one_property.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/rename_to_for_one_property.cs @@ -58,6 +58,6 @@ public class rename_to_for_one_property : given.all_dependencies }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/should_rename_for_nested_property.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/should_rename_for_nested_property.cs index d3f0e245b..7fb2143eb 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/should_rename_for_nested_property.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/should_rename_for_nested_property.cs @@ -70,6 +70,6 @@ public class should_rename_for_nested_property : given.all_dependencies }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/should_rename_for_one_property.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/should_rename_for_one_property.cs index 04318fa3b..0a4ff52f5 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/should_rename_for_one_property.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_conversions_have_changed/should_rename_for_one_property.cs @@ -58,6 +58,6 @@ public class should_rename_for_one_property : given.all_dependencies }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_to_collection_has_changed.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_to_collection_has_changed.cs index b583768b9..6773aad44 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_to_collection_has_changed.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_mongodb_copy_to_collection_has_changed.cs @@ -46,6 +46,6 @@ public class and_mongodb_copy_to_collection_has_changed : given.all_dependencies }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_should_copy_to_mongodb_has_changed.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_should_copy_to_mongodb_has_changed.cs index a071ebc78..07d1e7909 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_should_copy_to_mongodb_has_changed.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_should_copy_to_mongodb_has_changed.cs @@ -46,6 +46,6 @@ public class and_should_copy_to_mongodb_has_changed : given.all_dependencies }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_event_selector_expression.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_event_selector_expression.cs index f1ac4a029..3c3b66199 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_event_selector_expression.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_event_selector_expression.cs @@ -44,6 +44,6 @@ public class and_there_is_a_different_event_selector_expression : given.all_depe }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_event_selector_occurred_format.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_event_selector_occurred_format.cs index 67200b755..441b310d9 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_event_selector_occurred_format.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_event_selector_occurred_format.cs @@ -44,6 +44,6 @@ public class and_there_is_a_different_event_selector_occurred_format : given.all }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_event_selector_static_key.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_event_selector_static_key.cs index 66a7a0de8..d881c34de 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_event_selector_static_key.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_event_selector_static_key.cs @@ -44,6 +44,6 @@ public class and_there_is_a_different_event_selector_static_key : given.all_depe }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_event_selector_type.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_event_selector_type.cs index d90b9d5d6..eee0c930a 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_event_selector_type.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_event_selector_type.cs @@ -44,6 +44,6 @@ public class and_there_is_a_different_event_selector_type : given.all_dependenci }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_number_of_event_types.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_number_of_event_types.cs index 30c33b3b9..423426edf 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_number_of_event_types.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_number_of_event_types.cs @@ -38,6 +38,6 @@ public class and_there_is_a_different_number_of_event_types : given.all_dependen }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_set_of_event_types.cs b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_set_of_event_types.cs index aaed8b34f..ca606c425 100644 --- a/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_set_of_event_types.cs +++ b/Specifications/Events.Processing/Projections/for_CompareProjectionDefinitionsForAllTenants/when_there_is_one_tenant/and_there_is_a_different_set_of_event_types.cs @@ -43,6 +43,6 @@ public class and_there_is_a_different_set_of_event_types : given.all_dependencie }; Because of = () => result = comparer.DiffersFromPersisted(definition, CancellationToken.None).GetAwaiter().GetResult(); - It should_have_result_for_tenant = () => result.Keys.ShouldContain(tenant); + It should_have_result_for_tenant = () => result.ContainsKey(tenant).ShouldBeTrue(); It should_not_be_a_successful_result = () => result[tenant].Succeeded.ShouldBeFalse(); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitionState/when_creating_state.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitionState/when_creating_state.cs index 0551cceec..5a307dc1a 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitionState/when_creating_state.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitionState/when_creating_state.cs @@ -9,7 +9,7 @@ namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned.for_FailingPart public class when_creating_state { - static StreamPosition position; + static ProcessingPosition position; static string reason; static DateTimeOffset retry_time; static FailingPartitionState state; @@ -17,14 +17,14 @@ public class when_creating_state Establish context = () => { - position = 0; + position = ProcessingPosition.Initial; reason = "reason"; retry_time = DateTimeOffset.Now; processing_attempts = 0; }; Because of = () => - state = new FailingPartitionState(position, retry_time, reason, processing_attempts, DateTimeOffset.UtcNow); + state = new FailingPartitionState(position.StreamPosition, position.EventLogPosition, retry_time, reason, processing_attempts, DateTimeOffset.UtcNow); It should_have_the_correct_position = () => state.Position.ShouldEqual(position); It should_have_the_correct_reason = () => state.Reason.ShouldEqual(reason); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/given/all_dependencies.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/given/all_dependencies.cs index 63bf2f798..9519e0127 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/given/all_dependencies.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/given/all_dependencies.cs @@ -4,7 +4,6 @@ using System; using Dolittle.Runtime.Events.Store.Streams; using Dolittle.Runtime.Execution; -using Microsoft.Extensions.Logging; using Machine.Specifications; using Moq; @@ -13,7 +12,8 @@ namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned.for_FailingPart public class all_dependencies { protected static StreamId stream_id; - protected static Mock stream_processor_state_repository; + // protected static Mock stream_processor_state_repository; + protected static IStreamProcessorStates stream_processor_state_repository; protected static Mock event_processor; protected static Mock events_fetcher; protected static Func create_execution_context; @@ -22,7 +22,7 @@ public class all_dependencies { stream_id = Guid.NewGuid(); event_processor = new Mock(); - stream_processor_state_repository = new Mock(); + stream_processor_state_repository = new in_memory_stream_processor_states(); events_fetcher = new Mock(); create_execution_context = stream_event => stream_event.Event.ExecutionContext; }; diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/given/an_instance_of_failing_partitions.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/given/an_instance_of_failing_partitions.cs index 2f1bea085..29f88d38b 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/given/an_instance_of_failing_partitions.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/given/an_instance_of_failing_partitions.cs @@ -12,7 +12,7 @@ public class an_instance_of_failing_partitions : all_dependencies protected static FailingPartitions failing_partitions; Establish context = () => failing_partitions = new FailingPartitions( - stream_processor_state_repository.Object, + stream_processor_state_repository, event_processor.Object, events_fetcher.Object, create_execution_context, diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_adding_failing_partition.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_adding_failing_partition.cs index 9e9ec5a94..50c15ad22 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_adding_failing_partition.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_adding_failing_partition.cs @@ -2,10 +2,10 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Collections.Generic; -using System.Threading; +using System.Collections.Immutable; using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; +using It = Machine.Specifications.It; namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned.for_FailingPartitions; @@ -13,30 +13,34 @@ public class when_adding_failing_partition : given.an_instance_of_failing_partit { static StreamProcessorId stream_processor_id; static PartitionId partition; - static StreamPosition stream_position; + static ProcessingPosition processing_position; static DateTimeOffset retry_time; static StreamProcessorState old_state; static string reason; static IStreamProcessorState result; + static StreamEvent stream_event; + + Establish context = () => { + stream_processor_id = new StreamProcessorId(Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid()); partition = "a partition"; - stream_position = 0; + stream_event = new StreamEvent(committed_events.single(), 0, Guid.Empty, partition, false); + processing_position = ProcessingPosition.Initial; retry_time = DateTimeOffset.Now; - old_state = new StreamProcessorState(stream_position, new Dictionary(), DateTimeOffset.UtcNow); + old_state = new StreamProcessorState(processing_position, ImmutableDictionary.Empty, DateTimeOffset.UtcNow); reason = ""; }; - Because of = () => result = failing_partitions.AddFailingPartitionFor(stream_processor_id, old_state, stream_position, partition, retry_time, reason, CancellationToken.None).GetAwaiter().GetResult(); - It should_persist_a_new_state = () => stream_processor_state_repository.Verify(_ => _.Persist(stream_processor_id, Moq.It.IsAny(), Moq.It.IsAny())); + private Because of = () => result = old_state.WithFailure(new FailedProcessing(reason, true, TimeSpan.Zero), stream_event, retry_time); It should_return_a_new_state = () => result.ShouldNotBeNull(); It should_return_a_state_of_the_expected_type = () => result.ShouldBeOfExactType(); - It should_return_a_state_with_the_position_incremented_by_one = () => result.Position.Value.ShouldEqual(stream_position + 1); + It should_return_a_state_with_the_position_incremented_by_one = () => result.Position.StreamPosition.Value.ShouldEqual(processing_position.StreamPosition + 1); It should_return_a_state_with_that_is_partitioned = () => result.Partitioned.ShouldBeTrue(); It should_return_state_with_the_failing_partition = () => (result as StreamProcessorState).FailingPartitions.ContainsKey(partition).ShouldBeTrue(); - It should_return_state_with_failing_partition_with_the_correct_position = () => (result as StreamProcessorState).FailingPartitions[partition].Position.ShouldEqual(stream_position); + It should_return_state_with_failing_partition_with_the_correct_position = () => (result as StreamProcessorState).FailingPartitions[partition].Position.ShouldEqual(processing_position); It should_return_state_with_failing_partition_with_the_correct_reason = () => (result as StreamProcessorState).FailingPartitions[partition].Reason.ShouldEqual(reason); It should_return_state_with_failing_partition_with_the_correct_number_of_processing_attempts = () => (result as StreamProcessorState).FailingPartitions[partition].ProcessingAttempts.ShouldEqual(1u); It should_return_state_with_failing_partition_with_the_correct_retry_time = () => (result as StreamProcessorState).FailingPartitions[partition].RetryTime.ShouldEqual(retry_time); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/given/all_dependencies.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/given/all_dependencies.cs index e509da9fb..d14ecf79a 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/given/all_dependencies.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/given/all_dependencies.cs @@ -11,8 +11,8 @@ public class all_dependencies : when_catching_up.given.all_dependencies { protected static PartitionId first_failing_partition_id; protected static PartitionId second_failing_partition_id; - protected static StreamPosition first_initial_failing_partition_position; - protected static StreamPosition second_initial_failing_partition_position; + protected static ProcessingPosition first_initial_failing_partition_position; + protected static ProcessingPosition second_initial_failing_partition_position; protected static string first_initial_failing_partition_reason; protected static string second_initial_failing_partition_reason; protected static DateTimeOffset first_initial_failing_partition_retry_time; @@ -24,20 +24,24 @@ public class all_dependencies : when_catching_up.given.all_dependencies { first_failing_partition_id = "first failing partition"; second_failing_partition_id = "the second failing partiton"; - first_initial_failing_partition_position = second_initial_failing_partition_position = 0; + first_initial_failing_partition_position = second_initial_failing_partition_position = ProcessingPosition.Initial; first_initial_failing_partition_reason = second_initial_failing_partition_reason = "some reason"; first_initial_failing_partition_retry_time = second_initial_failing_partition_retry_time = DateTimeOffset.UtcNow; first_failing_partition_state = new FailingPartitionState(first_initial_failing_partition_position, first_initial_failing_partition_retry_time, first_initial_failing_partition_reason, 1, DateTimeOffset.MinValue); second_failing_partition_state = new FailingPartitionState(second_initial_failing_partition_position, second_initial_failing_partition_retry_time, second_initial_failing_partition_reason, 1, DateTimeOffset.MinValue); - stream_processor_state.FailingPartitions.Add(first_failing_partition_id, first_failing_partition_state); - stream_processor_state.FailingPartitions.Add(second_failing_partition_id, second_failing_partition_state); + stream_processor_state = stream_processor_state with + { + FailingPartitions = stream_processor_state.FailingPartitions + .Add(first_failing_partition_id, first_failing_partition_state) + .Add(second_failing_partition_id, second_failing_partition_state) + }; eventStream = new[] { new StreamEvent(committed_events.single(), 0, stream_id, first_failing_partition_id, true), - new StreamEvent(committed_events.single(), 1, stream_id, second_failing_partition_id, true), - new StreamEvent(committed_events.single(), 2, stream_id, first_failing_partition_id, true), + new StreamEvent(committed_events.single(1), 1, stream_id, second_failing_partition_id, true), + new StreamEvent(committed_events.single(2), 2, stream_id, first_failing_partition_id, true), }; }; } \ No newline at end of file diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_be_retried/and_fails_processing.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_be_retried/and_fails_processing.cs index 16abcbcd4..71edc564c 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_be_retried/and_fails_processing.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_be_retried/and_fails_processing.cs @@ -17,9 +17,14 @@ public class and_fails_processing : given.all_dependencies static StreamProcessorState result; Establish context = () => + { + stream_processor_state_repository.Persist(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult(); + event_processor - .Setup(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) + .Setup(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), + Moq.It.IsAny(), Moq.It.IsAny())) .Returns(Task.FromResult(new FailedProcessing(new_failing_reason))); + }; Because of = () => result = failing_partitions.CatchupFor(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult() as StreamProcessorState; @@ -28,7 +33,7 @@ public class and_fails_processing : given.all_dependencies It should_have_failing_partition_with_first_failing_partition_id = () => result.FailingPartitions.ContainsKey(first_failing_partition_id).ShouldBeTrue(); It should_have_failing_partition_with_second_failing_partition_id = () => result.FailingPartitions.ContainsKey(second_failing_partition_id).ShouldBeTrue(); It should_not_change_first_failing_partition_position = () => failing_partition(first_failing_partition_id).Position.ShouldEqual(first_initial_failing_partition_position); - It should_change_second_failing_partition_position_two_first_unprocessed_event_in_partition = () => failing_partition(second_failing_partition_id).Position.ShouldEqual(second_initial_failing_partition_position.Increment()); + It should_change_second_failing_partition_position_two_first_unprocessed_event_in_partition = () => failing_partition(second_failing_partition_id).Position.ShouldEqual(new ProcessingPosition(1,0)); It should_have_new_first_failing_partition_reason = () => failing_partition(first_failing_partition_id).Reason.ShouldEqual(new_failing_reason); It should_have_new_second_failing_partition_reason = () => failing_partition(second_failing_partition_id).Reason.ShouldEqual(new_failing_reason); It should_not_change_first_failing_partition_retry_time = () => failing_partition(first_failing_partition_id).RetryTime.ShouldEqual(DateTimeOffset.MaxValue); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_be_retried/and_must_retry_processing_twice_before_failing.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_be_retried/and_must_retry_processing_twice_before_failing.cs index 585bd9a5f..fe7770e46 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_be_retried/and_must_retry_processing_twice_before_failing.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_be_retried/and_must_retry_processing_twice_before_failing.cs @@ -30,6 +30,7 @@ public class and_must_retry_processing_twice_before_failing : given.all_dependen Moq.It.IsAny())) .Returns((@event, partition, reason, retryCount, _, _) => Task.FromResult(retryCount >= 1 ? new FailedProcessing(last_failure_reason) : new FailedProcessing(new_failing_reason, true, TimeSpan.Zero))); + stream_processor_state_repository.Persist(stream_processor_id,stream_processor_state, CancellationToken.None).GetAwaiter().GetResult(); }; Because of = () => result = failing_partitions.CatchupFor(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult() as StreamProcessorState; @@ -39,7 +40,7 @@ public class and_must_retry_processing_twice_before_failing : given.all_dependen It should_have_failing_partition_with_first_failing_partition_id = () => result.FailingPartitions.ContainsKey(first_failing_partition_id).ShouldBeTrue(); It should_have_failing_partition_with_second_failing_partition_id = () => result.FailingPartitions.ContainsKey(second_failing_partition_id).ShouldBeTrue(); It should_not_change_first_failing_partition_position = () => failing_partition(first_failing_partition_id).Position.ShouldEqual(first_initial_failing_partition_position); - It should_change_second_failing_partition_position_two_first_unprocessed_event_in_partition = () => failing_partition(second_failing_partition_id).Position.ShouldEqual(second_initial_failing_partition_position.Increment()); + It should_change_second_failing_partition_position_two_first_unprocessed_event_in_partition = () => failing_partition(second_failing_partition_id).Position.ShouldEqual(new ProcessingPosition(1,0)); It should_have_new_first_failing_partition_reason = () => failing_partition(first_failing_partition_id).Reason.ShouldEqual(last_failure_reason); It should_have_new_second_failing_partition_reason = () => failing_partition(second_failing_partition_id).Reason.ShouldEqual(last_failure_reason); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_be_retried/and_succeeds_in_processing/all_events.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_be_retried/and_succeeds_in_processing/all_events.cs index 2c55a6319..56b54c7d6 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_be_retried/and_succeeds_in_processing/all_events.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_be_retried/and_succeeds_in_processing/all_events.cs @@ -15,6 +15,7 @@ public class all_events : given.all_dependencies static StreamProcessorState result; Establish context = () => + { event_processor .Setup(_ => _.Process( Moq.It.IsAny(), @@ -23,7 +24,10 @@ public class all_events : given.all_dependencies Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); + + stream_processor_state_repository.Persist(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult(); + }; Because of = () => result = failing_partitions.CatchupFor(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult() as StreamProcessorState; diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_be_retried/and_succeeds_in_processing/but_fails_on_last_event.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_be_retried/and_succeeds_in_processing/but_fails_on_last_event.cs index c1b6db3f2..0ba7bf6e6 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_be_retried/and_succeeds_in_processing/but_fails_on_last_event.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_be_retried/and_succeeds_in_processing/but_fails_on_last_event.cs @@ -27,7 +27,9 @@ public class but_fails_on_last_event : given.all_dependencies Moq.It.IsAny(), Moq.It.IsAny())) .Returns((@event, partition, reason, retryCount, _, _) => - @event == eventStream[2].Event ? Task.FromResult(new FailedProcessing(new_failure_reason)) : Task.FromResult(new SuccessfulProcessing())); + @event == eventStream[2].Event ? Task.FromResult(new FailedProcessing(new_failure_reason)) : Task.FromResult(SuccessfulProcessing.Instance)); + stream_processor_state_repository.Persist(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult(); + }; Because of = () => result = failing_partitions.CatchupFor(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult() as StreamProcessorState; @@ -35,7 +37,7 @@ public class but_fails_on_last_event : given.all_dependencies It should_return_the_same_stream_position = () => result.Position.ShouldEqual(stream_processor_state.Position); It should_have_one_failing_partition = () => result.FailingPartitions.Count.ShouldEqual(1); It should_have_failing_partition_with_correct_id = () => result.FailingPartitions.ContainsKey(first_failing_partition_id).ShouldBeTrue(); - It should_have_the_correct_position_on_failing_partition = () => failing_partition(first_failing_partition_id).Position.ShouldEqual(new StreamPosition(first_initial_failing_partition_position + 2)); + It should_have_the_correct_position_on_failing_partition = () => failing_partition(first_failing_partition_id).Position.StreamPosition.ShouldEqual(new StreamPosition(first_initial_failing_partition_position.StreamPosition + 2)); It should_have_new_failing_partition_reason = () => failing_partition(first_failing_partition_id).Reason.ShouldEqual(new_failure_reason); It should_not_retry_failing_partition = () => failing_partition(first_failing_partition_id).RetryTime.ShouldEqual(DateTimeOffset.MaxValue); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_never_be_retried.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_never_be_retried.cs index 9221d1d49..9825df35c 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_never_be_retried.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_multiple_failing_partitions/that_should_never_be_retried.cs @@ -14,20 +14,22 @@ public class that_should_never_be_retried : given.all_dependencies { static StreamProcessorState result; - Establish context = () => + private Establish context = () => { - stream_processor_state.FailingPartitions[first_failing_partition_id] = new FailingPartitionState( + stream_processor_state = stream_processor_state.WithFailingPartition(first_failing_partition_id, new FailingPartitionState( first_failing_partition_state.Position, DateTimeOffset.MaxValue, first_failing_partition_state.Reason, first_failing_partition_state.ProcessingAttempts, - DateTimeOffset.UtcNow); - stream_processor_state.FailingPartitions[second_failing_partition_id] = new FailingPartitionState( + DateTimeOffset.UtcNow)); + + stream_processor_state = stream_processor_state.WithFailingPartition(second_failing_partition_id, new FailingPartitionState( second_failing_partition_state.Position, DateTimeOffset.MaxValue, second_failing_partition_state.Reason, second_failing_partition_state.ProcessingAttempts, - DateTimeOffset.UtcNow); + DateTimeOffset.UtcNow)); + stream_processor_state_repository.Persist(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult(); }; Because of = () => result = failing_partitions.CatchupFor(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult() as StreamProcessorState; diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_no_failing_partitions.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_no_failing_partitions.cs index 78ddfcdba..e400b8d81 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_no_failing_partitions.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_are_no_failing_partitions.cs @@ -1,6 +1,7 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.Collections.Immutable; using System.Threading; using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; @@ -13,7 +14,8 @@ public class and_there_are_no_failing_partitions : given.all_dependencies { static IStreamProcessorState result; - Establish context = () => stream_processor_state.FailingPartitions.Clear(); + private Establish context = () => + stream_processor_state = stream_processor_state with { FailingPartitions = ImmutableDictionary.Empty }; Because of = () => result = failing_partitions.CatchupFor(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult(); @@ -22,5 +24,9 @@ public class and_there_are_no_failing_partitions : given.all_dependencies It should_return_a_state_with_the_same_position = () => result.Position.ShouldEqual(stream_processor_state.Position); It should_return_a_state_with_the_correct_partitioned_value = () => result.Partitioned.ShouldEqual(stream_processor_state.Partitioned); It should_have_no_failing_partitions = () => (result as StreamProcessorState).FailingPartitions.ShouldBeEmpty(); - It should_not_process_any_events = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Never); + + It should_not_process_any_events = () => + event_processor.Verify( + _ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny()), + Moq.Times.Never); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/given/all_dependencies.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/given/all_dependencies.cs index 47702b059..2b53eadbc 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/given/all_dependencies.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/given/all_dependencies.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Threading; using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; @@ -10,19 +11,23 @@ namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned.for_FailingPart public class all_dependencies : when_catching_up.given.all_dependencies { protected static PartitionId failing_partition_id; - protected static StreamPosition initial_failing_partition_position; + protected static ProcessingPosition initial_failing_partition_position; protected static string initial_failing_partition_reason; protected static DateTimeOffset initial_failing_partition_retry_time; protected static FailingPartitionState failing_partition_state; - Establish context = () => + private Establish context = () => { failing_partition_id = "failing partition"; - initial_failing_partition_position = 0; + initial_failing_partition_position = ProcessingPosition.Initial; initial_failing_partition_reason = "some reason"; initial_failing_partition_retry_time = DateTimeOffset.UtcNow; failing_partition_state = new FailingPartitionState(initial_failing_partition_position, initial_failing_partition_retry_time, initial_failing_partition_reason, 1, DateTimeOffset.UtcNow); - stream_processor_state.FailingPartitions.Add(failing_partition_id, failing_partition_state); + stream_processor_state = stream_processor_state with + { + FailingPartitions = stream_processor_state.FailingPartitions.Add(failing_partition_id, failing_partition_state) + }; + stream_processor_state_repository.Persist(stream_processor_id, stream_processor_state, CancellationToken.None); eventStream = new[] { new StreamEvent(committed_events.single(), 0, stream_id, failing_partition_id, true), diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_be_retried/and_fails_processing.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_be_retried/and_fails_processing.cs index 1eeb92c3a..147142f95 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_be_retried/and_fails_processing.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_be_retried/and_fails_processing.cs @@ -17,6 +17,7 @@ public class and_fails_processing : given.all_dependencies static StreamProcessorState result; Establish context = () => + { event_processor .Setup(_ => _.Process( Moq.It.IsAny(), @@ -26,13 +27,16 @@ public class and_fails_processing : given.all_dependencies Moq.It.IsAny(), Moq.It.IsAny())) .Returns(Task.FromResult(new FailedProcessing(new_failing_reason))); + + stream_processor_state_repository.Persist(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult(); + }; Because of = () => result = failing_partitions.CatchupFor(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult() as StreamProcessorState; It should_return_the_same_stream_position = () => result.Position.ShouldEqual(stream_processor_state.Position); It should_have_one_failing_partition = () => result.FailingPartitions.Count.ShouldEqual(1); It should_have_failing_partition_with_correct_id = () => result.FailingPartitions.ContainsKey(failing_partition_id).ShouldBeTrue(); - It should_not_change_failing_partition_position = () => failing_partition(failing_partition_id).Position.ShouldEqual(initial_failing_partition_position); + It should_not_change_failing_partition_position = () => failing_partition(failing_partition_id).Position.StreamPosition.ShouldEqual(initial_failing_partition_position.StreamPosition); It should_have_new_failing_partition_reason = () => failing_partition(failing_partition_id).Reason.ShouldEqual(new_failing_reason); It should_not_retry_failing_partition = () => failing_partition(failing_partition_id).RetryTime.ShouldEqual(DateTimeOffset.MaxValue); @@ -45,7 +49,7 @@ public class and_fails_processing : given.all_dependencies It should_have_retried_processing_event_once = () => event_processor.Verify( _ => _.Process( - eventStream[(int)(result as StreamProcessorState).FailingPartitions[failing_partition_id].Position.Value].Event, + eventStream[(int)(result as StreamProcessorState).FailingPartitions[failing_partition_id].Position.StreamPosition.Value].Event, failing_partition_id, Moq.It.IsAny(), Moq.It.IsAny(), diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_be_retried/and_must_retry_processing_twice_before_failing.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_be_retried/and_must_retry_processing_twice_before_failing.cs index f7090567f..8a1a744b9 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_be_retried/and_must_retry_processing_twice_before_failing.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_be_retried/and_must_retry_processing_twice_before_failing.cs @@ -48,7 +48,7 @@ public class and_must_retry_processing_twice_before_failing : given.all_dependen It should_have_retried_processing_first_event_three_times = () => event_processor.Verify( _ => _.Process( - eventStream[(int)failing_partition(failing_partition_id).Position.Value].Event, + eventStream[(int)failing_partition(failing_partition_id).Position.StreamPosition.Value].Event, failing_partition_id, Moq.It.IsAny(), Moq.It.IsAny(), diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_be_retried/and_succeeds_in_processing/all_events.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_be_retried/and_succeeds_in_processing/all_events.cs index eaf83c91b..c6d4d1052 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_be_retried/and_succeeds_in_processing/all_events.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_be_retried/and_succeeds_in_processing/all_events.cs @@ -17,7 +17,7 @@ public class all_events : given.all_dependencies Establish context = () => event_processor .Setup(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); Because of = () => result = failing_partitions.CatchupFor(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult() as StreamProcessorState; diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_be_retried/and_succeeds_in_processing/but_fails_on_last_event.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_be_retried/and_succeeds_in_processing/but_fails_on_last_event.cs index 6b750a891..dcbb0316d 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_be_retried/and_succeeds_in_processing/but_fails_on_last_event.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_be_retried/and_succeeds_in_processing/but_fails_on_last_event.cs @@ -20,10 +20,10 @@ public class but_fails_on_last_event : given.all_dependencies { event_processor .Setup(_ => _.Process(eventStream[0].Event, Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); event_processor .Setup(_ => _.Process(eventStream[1].Event, Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); event_processor .Setup(_ => _.Process(eventStream[2].Event, Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) .Returns(Task.FromResult(new FailedProcessing(new_failure_reason))); @@ -34,7 +34,7 @@ public class but_fails_on_last_event : given.all_dependencies It should_return_the_same_stream_position = () => result.Position.ShouldEqual(stream_processor_state.Position); It should_have_one_failing_partition = () => result.FailingPartitions.Count.ShouldEqual(1); It should_have_failing_partition_with_correct_id = () => result.FailingPartitions.ContainsKey(failing_partition_id).ShouldBeTrue(); - It should_have_the_correct_position_on_failing_partition = () => failing_partition(failing_partition_id).Position.ShouldEqual(new StreamPosition(initial_failing_partition_position + 2)); + It should_have_the_correct_position_on_failing_partition = () => failing_partition(failing_partition_id).Position.StreamPosition.ShouldEqual(new StreamPosition(initial_failing_partition_position.StreamPosition + 2)); It should_have_new_failing_partition_reason = () => failing_partition(failing_partition_id).Reason.ShouldEqual(new_failure_reason); It should_not_retry_failing_partition = () => failing_partition(failing_partition_id).RetryTime.ShouldEqual(DateTimeOffset.MaxValue); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_never_be_retried.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_never_be_retried.cs index f7f2131a7..7a88dabbe 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_never_be_retried.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/and_there_is_one_failing_partition/that_should_never_be_retried.cs @@ -14,17 +14,20 @@ public class that_should_never_be_retried : given.all_dependencies { static StreamProcessorState result; - Establish context = () => + private Establish context = () => { - stream_processor_state.FailingPartitions[failing_partition_id] = new FailingPartitionState( + stream_processor_state = stream_processor_state.WithFailingPartition(failing_partition_id, new FailingPartitionState( failing_partition_state.Position, DateTimeOffset.MaxValue, failing_partition_state.Reason, failing_partition_state.ProcessingAttempts, - DateTimeOffset.UtcNow); + DateTimeOffset.UtcNow)); + stream_processor_state_repository.Persist(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult(); }; - Because of = () => result = failing_partitions.CatchupFor(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult() as StreamProcessorState; + Because of = () => + result = + failing_partitions.CatchupFor(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult() as StreamProcessorState; It should_return_a_state = () => result.ShouldNotBeNull(); It should_return_a_state_of_the_expected_type = () => result.ShouldBeOfExactType(); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/given/all_dependencies.cs b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/given/all_dependencies.cs index 3f552d6e7..0abf11dbf 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/given/all_dependencies.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_FailingPartitions/when_catching_up/given/all_dependencies.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -14,7 +15,7 @@ namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned.for_FailingPart public class all_dependencies : for_FailingPartitions.given.an_instance_of_failing_partitions { - protected static readonly StreamPosition initial_stream_processor_position = 3; + protected static readonly ProcessingPosition initial_stream_processor_position = new(3,3); protected static StreamProcessorId stream_processor_id; protected static StreamProcessorState stream_processor_state; protected static IReadOnlyList eventStream; @@ -22,20 +23,8 @@ public class all_dependencies : for_FailingPartitions.given.an_instance_of_faili Establish context = () => { stream_processor_id = new StreamProcessorId(Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid()); - stream_processor_state = new StreamProcessorState(initial_stream_processor_position, new Dictionary(), DateTimeOffset.UtcNow); - - stream_processor_state_repository - .Setup(_ => _.TryGetFor(Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(Try.Succeeded(stream_processor_state))); - - stream_processor_state_repository - .Setup(_ => _.Persist(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) - .Returns((stream_processor_id, new_state, _) => - { - stream_processor_state = new_state as StreamProcessorState; - return Task.FromResult(stream_processor_state); - }); - + stream_processor_state = new StreamProcessorState(initial_stream_processor_position, ImmutableDictionary.Empty, DateTimeOffset.UtcNow); + stream_processor_state_repository.Persist(stream_processor_id, stream_processor_state, CancellationToken.None).GetAwaiter().GetResult(); events_fetcher .Setup(_ => _.FetchInPartition(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) .Returns((partition, position, _) => diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/given/all_dependencies.cs b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/given/all_dependencies.cs index 3093fe5ac..f173a3611 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/given/all_dependencies.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/given/all_dependencies.cs @@ -28,7 +28,7 @@ public class all_dependencies protected static TenantId tenant_id; protected static StreamId source_stream_id; protected static StreamProcessorId stream_processor_id; - protected static IResilientStreamProcessorStateRepository stream_processor_state_repository; + protected static IStreamProcessorStates stream_processor_state_repository; protected static Mock events_fetcher; protected static IFailingPartitions failing_partitiones; protected static Mock stream_processors; @@ -41,7 +41,7 @@ public class all_dependencies { execution_context = execution_contexts.create(); cancellation_token_source = new CancellationTokenSource(); - var in_memory_stream_processor_state_repository = new in_memory_stream_processor_state_repository(); + var in_memory_stream_processor_state_repository = new in_memory_stream_processor_states(); event_processor_id = Guid.NewGuid(); scope_id = Guid.NewGuid(); tenant_id = Guid.NewGuid(); @@ -75,13 +75,12 @@ public class all_dependencies (processor, stream, arg3) => failing_partitiones, new EventFetcherPolicies(Mock.Of()), event_waiter, - new TimeToRetryForPartitionedStreamProcessor(), Mock.Of>()); action_to_perform_before_reprocessing = new Mock>>(); action_to_perform_before_reprocessing .Setup(_ => _(It.IsAny(), It.IsAny())) - .ReturnsAsync(Try.Succeeded()); + .ReturnsAsync(Try.Succeeded); }; Cleanup clean = () => cancellation_token_source.Dispose(); @@ -90,7 +89,7 @@ protected static Task start_stream_processor_and_cancel_after(TimeSpan cancelAft cancellation_token_source.CancelAfter(cancelAfter); return stream_processor.Start(cancellation_token_source.Token); } - protected static Task start_stream_processor_set_position_after_and_cancel_after(TimeSpan setPositionAfter, StreamPosition position, Func> beforeReprocessingAction, TimeSpan cancelAfter) + protected static Task start_stream_processor_set_position_after_and_cancel_after(TimeSpan setPositionAfter, ProcessingPosition position, Func> beforeReprocessingAction, TimeSpan cancelAfter) { var result = stream_processor.Start(cancellation_token_source.Token); Task.Delay(setPositionAfter).GetAwaiter().GetResult(); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/a_stream_that_has_events_in_two_partitions/and_processing_fails_at_second_event_in_both_partitions.cs b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/a_stream_that_has_events_in_two_partitions/and_processing_fails_at_second_event_in_both_partitions.cs index 6c5910031..344bf4860 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/a_stream_that_has_events_in_two_partitions/and_processing_fails_at_second_event_in_both_partitions.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/a_stream_that_has_events_in_two_partitions/and_processing_fails_at_second_event_in_both_partitions.cs @@ -4,7 +4,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using Dolittle.Runtime.Rudimentary; using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; @@ -36,7 +35,7 @@ public class and_processing_fails_at_second_event_in_both_partitions : given.all Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); event_processor .Setup(_ => _.Process( Moq.It.Is(_ => _ == third_event.Event || _ == fourth_event.Event), @@ -57,12 +56,12 @@ public class and_processing_fails_at_second_event_in_both_partitions : given.all It should_process_fourth_event = () => event_processor.Verify(_ => _.Process(fourth_event.Event, second_partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once); It should_not_retry_processing = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Never); - It should_have_persisted_the_correct_position = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(4)); + It should_have_persisted_the_correct_position = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(4)); It should_have_persisted_state_with_two_failing_partitions = () => current_stream_processor_state.FailingPartitions.Count.ShouldEqual(2); It should_have_persisted_state_with_correct_first_failing_partition = () => current_stream_processor_state.FailingPartitions.ContainsKey(first_partition_id).ShouldBeTrue(); It should_have_persisted_state_with_correct_second_failing_partition = () => current_stream_processor_state.FailingPartitions.ContainsKey(second_partition_id).ShouldBeTrue(); - It should_have_persisted_correct_position_on_the_first_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].Position.ShouldEqual(new StreamPosition(2)); - It should_have_persisted_correct_position_on_the_second_failing_partition = () => current_stream_processor_state.FailingPartitions[second_partition_id].Position.ShouldEqual(new StreamPosition(3)); + It should_have_persisted_correct_position_on_the_first_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].Position.StreamPosition.ShouldEqual(new StreamPosition(2)); + It should_have_persisted_correct_position_on_the_second_failing_partition = () => current_stream_processor_state.FailingPartitions[second_partition_id].Position.StreamPosition.ShouldEqual(new StreamPosition(3)); It should_have_persisted_correct_retry_time_on_the_first_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].RetryTime.ShouldEqual(DateTimeOffset.MaxValue); It should_have_persisted_correct_retry_time_on_the_second_failing_partition = () => current_stream_processor_state.FailingPartitions[second_partition_id].RetryTime.ShouldEqual(DateTimeOffset.MaxValue); It should_have_persisted_correct_reason_on_the_first_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].Reason.ShouldEqual(reason); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/a_stream_that_has_events_in_two_partitions/and_processing_fails_in_both_partitions.cs b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/a_stream_that_has_events_in_two_partitions/and_processing_fails_in_both_partitions.cs index d3f8c1b6f..87a8488d0 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/a_stream_that_has_events_in_two_partitions/and_processing_fails_in_both_partitions.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/a_stream_that_has_events_in_two_partitions/and_processing_fails_in_both_partitions.cs @@ -4,7 +4,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using Dolittle.Runtime.Rudimentary; using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; @@ -40,12 +39,12 @@ public class and_processing_fails_in_both_partitions : given.all_dependencies It should_process_second_event = () => event_processor.Verify(_ => _.Process(second_event.Event, second_partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once); It should_not_retry_processing = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Never); - It should_have_persisted_the_correct_position = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(2)); + It should_have_persisted_the_correct_position = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(2)); It should_have_persisted_state_with_two_failing_partitions = () => current_stream_processor_state.FailingPartitions.Count.ShouldEqual(2); It should_have_persisted_state_with_correct_first_failing_partition = () => current_stream_processor_state.FailingPartitions.ContainsKey(first_partition_id).ShouldBeTrue(); It should_have_persisted_state_with_correct_second_failing_partition = () => current_stream_processor_state.FailingPartitions.ContainsKey(second_partition_id).ShouldBeTrue(); - It should_have_persisted_correct_position_on_the_first_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].Position.ShouldEqual(new StreamPosition(0)); - It should_have_persisted_correct_position_on_the_second_failing_partition = () => current_stream_processor_state.FailingPartitions[second_partition_id].Position.ShouldEqual(new StreamPosition(1)); + It should_have_persisted_correct_position_on_the_first_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].Position.StreamPosition.ShouldEqual(new StreamPosition(0)); + It should_have_persisted_correct_position_on_the_second_failing_partition = () => current_stream_processor_state.FailingPartitions[second_partition_id].Position.StreamPosition.ShouldEqual(new StreamPosition(1)); It should_have_persisted_correct_retry_time_on_the_first_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].RetryTime.ShouldEqual(DateTimeOffset.MaxValue); It should_have_persisted_correct_retry_time_on_the_second_failing_partition = () => current_stream_processor_state.FailingPartitions[second_partition_id].RetryTime.ShouldEqual(DateTimeOffset.MaxValue); It should_have_persisted_correct_reason_on_the_first_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].Reason.ShouldEqual(reason); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/a_stream_that_has_events_in_two_partitions/and_processing_fails_in_one_partition.cs b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/a_stream_that_has_events_in_two_partitions/and_processing_fails_in_one_partition.cs index f285857a3..03e102a7d 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/a_stream_that_has_events_in_two_partitions/and_processing_fails_in_one_partition.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/a_stream_that_has_events_in_two_partitions/and_processing_fails_in_one_partition.cs @@ -4,7 +4,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using Dolittle.Runtime.Rudimentary; using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; @@ -32,7 +31,7 @@ public class and_processing_fails_in_one_partition : given.all_dependencies fourth_event = new StreamEvent(committed_events.single(), 3u, Guid.NewGuid(), second_partition_id, true); event_processor .Setup(_ => _.Process(Moq.It.IsAny(), second_partition_id, Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); event_processor .Setup(_ => _.Process(Moq.It.IsAny(), first_partition_id, Moq.It.IsAny(), Moq.It.IsAny())) .Returns(Task.FromResult(new FailedProcessing(reason))); @@ -49,10 +48,10 @@ public class and_processing_fails_in_one_partition : given.all_dependencies It should_process_fourth_event = () => event_processor.Verify(_ => _.Process(fourth_event.Event, second_partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once); It should_not_retry_processing = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Never); - It should_have_persisted_the_correct_position = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(4)); + It should_have_persisted_the_correct_position = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(4)); It should_have_persisted_state_with_one_failing_partition = () => current_stream_processor_state.FailingPartitions.Count.ShouldEqual(1); It should_have_persisted_state_with_correct_first_failing_partition = () => current_stream_processor_state.FailingPartitions.ContainsKey(first_partition_id).ShouldBeTrue(); - It should_have_persisted_correct_position_on_the_first_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].Position.ShouldEqual(new StreamPosition(0)); + It should_have_persisted_correct_position_on_the_first_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].Position.StreamPosition.ShouldEqual(new StreamPosition(0)); It should_have_persisted_correct_retry_time_on_the_first_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].RetryTime.ShouldEqual(DateTimeOffset.MaxValue); It should_have_persisted_correct_reason_on_the_first_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].Reason.ShouldEqual(reason); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/a_stream_that_has_events_in_two_partitions/and_processing_must_retry_in_both_partitions.cs b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/a_stream_that_has_events_in_two_partitions/and_processing_must_retry_in_both_partitions.cs index 70d7c95c3..d20f6b107 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/a_stream_that_has_events_in_two_partitions/and_processing_must_retry_in_both_partitions.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/a_stream_that_has_events_in_two_partitions/and_processing_must_retry_in_both_partitions.cs @@ -4,7 +4,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using Dolittle.Runtime.Rudimentary; using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; @@ -25,7 +24,7 @@ public class and_processing_must_retry_in_both_partitions : given.all_dependenci first_partition_id = "first partition"; second_partition_id = "second partition"; first_event = new StreamEvent(committed_events.single(), StreamPosition.Start, Guid.NewGuid(), first_partition_id, true); - second_event = new StreamEvent(committed_events.single(), 1u, Guid.NewGuid(), second_partition_id, true); + second_event = new StreamEvent(committed_events.single(2), 1u, Guid.NewGuid(), second_partition_id, true); event_processor .Setup(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) .Returns(Task.FromResult(new FailedProcessing(reason, true, TimeSpan.Zero))); @@ -35,7 +34,10 @@ public class and_processing_must_retry_in_both_partitions : given.all_dependenci setup_event_stream(first_event, second_event); }; - Because of = () => start_stream_processor_and_cancel_after(TimeSpan.FromMilliseconds(100)).GetAwaiter().GetResult(); + private Because of = () => + { + start_stream_processor_and_cancel_after(TimeSpan.FromMilliseconds(100)).GetAwaiter().GetResult(); + }; It should_process_one_event_in_first_partition = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), first_partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once); It should_process_one_event_in_second_partition = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), second_partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once); @@ -45,12 +47,12 @@ public class and_processing_must_retry_in_both_partitions : given.all_dependenci It should_retry_processing_event_in_first_partition_once = () => event_processor.Verify(_ => _.Process(first_event.Event, first_partition_id, Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once); It should_retry_processing_event_in_second_partition_once = () => event_processor.Verify(_ => _.Process(second_event.Event, second_partition_id, Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once); - It should_have_persisted_the_correct_position = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(2)); + It should_have_persisted_the_correct_position = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(2)); It should_have_persisted_state_with_two_failing_partitions = () => current_stream_processor_state.FailingPartitions.Count.ShouldEqual(2); It should_have_persisted_state_with_correct_first_failing_partition = () => current_stream_processor_state.FailingPartitions.ContainsKey(first_partition_id).ShouldBeTrue(); It should_have_persisted_state_with_correct_second_failing_partition = () => current_stream_processor_state.FailingPartitions.ContainsKey(second_partition_id).ShouldBeTrue(); - It should_have_persisted_correct_position_on_the_first_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].Position.ShouldEqual(new StreamPosition(0)); - It should_have_persisted_correct_position_on_the_second_failing_partition = () => current_stream_processor_state.FailingPartitions[second_partition_id].Position.ShouldEqual(new StreamPosition(1)); + It should_have_persisted_correct_position_on_the_first_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].Position.StreamPosition.ShouldEqual(new StreamPosition(0)); + It should_have_persisted_correct_position_on_the_second_failing_partition = () => current_stream_processor_state.FailingPartitions[second_partition_id].Position.StreamPosition.ShouldEqual(new StreamPosition(1)); It should_have_persisted_correct_retry_time_on_the_first_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].RetryTime.ShouldEqual(DateTimeOffset.MaxValue); It should_have_persisted_correct_retry_time_on_the_second_failing_partition = () => current_stream_processor_state.FailingPartitions[second_partition_id].RetryTime.ShouldEqual(DateTimeOffset.MaxValue); It should_have_persisted_correct_reason_on_the_first_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].Reason.ShouldEqual(reason); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/and_stream_has_only_one_partition/and_event_processing_failed_at_first_event.cs b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/and_stream_has_only_one_partition/and_event_processing_failed_at_first_event.cs index 1000f288f..f660171a3 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/and_stream_has_only_one_partition/and_event_processing_failed_at_first_event.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/and_stream_has_only_one_partition/and_event_processing_failed_at_first_event.cs @@ -31,10 +31,10 @@ public class and_event_processing_failed_at_first_event : given.all_dependencies It should_process_one_event = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once()); It should_process_first_event = () => event_processor.Verify(_ => _.Process(first_event, partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once()); - It should_have_current_position_equal_zero = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(1)); + It should_have_current_position_equal_zero = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(1)); It should_have_one_failing_partition = () => current_stream_processor_state.FailingPartitions.Count.ShouldEqual(1); It should_have_the_correct_failing_partition = () => current_stream_processor_state.FailingPartitions.ContainsKey(partition_id).ShouldBeTrue(); - It should_have_the_correct_position_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].Position.ShouldEqual(new StreamPosition(0)); + It should_have_the_correct_position_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].Position.StreamPosition.ShouldEqual(new StreamPosition(0)); It should_have_the_correct_retry_time_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].RetryTime.ShouldEqual(DateTimeOffset.MaxValue); It should_have_the_correct_reason_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].Reason.ShouldEqual(reason); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/and_stream_has_only_one_partition/and_event_processing_failed_at_second_event.cs b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/and_stream_has_only_one_partition/and_event_processing_failed_at_second_event.cs index d194c0c6d..453c13397 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/and_stream_has_only_one_partition/and_event_processing_failed_at_second_event.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/and_stream_has_only_one_partition/and_event_processing_failed_at_second_event.cs @@ -22,7 +22,7 @@ public class and_event_processing_failed_at_second_event : given.all_dependencie { event_processor .Setup(_ => _.Process(first_event, partition_id, Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); event_processor .Setup(_ => _.Process(second_event, partition_id, Moq.It.IsAny(), Moq.It.IsAny())) .Returns(Task.FromResult(new FailedProcessing(reason))); @@ -37,10 +37,10 @@ public class and_event_processing_failed_at_second_event : given.all_dependencie It should_process_first_event = () => event_processor.Verify(_ => _.Process(first_event, partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once()); It should_process_second_event = () => event_processor.Verify(_ => _.Process(second_event, partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once()); - It should_have_current_position_equal_1 = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(2)); + It should_have_current_position_equal_1 = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(2)); It should_have_one_failing_partition = () => current_stream_processor_state.FailingPartitions.Count.ShouldEqual(1); It should_have_the_correct_failing_partition = () => current_stream_processor_state.FailingPartitions.ContainsKey(partition_id).ShouldBeTrue(); - It should_have_the_correct_position_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].Position.ShouldEqual(new StreamPosition(1)); + It should_have_the_correct_position_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].Position.StreamPosition.ShouldEqual(new StreamPosition(1)); It should_have_the_correct_reason_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].Reason.ShouldEqual(reason); It should_have_the_correct_retry_time_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].RetryTime.ShouldEqual(DateTimeOffset.MaxValue); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/and_stream_has_only_one_partition/and_stream_processor_must_retry_processing_an_event_three_times.cs b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/and_stream_has_only_one_partition/and_stream_processor_must_retry_processing_an_event_three_times.cs index db80c745a..3007214dc 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/and_stream_has_only_one_partition/and_stream_processor_must_retry_processing_an_event_three_times.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_processing/and_stream_has_only_one_partition/and_stream_processor_must_retry_processing_an_event_three_times.cs @@ -4,7 +4,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using Dolittle.Runtime.Rudimentary; using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; @@ -44,10 +43,10 @@ public class and_stream_processor_must_retry_processing_an_event_three_times : g It should_retry_processing_first_event_second_time_with_correct_reason = () => event_processor.Verify(_ => _.Process(first_event, partition_id, retry_reason, 1, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once); It should_retry_processing_first_event_third_time_with_correct_reason = () => event_processor.Verify(_ => _.Process(first_event, partition_id, retry_reason, 2, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once); - It should_have_current_position_equal_one = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(1)); + It should_have_current_position_equal_one = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(1)); It should_have_one_failing_partition = () => current_stream_processor_state.FailingPartitions.Count.ShouldEqual(1); It should_have_the_correct_failing_partition = () => current_stream_processor_state.FailingPartitions.ContainsKey(partition_id).ShouldBeTrue(); - It should_have_the_correct_position_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].Position.ShouldEqual(new StreamPosition(0)); + It should_have_the_correct_position_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].Position.StreamPosition.ShouldEqual(new StreamPosition(0)); It should_have_the_correct_reason_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].Reason.ShouldEqual(failure_reason); It should_have_the_correct_retry_time_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].RetryTime.ShouldBeGreaterThan(DateTimeOffset.UtcNow); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/a_stream_that_has_events_in_two_partitions/and_everything_is_ok.cs b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/a_stream_that_has_events_in_two_partitions/and_everything_is_ok.cs index a7ae87e73..469878007 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/a_stream_that_has_events_in_two_partitions/and_everything_is_ok.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/a_stream_that_has_events_in_two_partitions/and_everything_is_ok.cs @@ -7,7 +7,6 @@ using Dolittle.Runtime.Events.Processing.Streams.Partitioned.for_ScopedStreamProcessor.given; using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Rudimentary; using Machine.Specifications; using Moq; using It = Machine.Specifications.It; @@ -31,17 +30,17 @@ public class and_everything_is_ok : all_dependencies second_event = new StreamEvent(committed_events.single(), 1u, Guid.NewGuid(), second_partition_id, true); event_processor .Setup(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); setup_event_stream(first_event, second_event); }; - Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100), 0, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); + Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100), ProcessingPosition.Initial, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); It should_process_four_times = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Exactly(4)); It should_process_first_event_twice = () => event_processor.Verify(_ => _.Process(first_event.Event, first_partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Exactly(2)); It should_process_second_event_twice = () => event_processor.Verify(_ => _.Process(second_event.Event, second_partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Exactly(2)); It should_not_retry_processing = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Never); - It should_have_persisted_the_correct_position = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(2)); + It should_have_persisted_the_correct_position = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(2)); It should_not_have_failing_partition = () => current_stream_processor_state.FailingPartitions.Count.ShouldEqual(0); It should_perform_the_action = () => action_to_perform_before_reprocessing.Verify(_ => _(tenant_id, Moq.It.IsAny()), Times.Once); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/a_stream_that_has_events_in_two_partitions/and_performing_action_fails.cs b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/a_stream_that_has_events_in_two_partitions/and_performing_action_fails.cs index a07e350ab..e39aaf782 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/a_stream_that_has_events_in_two_partitions/and_performing_action_fails.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/a_stream_that_has_events_in_two_partitions/and_performing_action_fails.cs @@ -31,7 +31,7 @@ public class and_performing_action_fails : all_dependencies second_event = new StreamEvent(committed_events.single(), 1u, Guid.NewGuid(), second_partition_id, true); event_processor .Setup(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); setup_event_stream(first_event, second_event); action_to_perform_before_reprocessing @@ -39,13 +39,13 @@ public class and_performing_action_fails : all_dependencies .ReturnsAsync(Try.Failed(new Exception())); }; - Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100), 0, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); + Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100), ProcessingPosition.Initial, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); It should_process_two_times = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Exactly(2)); It should_not_process_first_event_twice = () => event_processor.Verify(_ => _.Process(first_event.Event, first_partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once); It should_not_process_second_event_twice = () => event_processor.Verify(_ => _.Process(second_event.Event, second_partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once); It should_not_retry_processing = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Never); - It should_have_persisted_the_correct_position = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(2)); + It should_have_persisted_the_correct_position = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(2)); It should_not_have_failing_partition = () => current_stream_processor_state.FailingPartitions.Count.ShouldEqual(0); It should_perform_the_action = () => action_to_perform_before_reprocessing.Verify(_ => _(tenant_id, Moq.It.IsAny()), Times.Once); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/a_stream_that_has_events_in_two_partitions/and_setting_position_after_a_failing_partition.cs b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/a_stream_that_has_events_in_two_partitions/and_setting_position_after_a_failing_partition.cs index 091c92c44..ab3900564 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/a_stream_that_has_events_in_two_partitions/and_setting_position_after_a_failing_partition.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/a_stream_that_has_events_in_two_partitions/and_setting_position_after_a_failing_partition.cs @@ -7,7 +7,6 @@ using Dolittle.Runtime.Events.Processing.Streams.Partitioned.for_ScopedStreamProcessor.given; using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Rudimentary; using Machine.Specifications; using Moq; using It = Machine.Specifications.It; @@ -34,19 +33,19 @@ public class and_processing_fails_at_second_event_in_both_partitions : all_depen .Returns(Task.FromResult(new FailedProcessing(reason))); event_processor .Setup(_ => _.Process(second_event.Event, Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); setup_event_stream(first_event, second_event); }; - Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100), 1, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); + Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100), new ProcessingPosition(1,1), action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); It should_process_first_event_once = () => event_processor.Verify(_ => _.Process(first_event.Event, first_partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once); It should_process_second_event_twice = () => event_processor.Verify(_ => _.Process(second_event.Event, second_partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Exactly(2)); It should_not_retry_processing = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Never); - It should_have_persisted_the_correct_position = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(2)); + It should_have_persisted_the_correct_position = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(2)); It should_have_persisted_state_with_one_failing_partitions = () => current_stream_processor_state.FailingPartitions.Count.ShouldEqual(1); It should_have_persisted_state_with_correct_failing_partition = () => current_stream_processor_state.FailingPartitions.ContainsKey(first_partition_id).ShouldBeTrue(); - It should_have_persisted_correct_position_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].Position.ShouldEqual(new StreamPosition(0)); + It should_have_persisted_correct_position_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].Position.ShouldEqual(ProcessingPosition.Initial); It should_have_persisted_correct_retry_time_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].RetryTime.ShouldEqual(DateTimeOffset.MaxValue); It should_have_persisted_correct_reason_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[first_partition_id].Reason.ShouldEqual(reason); It should_perform_the_action = () => action_to_perform_before_reprocessing.Verify(_ => _(tenant_id, Moq.It.IsAny()), Times.Once); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/and_stream_has_only_one_partition/and_event_processing_failed_at_second_event.cs b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/and_stream_has_only_one_partition/and_event_processing_failed_at_second_event.cs index 30f4434ea..0bee467d2 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/and_stream_has_only_one_partition/and_event_processing_failed_at_second_event.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/and_stream_has_only_one_partition/and_event_processing_failed_at_second_event.cs @@ -25,7 +25,7 @@ public class and_event_processing_failed_at_second_event : all_dependencies { event_processor .Setup(_ => _.Process(first_event, partition_id, Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); event_processor .Setup(_ => _.Process(second_event, partition_id, Moq.It.IsAny(), Moq.It.IsAny())) .Returns(Task.FromResult(new FailedProcessing(reason))); @@ -34,15 +34,15 @@ public class and_event_processing_failed_at_second_event : all_dependencies new StreamEvent(second_event, 1, Guid.NewGuid(), partition_id, true)); }; - Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100), 0, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); + Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100), ProcessingPosition.Initial, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); It should_process_four_events = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Exactly(4)); It should_process_first_event_twice = () => event_processor.Verify(_ => _.Process(first_event, partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Exactly(2)); It should_process_second_event_twice = () => event_processor.Verify(_ => _.Process(second_event, partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Exactly(2)); - It should_have_current_position_equal_2 = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(2)); + It should_have_current_position_equal_2 = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(2)); It should_have_one_failing_partition = () => current_stream_processor_state.FailingPartitions.Count.ShouldEqual(1); It should_have_the_correct_failing_partition = () => current_stream_processor_state.FailingPartitions.ContainsKey(partition_id).ShouldBeTrue(); - It should_have_the_correct_position_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].Position.ShouldEqual(new StreamPosition(1)); + It should_have_the_correct_position_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].Position.StreamPosition.ShouldEqual(new StreamPosition(1)); It should_have_the_correct_reason_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].Reason.ShouldEqual(reason); It should_have_the_correct_retry_time_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].RetryTime.ShouldEqual(DateTimeOffset.MaxValue); It should_perform_the_action = () => action_to_perform_before_reprocessing.Verify(_ => _(tenant_id, Moq.It.IsAny()), Times.Once); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/and_stream_has_only_one_partition/and_everything_is_ok.cs b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/and_stream_has_only_one_partition/and_everything_is_ok.cs index da8a971de..e00fc30ff 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/and_stream_has_only_one_partition/and_everything_is_ok.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/and_stream_has_only_one_partition/and_everything_is_ok.cs @@ -25,15 +25,15 @@ public class and_everything_is_ok : all_dependencies var event_with_partition = new StreamEvent(first_event, StreamPosition.Start, Guid.NewGuid(), partition_id, true); event_processor .Setup(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); setup_event_stream(event_with_partition); }; - Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100), 0, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); + Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100), ProcessingPosition.Initial, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); It should_process_two_event = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Exactly(2)); It should_process_first_event_twice = () => event_processor.Verify(_ => _.Process(first_event, partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Exactly(2)); - It should_have_current_position_equal_one = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(1)); + It should_have_current_position_equal_one = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(1)); It should_not_have_failing_partition = () => current_stream_processor_state.FailingPartitions.Count.ShouldEqual(0); It should_perform_the_action = () => action_to_perform_before_reprocessing.Verify(_ => _(tenant_id, Moq.It.IsAny()), Times.Once); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/and_stream_has_only_one_partition/and_performing_action_fails.cs b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/and_stream_has_only_one_partition/and_performing_action_fails.cs index fd4ceca2b..b9761a215 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/and_stream_has_only_one_partition/and_performing_action_fails.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/and_stream_has_only_one_partition/and_performing_action_fails.cs @@ -26,7 +26,7 @@ public class and_performing_action_fails : all_dependencies var event_with_partition = new StreamEvent(first_event, StreamPosition.Start, Guid.NewGuid(), partition_id, true); event_processor .Setup(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); setup_event_stream(event_with_partition); action_to_perform_before_reprocessing @@ -34,11 +34,11 @@ public class and_performing_action_fails : all_dependencies .ReturnsAsync(Try.Failed(new Exception())); }; - Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100), 0, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); + Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100), ProcessingPosition.Initial, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); It should_process_one_event = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once); It should_not_process_first_event_twice = () => event_processor.Verify(_ => _.Process(first_event, partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once); - It should_have_current_position_equal_one = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(1)); + It should_have_current_position_equal_one = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(1)); It should_not_have_failing_partition = () => current_stream_processor_state.FailingPartitions.Count.ShouldEqual(0); It should_perform_the_action = () => action_to_perform_before_reprocessing.Verify(_ => _(tenant_id, Moq.It.IsAny()), Times.Once); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/and_stream_has_only_one_partition/and_setting_position_to_failing_event.cs b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/and_stream_has_only_one_partition/and_setting_position_to_failing_event.cs index 20961c2a4..1039d2189 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/and_stream_has_only_one_partition/and_setting_position_to_failing_event.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_ScopedStreamProcessor/when_setting_position/and_stream_has_only_one_partition/and_setting_position_to_failing_event.cs @@ -7,7 +7,6 @@ using Dolittle.Runtime.Events.Processing.Streams.Partitioned.for_ScopedStreamProcessor.given; using Dolittle.Runtime.Events.Store; using Dolittle.Runtime.Events.Store.Streams; -using Dolittle.Runtime.Rudimentary; using Machine.Specifications; using Moq; using It = Machine.Specifications.It; @@ -30,13 +29,13 @@ public class and_setting_position_to_failing_event : all_dependencies setup_event_stream(new StreamEvent(first_event, 0, Guid.NewGuid(), partition_id, true)); }; - Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100), 0, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); + Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100), ProcessingPosition.Initial, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); It should_process_first_event_twice = () => event_processor.Verify(_ => _.Process(first_event, partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Exactly(2)); - It should_have_current_position_equal_one = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(1)); + It should_have_current_position_equal_one = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(1)); It should_have_one_failing_partition = () => current_stream_processor_state.FailingPartitions.Count.ShouldEqual(1); It should_have_the_correct_failing_partition = () => current_stream_processor_state.FailingPartitions.ContainsKey(partition_id).ShouldBeTrue(); - It should_have_the_correct_position_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].Position.ShouldEqual(new StreamPosition(0)); + It should_have_the_correct_position_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].Position.StreamPosition.ShouldEqual(new StreamPosition(0)); It should_have_the_correct_reason_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].Reason.ShouldEqual(failure_reason); It should_have_the_correct_retry_time_on_the_failing_partition = () => current_stream_processor_state.FailingPartitions[partition_id].RetryTime.ShouldBeGreaterThan(DateTimeOffset.UtcNow); It should_perform_the_action = () => action_to_perform_before_reprocessing.Verify(_ => _(tenant_id, Moq.It.IsAny()), Times.Once); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_StreamProcessorState/when_creating_state.cs b/Specifications/Events.Processing/Streams/Partitioned/for_StreamProcessorState/when_creating_state.cs index dcd6d2f7b..aca9c9f23 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_StreamProcessorState/when_creating_state.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_StreamProcessorState/when_creating_state.cs @@ -2,7 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Collections.Generic; +using System.Collections.Immutable; using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; @@ -10,15 +10,15 @@ namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned.for_StreamProce public class when_creating_state { - static StreamPosition stream_position; - static IDictionary failing_partitions; + static ProcessingPosition stream_position; + static ImmutableDictionary failing_partitions; static StreamProcessorState state; static DateTimeOffset last_successfully_processed; Establish context = () => { - stream_position = 0; - failing_partitions = new Dictionary(); + stream_position = ProcessingPosition.Initial; + failing_partitions = ImmutableDictionary.Empty; last_successfully_processed = DateTimeOffset.UtcNow; }; diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_TimeToRetryForPartitionedStreamProcessor/when_there_are_failing_partitions/and_earliest_retry_time_is_in_the_future.cs b/Specifications/Events.Processing/Streams/Partitioned/for_TimeToRetryForPartitionedStreamProcessor/when_there_are_failing_partitions/and_earliest_retry_time_is_in_the_future.cs index f87798bd6..899e955ba 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_TimeToRetryForPartitionedStreamProcessor/when_there_are_failing_partitions/and_earliest_retry_time_is_in_the_future.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_TimeToRetryForPartitionedStreamProcessor/when_there_are_failing_partitions/and_earliest_retry_time_is_in_the_future.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; @@ -10,21 +11,19 @@ namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned.for_TimeToRetry public class and_earliest_retry_time_is_in_the_future { - static TimeToRetryForPartitionedStreamProcessor time_to_retry_getter; - static IDictionary failing_partitions; + static ImmutableDictionary failing_partitions; static StreamProcessorState state; static bool success; static TimeSpan time_to_retry; Establish context = () => { - time_to_retry_getter = new TimeToRetryForPartitionedStreamProcessor(); failing_partitions = new Dictionary() { { "9b025684-130c-4789-b904-878a8e26c2d0", new FailingPartitionState( - 0, + 0,0, DateTimeOffset.UtcNow.AddSeconds(60), "reason", 0, @@ -33,7 +32,7 @@ public class and_earliest_retry_time_is_in_the_future { "6dde48c5-6c8f-4600-8f14-ef323d251f97", new FailingPartitionState( - 0, + 0,0, DateTimeOffset.UtcNow.AddSeconds(64), "reason", 0, @@ -42,17 +41,17 @@ public class and_earliest_retry_time_is_in_the_future { "da8f0a4a-eaeb-4490-8530-b7f75da332cb", new FailingPartitionState( - 0, + 0,0, DateTimeOffset.UtcNow.AddSeconds(78), "reason", 0, DateTimeOffset.UtcNow) } - }; - state = new StreamProcessorState(0, failing_partitions, DateTimeOffset.UtcNow); + }.ToImmutableDictionary(); + state = new StreamProcessorState(ProcessingPosition.Initial, failing_partitions, DateTimeOffset.UtcNow); }; - Because of = () => success = time_to_retry_getter.TryGetTimespanToRetry(state, out time_to_retry); + Because of = () => success = state.TryGetTimespanToRetry(out time_to_retry); It should_get_it = () => success.ShouldBeTrue(); It should_retry_in_the_future = () => time_to_retry.ShouldBeGreaterThan(TimeSpan.Zero); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_TimeToRetryForPartitionedStreamProcessor/when_there_are_failing_partitions/and_earliest_retry_time_is_in_the_past.cs b/Specifications/Events.Processing/Streams/Partitioned/for_TimeToRetryForPartitionedStreamProcessor/when_there_are_failing_partitions/and_earliest_retry_time_is_in_the_past.cs index f56762518..0761127d8 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_TimeToRetryForPartitionedStreamProcessor/when_there_are_failing_partitions/and_earliest_retry_time_is_in_the_past.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_TimeToRetryForPartitionedStreamProcessor/when_there_are_failing_partitions/and_earliest_retry_time_is_in_the_past.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; @@ -10,21 +11,19 @@ namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned.for_TimeToRetry public class and_earliest_retry_time_is_in_the_past { - static TimeToRetryForPartitionedStreamProcessor time_to_retry_getter; - static IDictionary failing_partitions; + static ImmutableDictionary failing_partitions; static StreamProcessorState state; static bool success; static TimeSpan time_to_retry; Establish context = () => { - time_to_retry_getter = new TimeToRetryForPartitionedStreamProcessor(); failing_partitions = new Dictionary() { { "9b025684-130c-4789-b904-878a8e26c2d0", new FailingPartitionState( - 0, + 0, 0, DateTimeOffset.UtcNow.AddSeconds(-10), "reason", 0, @@ -33,7 +32,7 @@ public class and_earliest_retry_time_is_in_the_past { "e90f7d42-0a21-4d90-93a8-e56bca822b67", new FailingPartitionState( - 0, + 0, 0, DateTimeOffset.UtcNow.AddSeconds(64), "reason", 0, @@ -42,17 +41,17 @@ public class and_earliest_retry_time_is_in_the_past { "36975349-318d-4c01-bbbb-4f1aeaf4e7ea", new FailingPartitionState( - 0, + 0, 0, DateTimeOffset.UtcNow.AddSeconds(78), "reason", 0, DateTimeOffset.UtcNow) } - }; - state = new StreamProcessorState(0, failing_partitions, DateTimeOffset.UtcNow); + }.ToImmutableDictionary(); + state = new StreamProcessorState(ProcessingPosition.Initial, failing_partitions, DateTimeOffset.UtcNow); }; - Because of = () => success = time_to_retry_getter.TryGetTimespanToRetry(state, out time_to_retry); + Because of = () => success = state.TryGetTimespanToRetry(out time_to_retry); It should_get_it = () => success.ShouldBeTrue(); It should_retry_now = () => time_to_retry.ShouldEqual(TimeSpan.Zero); diff --git a/Specifications/Events.Processing/Streams/Partitioned/for_TimeToRetryForPartitionedStreamProcessor/when_there_are_no_failing_partitions.cs b/Specifications/Events.Processing/Streams/Partitioned/for_TimeToRetryForPartitionedStreamProcessor/when_there_are_no_failing_partitions.cs index f95247f5a..090508f37 100644 --- a/Specifications/Events.Processing/Streams/Partitioned/for_TimeToRetryForPartitionedStreamProcessor/when_there_are_no_failing_partitions.cs +++ b/Specifications/Events.Processing/Streams/Partitioned/for_TimeToRetryForPartitionedStreamProcessor/when_there_are_no_failing_partitions.cs @@ -2,7 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Collections.Generic; +using System.Collections.Immutable; using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; @@ -10,18 +10,16 @@ namespace Dolittle.Runtime.Events.Processing.Streams.Partitioned.for_TimeToRetry public class when_there_are_no_failing_partitions { - static TimeToRetryForPartitionedStreamProcessor time_to_retry_getter; static StreamProcessorState state; static bool success; static TimeSpan time_to_retry; Establish context = () => { - time_to_retry_getter = new TimeToRetryForPartitionedStreamProcessor(); - state = new StreamProcessorState(0, new Dictionary(), DateTimeOffset.UtcNow); + state = new StreamProcessorState(ProcessingPosition.Initial, ImmutableDictionary.Empty, DateTimeOffset.UtcNow); }; - Because of = () => success = time_to_retry_getter.TryGetTimespanToRetry(state, out time_to_retry); + Because of = () => success = state.TryGetTimespanToRetry(out time_to_retry); It should_not_get_it = () => success.ShouldBeFalse(); It should_return_the_max_value_of_time_span = () => time_to_retry.ShouldEqual(TimeSpan.MaxValue); diff --git a/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/given/all_dependencies.cs b/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/given/all_dependencies.cs index a4cbcae9e..ea983d96a 100644 --- a/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/given/all_dependencies.cs +++ b/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/given/all_dependencies.cs @@ -26,7 +26,7 @@ public class all_dependencies protected static TenantId tenant_id; protected static StreamId source_stream_id; protected static StreamProcessorId stream_processor_id; - protected static IResilientStreamProcessorStateRepository stream_processor_state_repository; + protected static IStreamProcessorStates stream_processor_state_repository; protected static Mock events_fetcher; protected static Mock stream_processors; protected static Mock event_processor; @@ -37,13 +37,13 @@ public class all_dependencies Establish context = () => { cancellation_token_source = new CancellationTokenSource(); - var in_memory_stream_processor_state_repository = new in_memory_stream_processor_state_repository(); + var in_memory_stream_processor_states = new in_memory_stream_processor_states(); event_processor_id = Guid.NewGuid(); scope_id = Guid.NewGuid(); tenant_id = Guid.NewGuid(); source_stream_id = Guid.NewGuid(); stream_processor_id = new StreamProcessorId(scope_id, event_processor_id, source_stream_id); - stream_processor_state_repository = in_memory_stream_processor_state_repository; + stream_processor_state_repository = in_memory_stream_processor_states; events_fetcher = new Mock(MockBehavior.Strict); event_processor = new Mock(MockBehavior.Strict); event_processor.SetupGet(_ => _.Identifier).Returns(event_processor_id); @@ -62,13 +62,12 @@ public class all_dependencies execution_contexts.create(), new EventFetcherPolicies(Mock.Of()), event_waiter, - new TimeToRetryForUnpartitionedStreamProcessor(), Mock.Of>()); action_to_perform_before_reprocessing = new Mock>>(); action_to_perform_before_reprocessing .Setup(_ => _(It.IsAny(), It.IsAny())) - .ReturnsAsync(Try.Succeeded()); + .ReturnsAsync(Try.Succeeded); }; Cleanup clean = () => cancellation_token_source.Dispose(); @@ -78,7 +77,7 @@ protected static Task start_stream_processor_and_cancel_after(TimeSpan cancelAft cancellation_token_source.CancelAfter(cancelAfter); return stream_processor.Start(cancellation_token_source.Token); } - protected static Task start_stream_processor_set_position_after_and_cancel_after(TimeSpan setPositionAfter, StreamPosition position, Func> beforeReprocessingAction, TimeSpan cancelAfter) + protected static Task start_stream_processor_set_position_after_and_cancel_after(TimeSpan setPositionAfter, ProcessingPosition position, Func> beforeReprocessingAction, TimeSpan cancelAfter) { var result = stream_processor.Start(cancellation_token_source.Token); Task.Delay(setPositionAfter).GetAwaiter().GetResult(); diff --git a/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_processing/and_event_processing_failed_at_first_event.cs b/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_processing/and_event_processing_failed_at_first_event.cs index 546e57be7..8f5538af2 100644 --- a/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_processing/and_event_processing_failed_at_first_event.cs +++ b/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_processing/and_event_processing_failed_at_first_event.cs @@ -31,7 +31,7 @@ public class and_event_processing_failed_at_first_event : given.all_dependencies It should_process_one_event = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once()); It should_process_first_event = () => event_processor.Verify(_ => _.Process(first_event, partition_id, Moq.It.IsAny(),Moq.It.IsAny()), Moq.Times.Once()); - It should_have_current_position_equal_zero = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(0)); + It should_have_current_position_equal_zero = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(0)); It should_be_failing = () => current_stream_processor_state.IsFailing.ShouldBeTrue(); It should_have_the_correct_retry_time = () => current_stream_processor_state.RetryTime.ShouldEqual(DateTimeOffset.MaxValue); It should_have_the_correct_reason = () => current_stream_processor_state.FailureReason.ShouldEqual(reason); diff --git a/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_processing/and_event_processing_failed_at_second_event.cs b/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_processing/and_event_processing_failed_at_second_event.cs index 02c0a0236..61405042b 100644 --- a/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_processing/and_event_processing_failed_at_second_event.cs +++ b/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_processing/and_event_processing_failed_at_second_event.cs @@ -22,7 +22,7 @@ public class and_event_processing_failed_at_second_event : given.all_dependencie { event_processor .Setup(_ => _.Process(first_event, partition_id, Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); event_processor .Setup(_ => _.Process(second_event, partition_id, Moq.It.IsAny(),Moq.It.IsAny())) .Returns(Task.FromResult(new FailedProcessing(reason))); @@ -37,7 +37,7 @@ public class and_event_processing_failed_at_second_event : given.all_dependencie It should_process_two_events = () => event_processor.Verify(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(),Moq.It.IsAny()), Moq.Times.Exactly(2)); It should_process_first_event = () => event_processor.Verify(_ => _.Process(first_event, partition_id, Moq.It.IsAny(),Moq.It.IsAny()), Moq.Times.Once()); It should_process_second_event = () => event_processor.Verify(_ => _.Process(second_event, partition_id, Moq.It.IsAny(),Moq.It.IsAny()), Moq.Times.Once()); - It should_have_current_position_equal_one = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(1)); + It should_have_current_position_equal_one = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(1)); It should_be_failing = () => current_stream_processor_state.IsFailing.ShouldBeTrue(); It should_have_the_correct_retry_time = () => current_stream_processor_state.RetryTime.ShouldEqual(DateTimeOffset.MaxValue); It should_have_the_correct_reason = () => current_stream_processor_state.FailureReason.ShouldEqual(reason); diff --git a/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_processing/and_stream_processor_must_retry_processing_an_event_three_times.cs b/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_processing/and_stream_processor_must_retry_processing_an_event_three_times.cs index afc04519c..08cc92a71 100644 --- a/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_processing/and_stream_processor_must_retry_processing_an_event_three_times.cs +++ b/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_processing/and_stream_processor_must_retry_processing_an_event_three_times.cs @@ -48,7 +48,7 @@ public class and_stream_processor_must_retry_processing_an_event_three_times : g It should_retry_processing_first_event_first_time_with_correct_reason = () => event_processor.Verify(_ => _.Process(first_event, partition_id, retry_reason, 0, Moq.It.IsAny(),Moq.It.IsAny()), Moq.Times.Once); It should_retry_processing_first_event_second_time_with_correct_reason = () => event_processor.Verify(_ => _.Process(first_event, partition_id, retry_reason, 1, Moq.It.IsAny(),Moq.It.IsAny()), Moq.Times.Once); It should_retry_processing_first_event_third_time_with_correct_reason = () => event_processor.Verify(_ => _.Process(first_event, partition_id, retry_reason, 2, Moq.It.IsAny(),Moq.It.IsAny()), Moq.Times.Once); - It should_have_current_position_equal_zero = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(0)); + It should_have_current_position_equal_zero = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(0)); It should_be_failing = () => current_stream_processor_state.IsFailing.ShouldBeTrue(); It should_have_the_correct_retry_time = () => current_stream_processor_state.RetryTime.ShouldEqual(DateTimeOffset.MaxValue); It should_have_the_correct_reason = () => current_stream_processor_state.FailureReason.ShouldEqual(failure_reason); diff --git a/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_processing/stream_with_one_event/and_everything_is_ok.cs b/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_processing/stream_with_one_event/and_everything_is_ok.cs index ab29fe873..80637890d 100644 --- a/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_processing/stream_with_one_event/and_everything_is_ok.cs +++ b/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_processing/stream_with_one_event/and_everything_is_ok.cs @@ -21,14 +21,14 @@ public class and_everything_is_ok : given.all_dependencies var event_with_partition = new StreamEvent(first_event, StreamPosition.Start, Guid.NewGuid(), partition_id, false); event_processor .Setup(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); setup_event_stream(event_with_partition); }; Because of = () => start_stream_processor_and_cancel_after(TimeSpan.FromMilliseconds(500)).GetAwaiter().GetResult(); It should_process_first_event = () => event_processor.Verify(_ => _.Process(first_event, partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once()); - It should_have_current_position_equal_one = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(1)); + It should_have_current_position_equal_one = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(1)); It should_not_be_failing = () => current_stream_processor_state.IsFailing.ShouldBeFalse(); - It should_try_fetching_next_event = () => events_fetcher.Verify(_ => _.Fetch((ulong)1, Moq.It.IsAny()), Moq.Times.Once); + It should_try_fetching_next_event = () => events_fetcher.Verify(_ => _.Fetch(1, Moq.It.IsAny()), Moq.Times.Once); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_setting_position/and_everything_is_ok.cs b/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_setting_position/and_everything_is_ok.cs index da2ff3786..2857f2405 100644 --- a/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_setting_position/and_everything_is_ok.cs +++ b/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_setting_position/and_everything_is_ok.cs @@ -24,16 +24,16 @@ public class and_everything_is_ok : all_dependencies var event_with_partition = new StreamEvent(first_event, StreamPosition.Start, Guid.NewGuid(), partition_id, false); event_processor .Setup(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); setup_event_stream(event_with_partition); }; - Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100),0, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); + Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100),ProcessingPosition.Initial, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); It should_process_event_twice = () => event_processor.Verify(_ => _.Process(first_event, partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Exactly(2)); - It should_fetch_event_twice = () => events_fetcher.Verify(_ => _.Fetch((ulong)0, Moq.It.IsAny()), Moq.Times.Exactly(2)); - It should_have_current_position_equal_one = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(1)); + It should_fetch_event_twice = () => events_fetcher.Verify(_ => _.Fetch(0, Moq.It.IsAny()), Moq.Times.Exactly(2)); + It should_have_current_position_equal_one = () => current_stream_processor_state.Position.StreamPosition.ShouldEqual(new StreamPosition(1)); It should_not_be_failing = () => current_stream_processor_state.IsFailing.ShouldBeFalse(); - It should_try_fetching_next_event = () => events_fetcher.Verify(_ => _.Fetch((ulong)1, Moq.It.IsAny()), Moq.Times.AtLeastOnce); + It should_try_fetching_next_event = () => events_fetcher.Verify(_ => _.Fetch(1, Moq.It.IsAny()), Moq.Times.AtLeastOnce); It should_perform_the_action = () => action_to_perform_before_reprocessing.Verify(_ => _(tenant_id, Moq.It.IsAny()), Times.Once); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_setting_position/and_performing_action_fails.cs b/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_setting_position/and_performing_action_fails.cs index 6ee577f3d..aa7dfbfef 100644 --- a/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_setting_position/and_performing_action_fails.cs +++ b/Specifications/Events.Processing/Streams/for_ScopedStreamProcessor/when_setting_position/and_performing_action_fails.cs @@ -25,7 +25,7 @@ public class and_performing_action_fails : all_dependencies var event_with_partition = new StreamEvent(first_event, StreamPosition.Start, Guid.NewGuid(), partition_id, false); event_processor .Setup(_ => _.Process(Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny(), Moq.It.IsAny())) - .Returns(Task.FromResult(new SuccessfulProcessing())); + .Returns(Task.FromResult(SuccessfulProcessing.Instance)); setup_event_stream(event_with_partition); action_to_perform_before_reprocessing @@ -33,12 +33,12 @@ public class and_performing_action_fails : all_dependencies .ReturnsAsync(Try.Failed(new Exception())); }; - Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100),0, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); + Because of = () => start_stream_processor_set_position_after_and_cancel_after(TimeSpan.FromMilliseconds(100),ProcessingPosition.Initial, action_to_perform_before_reprocessing.Object, TimeSpan.FromMilliseconds(50)).GetAwaiter().GetResult(); It should_not_process_event_again = () => event_processor.Verify(_ => _.Process(first_event, partition_id, Moq.It.IsAny(), Moq.It.IsAny()), Moq.Times.Once); - It should_not_fetch_event_again = () => events_fetcher.Verify(_ => _.Fetch((ulong)0, Moq.It.IsAny()), Moq.Times.Once); - It should_have_current_position_equal_one = () => current_stream_processor_state.Position.ShouldEqual(new StreamPosition(1)); + It should_not_fetch_event_again = () => events_fetcher.Verify(_ => _.Fetch(0, Moq.It.IsAny()), Moq.Times.Once); + It should_have_current_position_equal_one = () => current_stream_processor_state.Position.ShouldEqual(new ProcessingPosition(1,1)); It should_not_be_failing = () => current_stream_processor_state.IsFailing.ShouldBeFalse(); - It should_try_fetching_next_event = () => events_fetcher.Verify(_ => _.Fetch((ulong)1, Moq.It.IsAny()), Moq.Times.AtLeastOnce); + It should_try_fetching_next_event = () => events_fetcher.Verify(_ => _.Fetch(1, Moq.It.IsAny()), Moq.Times.AtLeastOnce); It should_perform_the_action = () => action_to_perform_before_reprocessing.Verify(_ => _(tenant_id, Moq.It.IsAny()), Times.Once); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Streams/for_StreamProcessor/given/all_dependencies.cs b/Specifications/Events.Processing/Streams/for_StreamProcessor/given/all_dependencies.cs index 2ae10a6d2..3f5b8628b 100644 --- a/Specifications/Events.Processing/Streams/for_StreamProcessor/given/all_dependencies.cs +++ b/Specifications/Events.Processing/Streams/for_StreamProcessor/given/all_dependencies.cs @@ -8,7 +8,6 @@ using Dolittle.Runtime.Domain.Tenancy; using Dolittle.Runtime.Events.Store.Streams; using Dolittle.Runtime.Events.Store.Streams.Filters; -using Dolittle.Runtime.Execution; using Dolittle.Runtime.Tenancy; using Machine.Specifications; using Microsoft.Extensions.Logging; diff --git a/Specifications/Events.Processing/Streams/for_StreamProcessorState/when_creating_failing_state.cs b/Specifications/Events.Processing/Streams/for_StreamProcessorState/when_creating_failing_state.cs index 607ad4901..108d2b740 100644 --- a/Specifications/Events.Processing/Streams/for_StreamProcessorState/when_creating_failing_state.cs +++ b/Specifications/Events.Processing/Streams/for_StreamProcessorState/when_creating_failing_state.cs @@ -9,7 +9,7 @@ namespace Dolittle.Runtime.Events.Processing.Streams.for_StreamProcessorState; public class when_creating_failing_state { - static StreamPosition stream_position; + static ProcessingPosition processing_position; static string failure_reason; static DateTimeOffset retry_time; static uint processing_attempts; @@ -17,15 +17,15 @@ public class when_creating_failing_state Establish context = () => { - stream_position = 0; + processing_position = ProcessingPosition.Initial; failure_reason = ""; retry_time = DateTimeOffset.UtcNow; processing_attempts = 0; }; - Because of = () => state = new StreamProcessorState(stream_position, failure_reason, retry_time, processing_attempts, DateTimeOffset.MinValue, false); + Because of = () => state = new StreamProcessorState(processing_position, failure_reason, retry_time, processing_attempts, DateTimeOffset.MinValue, false); - It should_have_the_correct_stream_position = () => state.Position.ShouldEqual(stream_position); + It should_have_the_correct_stream_position = () => state.Position.ShouldEqual(processing_position); It should_have_the_correct_failure_reason = () => state.FailureReason.ShouldEqual(failure_reason); It should_have_the_correct_retry_time = () => state.RetryTime.ShouldEqual(retry_time); It should_have_the_correct_processing_attempts = () => state.ProcessingAttempts.ShouldEqual(processing_attempts); diff --git a/Specifications/Events.Processing/Streams/for_StreamProcessorState/when_creating_state.cs b/Specifications/Events.Processing/Streams/for_StreamProcessorState/when_creating_state.cs index 75cafa15c..57b086ba2 100644 --- a/Specifications/Events.Processing/Streams/for_StreamProcessorState/when_creating_state.cs +++ b/Specifications/Events.Processing/Streams/for_StreamProcessorState/when_creating_state.cs @@ -9,15 +9,15 @@ namespace Dolittle.Runtime.Events.Processing.Streams.for_StreamProcessorState; public class when_creating_state { - static StreamPosition stream_position; + static ProcessingPosition processing_position; static StreamProcessorState state; Establish context = () => { - stream_position = 0; + processing_position = ProcessingPosition.Initial; }; - Because of = () => state = new StreamProcessorState(stream_position, DateTimeOffset.UtcNow); + Because of = () => state = new StreamProcessorState(processing_position, DateTimeOffset.UtcNow); - It should_have_the_correct_stream_position = () => state.Position.ShouldEqual(stream_position); + It should_have_the_correct_stream_position = () => state.Position.ShouldEqual(processing_position); } \ No newline at end of file diff --git a/Specifications/Events.Processing/Streams/for_TimeToRetryForUnpartitionedStreamProcessor/when_failing/and_retry_time_is_in_the_future.cs b/Specifications/Events.Processing/Streams/for_TimeToRetryForUnpartitionedStreamProcessor/when_failing/and_retry_time_is_in_the_future.cs index 366c1887e..4c1902d6e 100644 --- a/Specifications/Events.Processing/Streams/for_TimeToRetryForUnpartitionedStreamProcessor/when_failing/and_retry_time_is_in_the_future.cs +++ b/Specifications/Events.Processing/Streams/for_TimeToRetryForUnpartitionedStreamProcessor/when_failing/and_retry_time_is_in_the_future.cs @@ -2,24 +2,23 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; namespace Dolittle.Runtime.Events.Processing.Streams.for_TimeToRetryForUnpartitionedStreamProcessor.when_failing; public class and_retry_time_is_in_the_future { - static TimeToRetryForUnpartitionedStreamProcessor time_to_retry_getter; static StreamProcessorState state; static bool success; static TimeSpan time_to_retry; Establish context = () => { - time_to_retry_getter = new TimeToRetryForUnpartitionedStreamProcessor(); - state = new StreamProcessorState(0, "reason", DateTimeOffset.UtcNow.AddSeconds(60), 0, DateTimeOffset.UtcNow, true); + state = new StreamProcessorState(ProcessingPosition.Initial, "reason", DateTimeOffset.UtcNow.AddSeconds(60), 0, DateTimeOffset.UtcNow, true); }; - Because of = () => success = time_to_retry_getter.TryGetTimespanToRetry(state, out time_to_retry); + Because of = () => success = state.TryGetTimespanToRetry(out time_to_retry); It should_get_it = () => success.ShouldBeTrue(); It should_retry_in_the_future = () => time_to_retry.ShouldBeGreaterThan(TimeSpan.Zero); diff --git a/Specifications/Events.Processing/Streams/for_TimeToRetryForUnpartitionedStreamProcessor/when_failing/and_retry_time_is_in_the_past.cs b/Specifications/Events.Processing/Streams/for_TimeToRetryForUnpartitionedStreamProcessor/when_failing/and_retry_time_is_in_the_past.cs index da82876c5..36ac8cdc4 100644 --- a/Specifications/Events.Processing/Streams/for_TimeToRetryForUnpartitionedStreamProcessor/when_failing/and_retry_time_is_in_the_past.cs +++ b/Specifications/Events.Processing/Streams/for_TimeToRetryForUnpartitionedStreamProcessor/when_failing/and_retry_time_is_in_the_past.cs @@ -2,24 +2,23 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; namespace Dolittle.Runtime.Events.Processing.Streams.for_TimeToRetryForUnpartitionedStreamProcessor.when_failing; public class and_retry_time_is_in_the_past { - static TimeToRetryForUnpartitionedStreamProcessor time_to_retry_getter; static StreamProcessorState state; static bool success; static TimeSpan time_to_retry; Establish context = () => { - time_to_retry_getter = new TimeToRetryForUnpartitionedStreamProcessor(); - state = new StreamProcessorState(0, "reason", DateTimeOffset.UtcNow.AddSeconds(-10), 0, DateTimeOffset.UtcNow, true); + state = new StreamProcessorState(ProcessingPosition.Initial, "reason", DateTimeOffset.UtcNow.AddSeconds(-10), 0, DateTimeOffset.UtcNow, true); }; - Because of = () => success = time_to_retry_getter.TryGetTimespanToRetry(state, out time_to_retry); + Because of = () => success = state.TryGetTimespanToRetry(out time_to_retry); It should_get_it = () => success.ShouldBeTrue(); It should_retry_now = () => time_to_retry.ShouldEqual(TimeSpan.Zero); diff --git a/Specifications/Events.Processing/Streams/for_TimeToRetryForUnpartitionedStreamProcessor/when_failing/with_retriable_failure.cs b/Specifications/Events.Processing/Streams/for_TimeToRetryForUnpartitionedStreamProcessor/when_failing/with_retriable_failure.cs new file mode 100644 index 000000000..2e6211b12 --- /dev/null +++ b/Specifications/Events.Processing/Streams/for_TimeToRetryForUnpartitionedStreamProcessor/when_failing/with_retriable_failure.cs @@ -0,0 +1,40 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Dolittle.Runtime.Events.Store.Streams; +using Machine.Specifications; +using It = Machine.Specifications.It; + +namespace Dolittle.Runtime.Events.Processing.Streams.for_TimeToRetryForUnpartitionedStreamProcessor.when_failing; + +public class with_retriable_failure +{ + static StreamProcessorState before; + static IStreamProcessorState state; + static bool success; + static TimeSpan time_to_retry; + static DateTimeOffset at; + static StreamEvent stream_event; + + + + private Establish context = () => + { + stream_event = new StreamEvent(committed_events.single(), 0, Guid.Empty, "partition", false); + + var position = ProcessingPosition.Initial.IncrementWithStream(); + + at = DateTimeOffset.UtcNow; + before = new StreamProcessorState(ProcessingPosition.Initial, DateTimeOffset.UtcNow); + var failedProcessing = new FailedProcessing("testing", true, TimeSpan.FromSeconds(5)); + state = ((IStreamProcessorState)before).WithResult(failedProcessing, stream_event, at); + + }; + + Because of = () => success = state.TryGetTimespanToRetry(out time_to_retry); + + It should_get_it = () => success.ShouldBeTrue(); + It should_get_the_correct_delay = () => time_to_retry.ShouldBeGreaterThan(TimeSpan.FromSeconds(4)); + It should_not_be_higher_than_original_delay = () => time_to_retry.ShouldBeLessThan(TimeSpan.FromSeconds(5)); +} \ No newline at end of file diff --git a/Specifications/Events.Processing/Streams/for_TimeToRetryForUnpartitionedStreamProcessor/when_it_is_not_failing.cs b/Specifications/Events.Processing/Streams/for_TimeToRetryForUnpartitionedStreamProcessor/when_it_is_not_failing.cs index f8b6d10dc..726b9d1fb 100644 --- a/Specifications/Events.Processing/Streams/for_TimeToRetryForUnpartitionedStreamProcessor/when_it_is_not_failing.cs +++ b/Specifications/Events.Processing/Streams/for_TimeToRetryForUnpartitionedStreamProcessor/when_it_is_not_failing.cs @@ -2,24 +2,23 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using Dolittle.Runtime.Events.Store.Streams; using Machine.Specifications; namespace Dolittle.Runtime.Events.Processing.Streams.for_TimeToRetryForUnpartitionedStreamProcessor; public class when_it_is_not_failing { - static TimeToRetryForUnpartitionedStreamProcessor time_to_retry_getter; static StreamProcessorState state; static bool success; static TimeSpan time_to_retry; Establish context = () => { - time_to_retry_getter = new TimeToRetryForUnpartitionedStreamProcessor(); - state = new StreamProcessorState(0, DateTimeOffset.UtcNow); + state = new StreamProcessorState(ProcessingPosition.Initial, DateTimeOffset.UtcNow); }; - Because of = () => success = time_to_retry_getter.TryGetTimespanToRetry(state, out time_to_retry); + Because of = () => success = state.TryGetTimespanToRetry(out time_to_retry); It should_not_get_it = () => success.ShouldBeFalse(); It should_return_the_max_value_of_time_span = () => time_to_retry.ShouldEqual(TimeSpan.MaxValue); diff --git a/Specifications/Events.Processing/committed_events.cs b/Specifications/Events.Processing/committed_events.cs index a4e18ed64..9ebabe76e 100644 --- a/Specifications/Events.Processing/committed_events.cs +++ b/Specifications/Events.Processing/committed_events.cs @@ -10,7 +10,7 @@ namespace Dolittle.Runtime.Events.Processing; public static class committed_events { public static CommittedEvent single() => single(EventLogSequenceNumber.Initial); - + public static CommittedEvent single(EventLogSequenceNumber event_log_sequence_number) => single(event_log_sequence_number, "{\"something\":42}"); public static CommittedEvent single(string content) => single(EventLogSequenceNumber.Initial, content); public static CommittedEvent single(EventLogSequenceNumber event_log_sequence_number, string content) => new( diff --git a/Specifications/Events.Processing/in_memory_stream_processor_state_repository.cs b/Specifications/Events.Processing/in_memory_stream_processor_state_repository.cs index 93d30f50c..1afa1ea10 100644 --- a/Specifications/Events.Processing/in_memory_stream_processor_state_repository.cs +++ b/Specifications/Events.Processing/in_memory_stream_processor_state_repository.cs @@ -1,35 +1,48 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Dolittle.Runtime.Rudimentary; using Dolittle.Runtime.Events.Processing.Streams; using Dolittle.Runtime.Events.Store.Streams; -using System; +using Dolittle.Runtime.Events.Store; +using Dolittle.Runtime.Rudimentary; namespace Dolittle.Runtime.Events.Processing; -public class in_memory_stream_processor_state_repository : IResilientStreamProcessorStateRepository +public class in_memory_stream_processor_state_repository : IStreamProcessorStateRepository { readonly Dictionary states = new(); - public Task Persist(IStreamProcessorId streamProcessorId, IStreamProcessorState streamProcessorState, CancellationToken cancellationToken) - { - states[streamProcessorId as StreamProcessorId] = streamProcessorState; - return Task.CompletedTask; - } - public Task> TryGetFor(IStreamProcessorId streamProcessorId, CancellationToken cancellationToken) + public Task> TryGet(StreamProcessorId streamProcessorId, CancellationToken cancellationToken) { - if (states.ContainsKey(streamProcessorId as StreamProcessorId)) + if (states.TryGetValue(streamProcessorId, out var state)) { - return Task.FromResult(Try.Succeeded(states[streamProcessorId as StreamProcessorId])); + return Task.FromResult(Try.Succeeded(state)); } - else + + return Task.FromResult(Try.Failed(new Exception())); + } + + public IAsyncEnumerable> GetForScope(ScopeId scopeId, + CancellationToken cancellationToken) => throw new System.NotImplementedException(); + + public async Task PersistForScope(ScopeId scope, IReadOnlyDictionary streamProcessorStates, + CancellationToken cancellationToken) + { + await Task.Yield(); + + foreach (var (streamProcessorId, streamProcessorState) in streamProcessorStates) { - return Task.FromResult(Try.Failed(new Exception())); + states[streamProcessorId] = streamProcessorState; } + + return Try.Succeeded; } + + public IAsyncEnumerable> GetNonScoped(CancellationToken cancellationToken) => + GetForScope(ScopeId.Default, cancellationToken); } \ No newline at end of file diff --git a/Specifications/Events.Processing/in_memory_stream_processor_states.cs b/Specifications/Events.Processing/in_memory_stream_processor_states.cs new file mode 100644 index 000000000..2bd9488eb --- /dev/null +++ b/Specifications/Events.Processing/in_memory_stream_processor_states.cs @@ -0,0 +1,30 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Rudimentary; +using Dolittle.Runtime.Events.Store.Streams; +using System; +using System.Collections.Concurrent; + +namespace Dolittle.Runtime.Events.Processing; + +public class in_memory_stream_processor_states : IStreamProcessorStates +{ + readonly ConcurrentDictionary states = new(); + + public async Task> TryGetFor(IStreamProcessorId streamProcessorId, CancellationToken cancellationToken) + { + await Task.Yield(); + return states.TryGetValue(streamProcessorId, out var state) + ? Try.Succeeded(state) + : Try.Failed(new Exception()); + } + + public async Task Persist(IStreamProcessorId streamProcessorId, IStreamProcessorState streamProcessorState, CancellationToken cancellationToken) + { + states[streamProcessorId] = streamProcessorState; + await Task.Yield(); + } +} \ No newline at end of file diff --git a/Specifications/Events.Store.MongoDB/Events/for_ExecutionContext/when_creating.cs b/Specifications/Events.Store.MongoDB/Events/for_ExecutionContext/when_creating.cs index 00078bd3b..d096907d7 100644 --- a/Specifications/Events.Store.MongoDB/Events/for_ExecutionContext/when_creating.cs +++ b/Specifications/Events.Store.MongoDB/Events/for_ExecutionContext/when_creating.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using Dolittle.Runtime.Execution; using Machine.Specifications; namespace Dolittle.Runtime.Events.Store.MongoDB.Events.for_ExecutionContext; diff --git a/Specifications/Events.Store.MongoDB/Persistence/for_UpdateAggregateVersionsAfterCommit/when_commit_has/no_committed_aggregate_events.cs b/Specifications/Events.Store.MongoDB/Persistence/for_UpdateAggregateVersionsAfterCommit/when_commit_has/no_committed_aggregate_events.cs index 1fef39ae7..8975357b9 100644 --- a/Specifications/Events.Store.MongoDB/Persistence/for_UpdateAggregateVersionsAfterCommit/when_commit_has/no_committed_aggregate_events.cs +++ b/Specifications/Events.Store.MongoDB/Persistence/for_UpdateAggregateVersionsAfterCommit/when_commit_has/no_committed_aggregate_events.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Machine.Specifications; -using Moq; using It = Machine.Specifications.It; namespace Dolittle.Runtime.Events.Store.MongoDB.Persistence.for_UpdateAggregateVersionsAfterCommit.when_commit_has; diff --git a/Specifications/Events.Store/Events.Store.csproj b/Specifications/Events.Store/Events.Store.csproj index a4571aad3..ad4119584 100755 --- a/Specifications/Events.Store/Events.Store.csproj +++ b/Specifications/Events.Store/Events.Store.csproj @@ -12,7 +12,8 @@ - + + diff --git a/Specifications/Events.Store/Streams/for_EventWaiter/given/an_event_waiter.cs b/Specifications/Events.Store/Streams/for_EventWaiter/given/an_event_waiter.cs deleted file mode 100644 index 85dc1b369..000000000 --- a/Specifications/Events.Store/Streams/for_EventWaiter/given/an_event_waiter.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Store.Streams.for_EventWaiter.given; - -public class an_event_waiter -{ - protected static ScopeId scope; - protected static StreamId stream; - protected static EventWaiter event_waiter; - - Establish context = () => - { - scope = new ScopeId(Guid.Parse("9e0370f7-d1ed-4a2c-94af-45243fab0be6")); - stream = Guid.Parse("07690cac-45cd-4aa4-bd45-de28f8e27661"); - event_waiter = new EventWaiter(scope, stream); - }; -} \ No newline at end of file diff --git a/Specifications/Events.Store/Streams/for_EventWaiter/when_creating.cs b/Specifications/Events.Store/Streams/for_EventWaiter/when_creating.cs deleted file mode 100644 index c378edc71..000000000 --- a/Specifications/Events.Store/Streams/for_EventWaiter/when_creating.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Store.Streams.for_EventWaiter; - -public class when_creating -{ - static ScopeId scope; - static StreamId stream; - static EventWaiterId expected_id; - static EventWaiter result; - - Establish context = () => - { - scope = new ScopeId(Guid.Parse("9e0370f7-d1ed-4a2c-94af-45243fab0be6")); - stream = Guid.Parse("07690cac-45cd-4aa4-bd45-de28f8e27661"); - expected_id = new EventWaiterId(scope, stream); - }; - - Because of = () => result = new EventWaiter(scope, stream); - - It should_have_the_correct_id = () => result.Id.ShouldEqual(expected_id); -} \ No newline at end of file diff --git a/Specifications/Events.Store/Streams/for_EventWaiter/when_trying_to_provoke_dead_lock.cs b/Specifications/Events.Store/Streams/for_EventWaiter/when_trying_to_provoke_dead_lock.cs deleted file mode 100644 index 59f408c82..000000000 --- a/Specifications/Events.Store/Streams/for_EventWaiter/when_trying_to_provoke_dead_lock.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Threading; -using System.Threading.Tasks; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Store.Streams.for_EventWaiter; - -public class when_trying_to_provoke_dead_lock : given.an_event_waiter -{ - static CancellationTokenSource token_source; - static CancellationToken token; - - Establish context = () => - { - token_source = new CancellationTokenSource(); - token = token_source.Token; - }; - - Because of = () => - { - token_source.CancelAfter(TimeSpan.FromSeconds(3)); - try - { - dead_lock().Wait(); - } - catch (Exception) - { - } - - }; - - It should_not_be_a_dead_lock = () => token_source.IsCancellationRequested.ShouldBeFalse(); - - Cleanup clean = () => - { - token_source.Cancel(); - token_source.Dispose(); - }; - - static async Task dead_lock() - { - var first_wait = event_waiter.Wait(0, token).ConfigureAwait(false); - _ = Task.Run(() => - { - event_waiter.Notify(0); - }); - await first_wait; - var second_wait = event_waiter.Wait(1, token); - _ = Task.Run(() => - { - event_waiter.Notify(1); - }); - second_wait.Wait(); - } -} \ No newline at end of file diff --git a/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_a_later_position_is_later_notified.cs b/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_a_later_position_is_later_notified.cs deleted file mode 100644 index 41f56a5e3..000000000 --- a/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_a_later_position_is_later_notified.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Store.Streams.for_EventWaiter.when_waiting_for_10ms; - -public class and_a_later_position_is_later_notified : given.an_event_waiter -{ - static StreamPosition last_position; - static CancellationTokenSource token_source; - static CancellationToken token; - static IList tasks; - - Establish context = () => - { - token_source = new CancellationTokenSource(); - token = token_source.Token; - last_position = 3; - tasks = new List(); - }; - - Because of = () => - { - for (ulong i = 0; i <= last_position.Value; i++) - { - tasks.Add(event_waiter.Wait(i, token)); - } - - event_waiter.Notify(last_position.Value + 1); - Thread.Sleep(100); - }; - - It should_be_done_waiting_for_all_events = () => tasks.ShouldEachConformTo(_ => _.IsCompletedSuccessfully); - - Cleanup clean = () => - { - token_source.Cancel(); - token_source.Dispose(); - }; -} \ No newline at end of file diff --git a/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_has_already_been_notified.cs b/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_has_already_been_notified.cs deleted file mode 100644 index 9aa6aa5c6..000000000 --- a/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_has_already_been_notified.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Store.Streams.for_EventWaiter.when_waiting_for_10ms; - -public class and_has_already_been_notified : given.an_event_waiter -{ - static StreamPosition position; - static CancellationTokenSource token_source; - static CancellationToken token; - static Task result; - - Establish context = () => - { - position = 2; - token_source = new CancellationTokenSource(); - token = token_source.Token; - event_waiter.Notify(position); - }; - - Because of = () => - { - result = event_waiter.Wait(position, token); - Thread.Sleep(100); - }; - - It should_be_done_waiting_for_event = () => result.IsCompleted.ShouldBeTrue(); - - Cleanup clean = () => - { - token_source.Cancel(); - token_source.Dispose(); - }; -} \ No newline at end of file diff --git a/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_is_later_notified.cs b/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_is_later_notified.cs deleted file mode 100644 index 2c603d87d..000000000 --- a/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_is_later_notified.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Store.Streams.for_EventWaiter.when_waiting_for_10ms; - -public class and_is_later_notified : given.an_event_waiter -{ - static StreamPosition position; - static CancellationTokenSource token_source; - static CancellationToken token; - static Task result; - - Establish context = () => - { - position = 2; - token_source = new CancellationTokenSource(); - token = token_source.Token; - }; - - Because of = () => - { - result = event_waiter.Wait(position, token); - event_waiter.Notify(position); - Thread.Sleep(100); - }; - - It should_be_done_waiting_for_event = () => result.IsCompleted.ShouldBeTrue(); - - Cleanup clean = () => - { - token_source.Cancel(); - token_source.Dispose(); - }; -} \ No newline at end of file diff --git a/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_it_is_never_notified.cs b/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_it_is_never_notified.cs deleted file mode 100644 index 7a36f798e..000000000 --- a/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_it_is_never_notified.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Store.Streams.for_EventWaiter.when_waiting_for_10ms; - -public class and_it_is_never_notified : given.an_event_waiter -{ - static StreamPosition position; - static CancellationTokenSource token_source; - static CancellationToken token; - static Task result; - - Establish context = () => - { - position = 2; - token_source = new CancellationTokenSource(); - token = token_source.Token; - }; - - Because of = () => - { - result = event_waiter.Wait(position, token); - Thread.Sleep(100); - }; - - It should_wait_for_event = () => result.IsCompleted.ShouldBeFalse(); - - Cleanup clean = () => - { - token_source.Cancel(); - token_source.Dispose(); - }; -} \ No newline at end of file diff --git a/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_later_position_has_been_notified.cs b/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_later_position_has_been_notified.cs deleted file mode 100644 index 43f45e5ac..000000000 --- a/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_later_position_has_been_notified.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Store.Streams.for_EventWaiter.when_waiting_for_10ms; - -public class and_later_position_has_been_notified : given.an_event_waiter -{ - static StreamPosition position; - static CancellationTokenSource token_source; - static CancellationToken token; - static Task result; - - Establish context = () => - { - position = 2; - token_source = new CancellationTokenSource(); - token = token_source.Token; - event_waiter.Notify(5); - }; - - Because of = () => - { - result = event_waiter.Wait(position, token); - Thread.Sleep(100); - }; - - It should_be_done_waiting_for_event = () => result.IsCompleted.ShouldBeTrue(); - - Cleanup clean = () => - { - token_source.Cancel(); - token_source.Dispose(); - }; -} \ No newline at end of file diff --git a/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_previous_positions_has_been_notified.cs b/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_previous_positions_has_been_notified.cs deleted file mode 100644 index d28f80aa8..000000000 --- a/Specifications/Events.Store/Streams/for_EventWaiter/when_waiting_for_10ms/and_previous_positions_has_been_notified.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Dolittle. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Threading.Tasks; -using Machine.Specifications; - -namespace Dolittle.Runtime.Events.Store.Streams.for_EventWaiter.when_waiting_for_10ms; - -public class and_previous_positions_has_been_notified : given.an_event_waiter -{ - static StreamPosition position; - static CancellationTokenSource token_source; - static CancellationToken token; - static Task result; - - Establish context = () => - { - position = 2; - token_source = new CancellationTokenSource(); - token = token_source.Token; - event_waiter.Notify(0); - event_waiter.Notify(1); - }; - - Because of = () => - { - result = event_waiter.Wait(position, token); - Thread.Sleep(100); - }; - - It should_wait_for_event = () => result.IsCompleted.ShouldBeFalse(); - - Cleanup clean = () => - { - token_source.Cancel(); - token_source.Dispose(); - }; -} \ No newline at end of file diff --git a/Specifications/Events.Store/Streams/for_StreamEvent/when_creating_stream_event.cs b/Specifications/Events.Store/Streams/for_StreamEvent/when_creating_stream_event.cs index 6a938f175..7863be50b 100644 --- a/Specifications/Events.Store/Streams/for_StreamEvent/when_creating_stream_event.cs +++ b/Specifications/Events.Store/Streams/for_StreamEvent/when_creating_stream_event.cs @@ -11,6 +11,7 @@ public class when_creating_stream_event static CommittedEvent committed_event; static StreamId stream; static StreamPosition stream_position; + static EventLogSequenceNumber event_log_sequence; static PartitionId partition; static StreamEvent stream_event; static bool partitioned; @@ -20,10 +21,11 @@ public class when_creating_stream_event { stream = Guid.NewGuid(); stream_position = 0; + event_log_sequence = 0; partition = "]≈[partitionfiß"; execution_context = execution_contexts.create(); committed_event = new CommittedEvent( - 0, + event_log_sequence, DateTimeOffset.Now, "event source∞§", execution_context, diff --git a/Specifications/Events/Events.csproj b/Specifications/Events/Events.csproj index 5d4d2558b..41ebea2ae 100755 --- a/Specifications/Events/Events.csproj +++ b/Specifications/Events/Events.csproj @@ -5,6 +5,7 @@ Dolittle.Runtime.Events.Specs + diff --git a/Specifications/Projections.Store.Services.Grpc/Projections.Store.Services.Grpc.csproj b/Specifications/Projections.Store.Services.Grpc/Projections.Store.Services.Grpc.csproj index 50fc98047..2d3a98c76 100755 --- a/Specifications/Projections.Store.Services.Grpc/Projections.Store.Services.Grpc.csproj +++ b/Specifications/Projections.Store.Services.Grpc/Projections.Store.Services.Grpc.csproj @@ -6,10 +6,6 @@ Dolittle.Runtime.Projections.Store.Services.Grpc.Specs - - - - diff --git a/Specifications/Projections.Store.Services.Grpc/for_ProjectionsGrpcService/given/the_service.cs b/Specifications/Projections.Store.Services.Grpc/for_ProjectionsGrpcService/given/the_service.cs index c5c14c5bb..d973d6f2e 100644 --- a/Specifications/Projections.Store.Services.Grpc/for_ProjectionsGrpcService/given/the_service.cs +++ b/Specifications/Projections.Store.Services.Grpc/for_ProjectionsGrpcService/given/the_service.cs @@ -1,8 +1,6 @@ // Copyright (c) Dolittle. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Dolittle.Runtime.Projections.Contracts; -using Dolittle.Runtime.Services; using Machine.Specifications; using Microsoft.Extensions.Logging.Abstractions; using Moq; diff --git a/Specifications/Projections.Store/Projections.Store.csproj b/Specifications/Projections.Store/Projections.Store.csproj index bca7c7612..515004f00 100755 --- a/Specifications/Projections.Store/Projections.Store.csproj +++ b/Specifications/Projections.Store/Projections.Store.csproj @@ -8,7 +8,7 @@ - + diff --git a/Specifications/Protobuf/for_Extensions/CallContext.cs b/Specifications/Protobuf/for_Extensions/CallContext.cs index 7760027f2..56fb62164 100644 --- a/Specifications/Protobuf/for_Extensions/CallContext.cs +++ b/Specifications/Protobuf/for_Extensions/CallContext.cs @@ -2,38 +2,44 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Grpc.Core; namespace Dolittle.Runtime.Protobuf.for_Extensions; + public class CallContext : ServerCallContext -{ - public CallContext() +{ + readonly Metadata _requestHeaders; + readonly CancellationToken _cancellationToken; + readonly Metadata _responseTrailers; + readonly AuthContext _authContext; + readonly Dictionary _userState; + WriteOptions? _writeOptions; + + public Metadata? ResponseHeaders { get; private set; } + + private CallContext(Metadata requestHeaders, CancellationToken cancellationToken) { - RequestHeadersCore = new Metadata(); + _requestHeaders = requestHeaders; + _cancellationToken = cancellationToken; + _responseTrailers = new Metadata(); + _authContext = new AuthContext(string.Empty, new Dictionary>()); + _userState = new Dictionary(); } - protected override string MethodCore => "SpecMethod"; - - protected override string HostCore => throw new NotImplementedException(); - - protected override string PeerCore => throw new NotImplementedException(); - - protected override DateTime DeadlineCore => throw new NotImplementedException(); - - protected override Metadata RequestHeadersCore { get; } - - protected override CancellationToken CancellationTokenCore => throw new NotImplementedException(); - - protected override Metadata ResponseTrailersCore => throw new NotImplementedException(); - - protected override Status StatusCore { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - - protected override WriteOptions WriteOptionsCore { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - - protected override AuthContext AuthContextCore => throw new NotImplementedException(); + protected override string MethodCore => "MethodName"; + protected override string HostCore => "HostName"; + protected override string PeerCore => "PeerName"; + protected override DateTime DeadlineCore { get; } + protected override Metadata RequestHeadersCore => _requestHeaders; + protected override CancellationToken CancellationTokenCore => _cancellationToken; + protected override Metadata ResponseTrailersCore => _responseTrailers; + protected override Status StatusCore { get; set; } + protected override WriteOptions? WriteOptionsCore { get => _writeOptions; set { _writeOptions = value; } } + protected override AuthContext AuthContextCore => _authContext; protected override ContextPropagationToken CreatePropagationTokenCore(ContextPropagationOptions options) { @@ -42,6 +48,19 @@ protected override ContextPropagationToken CreatePropagationTokenCore(ContextPro protected override Task WriteResponseHeadersAsyncCore(Metadata responseHeaders) { - throw new NotImplementedException(); + if (ResponseHeaders != null) + { + throw new InvalidOperationException("Response headers have already been written."); + } + + ResponseHeaders = responseHeaders; + return Task.CompletedTask; + } + + protected override IDictionary UserStateCore => _userState; + + public static CallContext Create(Metadata? requestHeaders = null, CancellationToken cancellationToken = default) + { + return new CallContext(requestHeaders ?? new Metadata(), cancellationToken); } } \ No newline at end of file diff --git a/Specifications/Rudimentary/for_TaskGroup/when_both_tasks_fail.cs b/Specifications/Rudimentary/for_TaskGroup/when_both_tasks_fail.cs index f35390260..34df08c26 100644 --- a/Specifications/Rudimentary/for_TaskGroup/when_both_tasks_fail.cs +++ b/Specifications/Rudimentary/for_TaskGroup/when_both_tasks_fail.cs @@ -13,14 +13,15 @@ public class when_both_tasks_fail : given.a_group_and_inputs { static Exception first_task_failure; static Exception second_task_failure; - - Establish context = () => + + private Establish context = () => { first_task_failure = new Exception(); second_task_failure = new Exception(); - first_task = Task.Delay(20).ContinueWith(_ => throw first_task_failure); - second_task = Task.Delay(10).ContinueWith(_ => throw second_task_failure); + first_task = Task.Delay(5).ContinueWith(_ => throw first_task_failure); + second_task = Task.Delay(1).ContinueWith(_ => throw second_task_failure); + }; It should_throw_the_first_exception = () => exception.ShouldBeTheSameAs(second_task_failure); diff --git a/Specifications/Rudimentary/for_TaskGroup/when_first_task_completes_first.cs b/Specifications/Rudimentary/for_TaskGroup/when_first_task_completes_first.cs index ee8920d28..8a66b25c3 100644 --- a/Specifications/Rudimentary/for_TaskGroup/when_first_task_completes_first.cs +++ b/Specifications/Rudimentary/for_TaskGroup/when_first_task_completes_first.cs @@ -14,6 +14,7 @@ public class when_first_task_completes_first : given.a_group_and_inputs { first_task = Task.Delay(10); second_task = Task.Delay(20); + second_task.GetAwaiter().GetResult(); }; It should_not_throw_an_exception = () => exception.ShouldBeNull(); diff --git a/Specifications/Services.Clients/for_ReverseCallClient/given/a_client/MyClient.cs b/Specifications/Services.Clients/for_ReverseCallClient/given/a_client/MyClient.cs index dfbd22a54..ce070f97b 100644 --- a/Specifications/Services.Clients/for_ReverseCallClient/given/a_client/MyClient.cs +++ b/Specifications/Services.Clients/for_ReverseCallClient/given/a_client/MyClient.cs @@ -7,7 +7,7 @@ namespace Dolittle.Runtime.Services.Clients.for_ReverseCallClient.given.a_client; -public class MyClient : ClientBase +public class MyClient : Grpc.Core.ClientBase { readonly Mock> _server_stream; readonly Mock> _client_stream; diff --git a/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_server_stream_is_empty.cs b/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_server_stream_is_empty.cs index 27d95f295..e64284110 100644 --- a/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_server_stream_is_empty.cs +++ b/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_server_stream_is_empty.cs @@ -3,7 +3,6 @@ using System.Threading; using System.Threading.Tasks; -using Dolittle.Runtime.Services.Clients.for_ReverseCallClient.given; using Dolittle.Runtime.Services.Clients.for_ReverseCallClient.given.a_client; using Machine.Specifications; diff --git a/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_server_stream_responds_with_connect_response.cs b/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_server_stream_responds_with_connect_response.cs index f1fc81dbc..457b051ab 100644 --- a/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_server_stream_responds_with_connect_response.cs +++ b/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_server_stream_responds_with_connect_response.cs @@ -3,7 +3,6 @@ using System.Threading; using System.Threading.Tasks; -using Dolittle.Runtime.Services.Clients.for_ReverseCallClient.given; using Dolittle.Runtime.Services.Clients.for_ReverseCallClient.given.a_client; using Machine.Specifications; diff --git a/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_server_stream_responds_with_unexpected_response.cs b/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_server_stream_responds_with_unexpected_response.cs index f87c85bfb..5d5bc168d 100644 --- a/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_server_stream_responds_with_unexpected_response.cs +++ b/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_server_stream_responds_with_unexpected_response.cs @@ -3,7 +3,6 @@ using System.Threading; using System.Threading.Tasks; -using Dolittle.Runtime.Services.Clients.for_ReverseCallClient.given; using Dolittle.Runtime.Services.Clients.for_ReverseCallClient.given.a_client; using Machine.Specifications; diff --git a/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_the_ping_times_out.cs b/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_the_ping_times_out.cs index 256e3c96d..c9f395a2e 100644 --- a/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_the_ping_times_out.cs +++ b/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_the_ping_times_out.cs @@ -3,7 +3,6 @@ using System; using System.Threading; -using Dolittle.Runtime.Services.Clients.for_ReverseCallClient.given; using Dolittle.Runtime.Services.Clients.for_ReverseCallClient.given.a_client; using Grpc.Core; using Machine.Specifications; diff --git a/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_the_server_stream_sends_2_pings_and_a_response.cs b/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_the_server_stream_sends_2_pings_and_a_response.cs index 40925cfe2..878b238f7 100644 --- a/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_the_server_stream_sends_2_pings_and_a_response.cs +++ b/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/and_the_server_stream_sends_2_pings_and_a_response.cs @@ -3,7 +3,6 @@ using System.Threading; using System.Threading.Tasks; -using Dolittle.Runtime.Services.Clients.for_ReverseCallClient.given; using Dolittle.Runtime.Services.Clients.for_ReverseCallClient.given.a_client; using Dolittle.Services.Contracts; using Machine.Specifications; diff --git a/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/multiple_times.cs b/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/multiple_times.cs index 9b62661e3..1a27669de 100644 --- a/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/multiple_times.cs +++ b/Specifications/Services.Clients/for_ReverseCallClient/when_connecting/multiple_times.cs @@ -4,7 +4,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using Dolittle.Runtime.Services.Clients.for_ReverseCallClient.given; using Dolittle.Runtime.Services.Clients.for_ReverseCallClient.given.a_client; using Machine.Specifications; diff --git a/Specifications/Services/ReverseCall/for_PingedConnection/given/Scenario.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/given/Scenario.cs similarity index 92% rename from Specifications/Services/ReverseCall/for_PingedConnection/given/Scenario.cs rename to Specifications/Services/ReverseCalls/for_PingedConnection/given/Scenario.cs index 597f7f58a..d74fd2466 100644 --- a/Specifications/Services/ReverseCall/for_PingedConnection/given/Scenario.cs +++ b/Specifications/Services/ReverseCalls/for_PingedConnection/given/Scenario.cs @@ -6,11 +6,16 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Dolittle.Runtime.Actors; using Dolittle.Runtime.Services.Callbacks; +using Dolittle.Runtime.Services.Configuration; using Dolittle.Runtime.Services.ReverseCalls.given; using Grpc.Core; using Machine.Specifications; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Moq; +using Proto; namespace Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.given; @@ -137,6 +142,12 @@ public void Simulate( IMetricsCollector metrics, ILoggerFactory loggerFactory) { + var factory = new ReverseCallStreamWriterFactory( + new ActorSystem(), + Mock.Of(), + new OptionsWrapper(new ReverseCallsConfiguration{UseActors = false}), + metrics, + loggerFactory); _simulatedTime = 0; _writtenMessages = new List>(); _receivedMessages = new List>(); @@ -148,8 +159,9 @@ public void Simulate( var fakeKeepaliveDeadline = new SimulatedKeepaliveDeadline(this); var fakeCallbackScheduler = new SimulatedCallbackScheduler(this); - var connection = new PingedConnection( + _connection = new PingedConnection( requestId, + factory, new SimulatedStreamReader(this), new SimulatedStreamWriter(this), context, @@ -158,11 +170,10 @@ public void Simulate( fakeCallbackScheduler, metrics, loggerFactory); + + ConnectionCancellationToken = _connection.CancellationToken; - _connectionWriter = connection.ClientStream; - ConnectionCancellationToken = connection.CancellationToken; - - var reader = ReadAllConnectionOutputs(connection); + var reader = ReadAllConnectionOutputs(_connection); var time = 0; var currentStepIndex = 0; @@ -186,7 +197,9 @@ public void Simulate( Thread.Sleep(10); } - IAsyncStreamWriter _connectionWriter; + + private PingedConnection _connection; + IAsyncStreamWriter _connectionWriter => _connection.ClientStream; public CancellationToken ConnectionCancellationToken { get; private set; } diff --git a/Specifications/Services/ReverseCall/for_PingedConnection/when_disposing_after_pings_have_started.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_disposing_after_pings_have_started.cs similarity index 85% rename from Specifications/Services/ReverseCall/for_PingedConnection/when_disposing_after_pings_have_started.cs rename to Specifications/Services/ReverseCalls/for_PingedConnection/when_disposing_after_pings_have_started.cs index 6badbe1ca..2cc9666bb 100644 --- a/Specifications/Services/ReverseCall/for_PingedConnection/when_disposing_after_pings_have_started.cs +++ b/Specifications/Services/ReverseCalls/for_PingedConnection/when_disposing_after_pings_have_started.cs @@ -2,13 +2,17 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using Dolittle.Runtime.Actors; using Dolittle.Runtime.Services.Callbacks; +using Dolittle.Runtime.Services.Configuration; using Dolittle.Runtime.Services.ReverseCalls.given; using Dolittle.Services.Contracts; using Google.Protobuf.WellKnownTypes; using Grpc.Core; using Machine.Specifications; +using Microsoft.Extensions.Options; using Moq; +using Proto; using It = Machine.Specifications.It; namespace Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection; @@ -42,9 +46,15 @@ public class when_disposing_after_pings_have_started : all_dependencies callback_scheduler .Setup(_ => _.ScheduleCallback(Moq.It.IsAny(), Moq.It.IsAny())) .Returns(scheduled_callback.Object); - + var factory = new ReverseCallStreamWriterFactory( + new ActorSystem(), + Mock.Of(), + new OptionsWrapper(new ReverseCallsConfiguration{UseActors = false}), + metrics, + logger_factory); connection = new PingedConnection( request_id, + factory, an_async_stream_reader .that() .receives(message_with_call_arguments), diff --git a/Specifications/Services/ReverseCall/for_PingedConnection/when_first_read_fails.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_first_read_fails.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_PingedConnection/when_first_read_fails.cs rename to Specifications/Services/ReverseCalls/for_PingedConnection/when_first_read_fails.cs diff --git a/Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_12_seconds/and_next_message_is_received_after_35_seconds.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_12_seconds/and_next_message_is_received_after_35_seconds.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_12_seconds/and_next_message_is_received_after_35_seconds.cs rename to Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_12_seconds/and_next_message_is_received_after_35_seconds.cs diff --git a/Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_12_seconds/and_next_message_is_received_after_36_seconds.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_12_seconds/and_next_message_is_received_after_36_seconds.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_12_seconds/and_next_message_is_received_after_36_seconds.cs rename to Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_12_seconds/and_next_message_is_received_after_36_seconds.cs diff --git a/Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_12_seconds/and_no_further_messages_are_received.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_12_seconds/and_no_further_messages_are_received.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_12_seconds/and_no_further_messages_are_received.cs rename to Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_12_seconds/and_no_further_messages_are_received.cs diff --git a/Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_12_seconds/given/all_dependencies.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_12_seconds/given/all_dependencies.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_12_seconds/given/all_dependencies.cs rename to Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_12_seconds/given/all_dependencies.cs diff --git a/Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_5_seconds/and_a_message_is_received_after_7_seconds.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_5_seconds/and_a_message_is_received_after_7_seconds.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_5_seconds/and_a_message_is_received_after_7_seconds.cs rename to Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_5_seconds/and_a_message_is_received_after_7_seconds.cs diff --git a/Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_5_seconds/and_many_messages_are_sent_and_received.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_5_seconds/and_many_messages_are_sent_and_received.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_5_seconds/and_many_messages_are_sent_and_received.cs rename to Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_5_seconds/and_many_messages_are_sent_and_received.cs diff --git a/Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_5_seconds/and_next_message_is_received_after_16_seconds.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_5_seconds/and_next_message_is_received_after_16_seconds.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_5_seconds/and_next_message_is_received_after_16_seconds.cs rename to Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_5_seconds/and_next_message_is_received_after_16_seconds.cs diff --git a/Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_5_seconds/and_no_further_messages_are_received.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_5_seconds/and_no_further_messages_are_received.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_5_seconds/and_no_further_messages_are_received.cs rename to Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_5_seconds/and_no_further_messages_are_received.cs diff --git a/Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_5_seconds/given/all_dependencies.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_5_seconds/given/all_dependencies.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_PingedConnection/when_pings_are_requested_every_5_seconds/given/all_dependencies.cs rename to Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_requested_every_5_seconds/given/all_dependencies.cs diff --git a/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_turned_off/and_a_message_is_received_after_7_seconds.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_turned_off/and_a_message_is_received_after_7_seconds.cs new file mode 100644 index 000000000..1858462c0 --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_turned_off/and_a_message_is_received_after_7_seconds.cs @@ -0,0 +1,31 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.given; +using Dolittle.Runtime.Services.ReverseCalls.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.when_pings_are_turned_off; + +public class and_a_message_is_received_after_7_seconds : given.all_dependencies +{ + Establish context = () => + { + scenario = Scenario.New(_ => + { + _.Receive.Message(first_message_with_0_second_pings).AtTime(10); + _.Receive.Message(new a_message()).AtTime(17); + }); + }; + + Because of = () => scenario.Simulate( + request_id, + server_call_context, + message_converter.Object, + metrics, + logger_factory); + + It should_not_schedule_a_ping_callback = () => scenario.ScheduledCallbacks.ShouldBeEmpty(); + It should_not_have_written_anything = () => scenario.WrittenMessageTimes.ShouldBeEmpty(); + It should_not_have_refreshed_the_token = () => scenario.RefreshedTokenTimes.ShouldBeEmpty(); +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_turned_off/and_many_messages_are_sent_and_received.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_turned_off/and_many_messages_are_sent_and_received.cs new file mode 100644 index 000000000..395f1898c --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_turned_off/and_many_messages_are_sent_and_received.cs @@ -0,0 +1,42 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.given; +using Dolittle.Runtime.Services.ReverseCalls.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.when_pings_are_turned_off; + +public class and_many_messages_are_sent_and_received : given.all_dependencies +{ + static a_message first_message_to_send; + static a_message second_message_to_send; + + Establish context = () => + { + first_message_to_send = new a_message(); + second_message_to_send = new a_message(); + + scenario = Scenario.New(_ => + { + _.Receive.Message(first_message_with_0_second_pings).AtTime(5); + _.Receive.Message(new a_message()).AtTime(10); + _.Send.Message(first_message_to_send).AtTime(12); + _.Receive.Message(new a_message()).AtTime(14); + _.Send.Message(second_message_to_send).AtTime(20); + _.Receive.Message(new a_message()).AtTime(22); + }); + }; + + Because of = () => scenario.Simulate( + request_id, + server_call_context, + message_converter.Object, + metrics, + logger_factory); + + It should_not_schedule_a_ping_callback = () => scenario.ScheduledCallbacks.ShouldBeEmpty(); + It should_have_written_messages = () => scenario.WrittenMessageTimes.ShouldContainOnly(12, 20); + It should_not_have_refreshed_the_token = () => scenario.RefreshedTokenTimes.ShouldBeEmpty(); + It should_have_sent_the_two_messages = () => scenario.WrittenMessages.ShouldContainOnly(first_message_to_send, second_message_to_send); +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_turned_off/and_next_message_is_received_after_16_seconds.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_turned_off/and_next_message_is_received_after_16_seconds.cs new file mode 100644 index 000000000..c15afd733 --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_turned_off/and_next_message_is_received_after_16_seconds.cs @@ -0,0 +1,32 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.given; +using Dolittle.Runtime.Services.ReverseCalls.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.when_pings_are_turned_off; + +public class and_next_message_is_received_after_16_seconds : given.all_dependencies +{ + Establish context = () => + { + scenario = Scenario.New(_ => + { + _.Receive.Message(first_message_with_0_second_pings).AtTime(12); + _.Receive.Message(new a_message()).AtTime(28); + }); + }; + + Because of = () => scenario.Simulate( + request_id, + server_call_context, + message_converter.Object, + metrics, + logger_factory); + + It should_not_schedule_a_ping_callback = () => scenario.ScheduledCallbacks.ShouldBeEmpty(); + It should_not_have_written_pings = () => scenario.WrittenMessageTimes.ShouldBeEmpty(); + It should_not_have_refreshed_the_token = () => scenario.RefreshedTokenTimes.ShouldBeEmpty(); + It should_not_cancel_the_cancellation_token = () => scenario.ConnectionCancellationToken.IsCancellationRequested.ShouldBeFalse(); +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_turned_off/and_no_further_messages_are_received.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_turned_off/and_no_further_messages_are_received.cs new file mode 100644 index 000000000..d11331d91 --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_turned_off/and_no_further_messages_are_received.cs @@ -0,0 +1,28 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.when_pings_are_turned_off; + +public class and_no_further_messages_are_received : given.all_dependencies +{ + Establish context = () => + { + scenario = Scenario.New(_ => + { + _.Receive.Message(first_message_with_0_second_pings).AtTime(6); + }); + }; + + Because of = () => scenario.Simulate( + request_id, + server_call_context, + message_converter.Object, + metrics, + logger_factory); + + It should_not_schedule_a_ping_callback = () => scenario.ScheduledCallbacks.ShouldBeEmpty(); + It should_not_have_refreshed_the_token = () => scenario.RefreshedTokenTimes.ShouldBeEmpty(); +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_turned_off/given/all_dependencies.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_turned_off/given/all_dependencies.cs new file mode 100644 index 000000000..38895772b --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_are_turned_off/given/all_dependencies.cs @@ -0,0 +1,35 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.given; +using Dolittle.Runtime.Services.ReverseCalls.given; +using Dolittle.Services.Contracts; +using Google.Protobuf.WellKnownTypes; +using Machine.Specifications; +using mother_of_all_dependencies = Dolittle.Runtime.Services.ReverseCalls.given.all_dependencies; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.when_pings_are_turned_off.given; + +public class all_dependencies : mother_of_all_dependencies +{ + protected static Scenario scenario; + protected static a_message first_message_with_0_second_pings; + + Establish context = () => + { + first_message_with_0_second_pings = new a_message(); + var first_message_connect_arguments = new object(); + var first_message_arguments_context = new ReverseCallArgumentsContext() + { + PingInterval = Duration.FromTimeSpan(TimeSpan.Zero), + }; + + message_converter + .Setup(_ => _.GetConnectArguments(first_message_with_0_second_pings)) + .Returns(first_message_connect_arguments); + message_converter + .Setup(_ => _.GetArgumentsContext(first_message_connect_arguments)) + .Returns(first_message_arguments_context); + }; +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_duration_is_set_to_max/and_a_message_is_received_after_7_seconds.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_duration_is_set_to_max/and_a_message_is_received_after_7_seconds.cs new file mode 100644 index 000000000..5d735d02a --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_duration_is_set_to_max/and_a_message_is_received_after_7_seconds.cs @@ -0,0 +1,31 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.given; +using Dolittle.Runtime.Services.ReverseCalls.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.when_pings_duration_is_set_to_max; + +public class and_a_message_is_received_after_7_seconds : given.all_dependencies +{ + Establish context = () => + { + scenario = Scenario.New(_ => + { + _.Receive.Message(first_message_with_0_second_pings).AtTime(10); + _.Receive.Message(new a_message()).AtTime(17); + }); + }; + + Because of = () => scenario.Simulate( + request_id, + server_call_context, + message_converter.Object, + metrics, + logger_factory); + + It should_not_schedule_a_ping_callback = () => scenario.ScheduledCallbacks.ShouldBeEmpty(); + It should_not_have_written_anything = () => scenario.WrittenMessageTimes.ShouldBeEmpty(); + It should_not_have_refreshed_the_token = () => scenario.RefreshedTokenTimes.ShouldBeEmpty(); +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_duration_is_set_to_max/and_many_messages_are_sent_and_received.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_duration_is_set_to_max/and_many_messages_are_sent_and_received.cs new file mode 100644 index 000000000..2221ff1f6 --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_duration_is_set_to_max/and_many_messages_are_sent_and_received.cs @@ -0,0 +1,42 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.given; +using Dolittle.Runtime.Services.ReverseCalls.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.when_pings_duration_is_set_to_max; + +public class and_many_messages_are_sent_and_received : given.all_dependencies +{ + static a_message first_message_to_send; + static a_message second_message_to_send; + + Establish context = () => + { + first_message_to_send = new a_message(); + second_message_to_send = new a_message(); + + scenario = Scenario.New(_ => + { + _.Receive.Message(first_message_with_0_second_pings).AtTime(5); + _.Receive.Message(new a_message()).AtTime(10); + _.Send.Message(first_message_to_send).AtTime(12); + _.Receive.Message(new a_message()).AtTime(14); + _.Send.Message(second_message_to_send).AtTime(20); + _.Receive.Message(new a_message()).AtTime(22); + }); + }; + + Because of = () => scenario.Simulate( + request_id, + server_call_context, + message_converter.Object, + metrics, + logger_factory); + + It should_not_schedule_a_ping_callback = () => scenario.ScheduledCallbacks.ShouldBeEmpty(); + It should_have_written_messages = () => scenario.WrittenMessageTimes.ShouldContainOnly(12, 20); + It should_not_have_refreshed_the_token = () => scenario.RefreshedTokenTimes.ShouldBeEmpty(); + It should_have_sent_the_two_messages = () => scenario.WrittenMessages.ShouldContainOnly(first_message_to_send, second_message_to_send); +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_duration_is_set_to_max/and_next_message_is_received_after_16_seconds.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_duration_is_set_to_max/and_next_message_is_received_after_16_seconds.cs new file mode 100644 index 000000000..b3da1838b --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_duration_is_set_to_max/and_next_message_is_received_after_16_seconds.cs @@ -0,0 +1,32 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.given; +using Dolittle.Runtime.Services.ReverseCalls.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.when_pings_duration_is_set_to_max; + +public class and_next_message_is_received_after_16_seconds : given.all_dependencies +{ + Establish context = () => + { + scenario = Scenario.New(_ => + { + _.Receive.Message(first_message_with_0_second_pings).AtTime(12); + _.Receive.Message(new a_message()).AtTime(28); + }); + }; + + Because of = () => scenario.Simulate( + request_id, + server_call_context, + message_converter.Object, + metrics, + logger_factory); + + It should_not_schedule_a_ping_callback = () => scenario.ScheduledCallbacks.ShouldBeEmpty(); + It should_not_have_written_pings = () => scenario.WrittenMessageTimes.ShouldBeEmpty(); + It should_not_have_refreshed_the_token = () => scenario.RefreshedTokenTimes.ShouldBeEmpty(); + It should_not_cancel_the_cancellation_token = () => scenario.ConnectionCancellationToken.IsCancellationRequested.ShouldBeFalse(); +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_duration_is_set_to_max/and_no_further_messages_are_received.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_duration_is_set_to_max/and_no_further_messages_are_received.cs new file mode 100644 index 000000000..cef0285df --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_duration_is_set_to_max/and_no_further_messages_are_received.cs @@ -0,0 +1,28 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.when_pings_duration_is_set_to_max; + +public class and_no_further_messages_are_received : given.all_dependencies +{ + Establish context = () => + { + scenario = Scenario.New(_ => + { + _.Receive.Message(first_message_with_0_second_pings).AtTime(6); + }); + }; + + Because of = () => scenario.Simulate( + request_id, + server_call_context, + message_converter.Object, + metrics, + logger_factory); + + It should_not_schedule_a_ping_callback = () => scenario.ScheduledCallbacks.ShouldBeEmpty(); + It should_not_have_refreshed_the_token = () => scenario.RefreshedTokenTimes.ShouldBeEmpty(); +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_duration_is_set_to_max/given/all_dependencies.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_duration_is_set_to_max/given/all_dependencies.cs new file mode 100644 index 000000000..d34890e1f --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_PingedConnection/when_pings_duration_is_set_to_max/given/all_dependencies.cs @@ -0,0 +1,35 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.given; +using Dolittle.Runtime.Services.ReverseCalls.given; +using Dolittle.Services.Contracts; +using Google.Protobuf.WellKnownTypes; +using Machine.Specifications; +using mother_of_all_dependencies = Dolittle.Runtime.Services.ReverseCalls.given.all_dependencies; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_PingedConnection.when_pings_duration_is_set_to_max.given; + +public class all_dependencies : mother_of_all_dependencies +{ + protected static Scenario scenario; + protected static a_message first_message_with_0_second_pings; + + Establish context = () => + { + first_message_with_0_second_pings = new a_message(); + var first_message_connect_arguments = new object(); + var first_message_arguments_context = new ReverseCallArgumentsContext() + { + PingInterval = Duration.FromTimeSpan(TimeSpan.Zero), + }; + + message_converter + .Setup(_ => _.GetConnectArguments(first_message_with_0_second_pings)) + .Returns(first_message_connect_arguments); + message_converter + .Setup(_ => _.GetArgumentsContext(first_message_connect_arguments)) + .Returns(first_message_arguments_context); + }; +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCall/for_PingedConnection/when_receiving_no_messages.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_receiving_no_messages.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_PingedConnection/when_receiving_no_messages.cs rename to Specifications/Services/ReverseCalls/for_PingedConnection/when_receiving_no_messages.cs diff --git a/Specifications/Services/ReverseCall/for_PingedConnection/when_reverse_call_context_is_not_received.cs b/Specifications/Services/ReverseCalls/for_PingedConnection/when_reverse_call_context_is_not_received.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_PingedConnection/when_reverse_call_context_is_not_received.cs rename to Specifications/Services/ReverseCalls/for_PingedConnection/when_reverse_call_context_is_not_received.cs diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/given/a_wrapped_stream_writer.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/given/a_wrapped_stream_writer.cs similarity index 65% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/given/a_wrapped_stream_writer.cs rename to Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/given/a_wrapped_stream_writer.cs index b4f3dde8c..586e0e448 100644 --- a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/given/a_wrapped_stream_writer.cs +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/given/a_wrapped_stream_writer.cs @@ -6,18 +6,17 @@ using Machine.Specifications; using Moq; -namespace Dolittle.Runtime.Services.ReverseCalls.for_WrappedAsyncStreamWriter.given; +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriter.given; public class a_wrapped_stream_writer : all_dependencies { protected static Mock> original_writer; - protected static WrappedAsyncStreamWriter wrapped_writer; + protected static ReverseCallStreamWriter wrapped_writer; - Establish context = () => + private Establish context = () => { original_writer = new Mock>(); - - wrapped_writer = new WrappedAsyncStreamWriter( + wrapped_writer = new ReverseCallStreamWriter( request_id, original_writer.Object, message_converter.Object, diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_getting_write_options.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_getting_write_options.cs similarity index 90% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_getting_write_options.cs rename to Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_getting_write_options.cs index 9cdfd6b5b..f98120a67 100644 --- a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_getting_write_options.cs +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_getting_write_options.cs @@ -4,7 +4,7 @@ using Grpc.Core; using Machine.Specifications; -namespace Dolittle.Runtime.Services.ReverseCalls.for_WrappedAsyncStreamWriter; +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriter; public class when_getting_write_options : given.a_wrapped_stream_writer { diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_pinging/and_another_write_is_currently_blocking.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_pinging/and_another_write_is_currently_blocking.cs similarity index 91% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_pinging/and_another_write_is_currently_blocking.cs rename to Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_pinging/and_another_write_is_currently_blocking.cs index dc7e7b010..d0879379c 100644 --- a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_pinging/and_another_write_is_currently_blocking.cs +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_pinging/and_another_write_is_currently_blocking.cs @@ -8,7 +8,7 @@ using Moq; using It = Machine.Specifications.It; -namespace Dolittle.Runtime.Services.ReverseCalls.for_WrappedAsyncStreamWriter.when_pinging; +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriter.when_pinging; public class and_another_write_is_currently_blocking : given.a_wrapped_stream_writer { diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_pinging/and_writing_fails.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_pinging/and_writing_fails.cs similarity index 92% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_pinging/and_writing_fails.cs rename to Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_pinging/and_writing_fails.cs index 91f722344..e5f15b5ae 100644 --- a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_pinging/and_writing_fails.cs +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_pinging/and_writing_fails.cs @@ -7,7 +7,7 @@ using Dolittle.Services.Contracts; using Machine.Specifications; -namespace Dolittle.Runtime.Services.ReverseCalls.for_WrappedAsyncStreamWriter.when_pinging; +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriter.when_pinging; public class and_writing_fails : given.a_wrapped_stream_writer { diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_pinging/and_writing_succeeds.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_pinging/and_writing_succeeds.cs similarity index 91% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_pinging/and_writing_succeeds.cs rename to Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_pinging/and_writing_succeeds.cs index b583a9080..c02106dfb 100644 --- a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_pinging/and_writing_succeeds.cs +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_pinging/and_writing_succeeds.cs @@ -6,7 +6,7 @@ using Dolittle.Services.Contracts; using Machine.Specifications; -namespace Dolittle.Runtime.Services.ReverseCalls.for_WrappedAsyncStreamWriter.when_pinging; +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriter.when_pinging; public class and_writing_succeeds : given.a_wrapped_stream_writer { diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_setting_write_options.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_setting_write_options.cs similarity index 87% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_setting_write_options.cs rename to Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_setting_write_options.cs index d1ca8768f..07a7c7517 100644 --- a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_setting_write_options.cs +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_setting_write_options.cs @@ -4,7 +4,7 @@ using Grpc.Core; using Machine.Specifications; -namespace Dolittle.Runtime.Services.ReverseCalls.for_WrappedAsyncStreamWriter; +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriter; public class when_setting_write_options : given.a_wrapped_stream_writer { diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_writing/and_writing_fails.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_writing/and_writing_fails.cs similarity index 91% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_writing/and_writing_fails.cs rename to Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_writing/and_writing_fails.cs index 38715bff1..019c2c7df 100644 --- a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_writing/and_writing_fails.cs +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_writing/and_writing_fails.cs @@ -6,7 +6,7 @@ using Dolittle.Runtime.Services.ReverseCalls.given; using Machine.Specifications; -namespace Dolittle.Runtime.Services.ReverseCalls.for_WrappedAsyncStreamWriter.when_writing; +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriter.when_writing; public class and_writing_fails : given.a_wrapped_stream_writer { diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_writing/and_writing_fails_once_then_succeeds.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_writing/and_writing_fails_once_then_succeeds.cs similarity index 94% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_writing/and_writing_fails_once_then_succeeds.cs rename to Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_writing/and_writing_fails_once_then_succeeds.cs index 83b02bd33..edbc66a30 100644 --- a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_writing/and_writing_fails_once_then_succeeds.cs +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_writing/and_writing_fails_once_then_succeeds.cs @@ -6,7 +6,7 @@ using Dolittle.Runtime.Services.ReverseCalls.given; using Machine.Specifications; -namespace Dolittle.Runtime.Services.ReverseCalls.for_WrappedAsyncStreamWriter.when_writing; +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriter.when_writing; public class and_writing_fails_once_then_succeeds : given.a_wrapped_stream_writer { diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_writing/and_writing_succeeds.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_writing/and_writing_succeeds.cs similarity index 89% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_writing/and_writing_succeeds.cs rename to Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_writing/and_writing_succeeds.cs index 2a16e18c5..0b1e9f27e 100644 --- a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_writing/and_writing_succeeds.cs +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_writing/and_writing_succeeds.cs @@ -5,7 +5,7 @@ using Dolittle.Runtime.Services.ReverseCalls.given; using Machine.Specifications; -namespace Dolittle.Runtime.Services.ReverseCalls.for_WrappedAsyncStreamWriter.when_writing; +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriter.when_writing; public class and_writing_succeeds : given.a_wrapped_stream_writer { diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_writing/concurrently.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_writing/concurrently.cs similarity index 97% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_writing/concurrently.cs rename to Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_writing/concurrently.cs index 041291884..105356665 100644 --- a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamWriter/when_writing/concurrently.cs +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriter/when_writing/concurrently.cs @@ -6,7 +6,7 @@ using Dolittle.Runtime.Services.ReverseCalls.given; using Machine.Specifications; -namespace Dolittle.Runtime.Services.ReverseCalls.for_WrappedAsyncStreamWriter.when_writing; +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriter.when_writing; public class concurrently : given.a_wrapped_stream_writer { @@ -55,7 +55,7 @@ public class concurrently : given.a_wrapped_stream_writer static bool second_write_third_check; static bool third_write_third_check; - Because of = () => + private Because of = () => { Task first_write_status = wrapped_writer.WriteAsync(first_message); Task second_write_status = wrapped_writer.WriteAsync(second_message); diff --git a/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/given/a_wrapped_stream_writer.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/given/a_wrapped_stream_writer.cs new file mode 100644 index 000000000..3788af7b6 --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/given/a_wrapped_stream_writer.cs @@ -0,0 +1,50 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Autofac.Extensions.DependencyInjection; +using Dolittle.Runtime.Actors; +using Dolittle.Runtime.Services.Configuration; +using Dolittle.Runtime.Services.ReverseCalls.given; +using Grpc.Core; +using Machine.Specifications; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using Moq; +using Proto; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriterActor.given; + +public class a_wrapped_stream_writer : all_dependencies +{ + protected static Mock> original_writer; + protected static IReverseCallStreamWriter writer; + static ActorSystem actor_system; + + private Establish context = () => + { + actor_system = new ActorSystem(); + original_writer = new Mock>(); + var host = Host.CreateDefaultBuilder() + .UseServiceProviderFactory(new AutofacServiceProviderFactory()) + .ConfigureLogging(_ => _.ClearProviders()) + .ConfigureServices(_ => _ + .AddSingleton(Mock.Of())) + .Build(); + var factory = new ReverseCallStreamWriterFactory( + actor_system, + new CreateProps(host.Services), + new OptionsWrapper(new ReverseCallsConfiguration{UseActors = true}), + metrics, + NullLoggerFactory.Instance); + writer = factory.CreateWriter(request_id, original_writer.Object, message_converter.Object, cancellation_token, null); + }; + + Cleanup cleanup = () => + { + writer.Dispose(); + actor_system.DisposeAsync().AsTask().GetAwaiter().GetResult(); + }; +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_getting_write_options.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_getting_write_options.cs new file mode 100644 index 000000000..81432ebf5 --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_getting_write_options.cs @@ -0,0 +1,26 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Grpc.Core; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriterActor; + +public class when_getting_write_options : given.a_wrapped_stream_writer +{ + static WriteOptions options; + + Establish context = () => + { + options = new WriteOptions(); + original_writer + .SetupGet(_ => _.WriteOptions) + .Returns(options); + }; + + static WriteOptions result; + Because of = () => result = writer.WriteOptions; + + It should_get_the_options_of_the_original_stream = () => original_writer.VerifyGet(_ => _.WriteOptions); + It should_return_the_options_from_the_original_stream = () => result.ShouldEqual(options); +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_pinging/and_another_write_is_currently_blocking.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_pinging/and_another_write_is_currently_blocking.cs new file mode 100644 index 000000000..51e961f0b --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_pinging/and_another_write_is_currently_blocking.cs @@ -0,0 +1,34 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Services.ReverseCalls.given; +using Machine.Specifications; +using Moq; +using It = Machine.Specifications.It; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriterActor.when_pinging; + +public class and_another_write_is_currently_blocking : given.a_wrapped_stream_writer +{ + static a_message another_message; + + Establish context = () => + { + another_message = new a_message(); + + original_writer + .Setup(_ => _.WriteAsync(another_message)) + .Returns(Task.Delay(Timeout.Infinite)); + }; + + Because of = () => + { + _ = writer.WriteAsync(another_message); + writer.MaybeWritePing(); + Thread.Sleep(20); + }; + + It should_not_write_the_ping_message_to_the_original_stream = () => original_writer.Verify(_ => _.WriteAsync(Moq.It.IsAny()), Times.Once); +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_pinging/and_writing_fails.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_pinging/and_writing_fails.cs new file mode 100644 index 000000000..89f9481b4 --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_pinging/and_writing_fails.cs @@ -0,0 +1,35 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading.Tasks; +using Dolittle.Runtime.Services.ReverseCalls.given; +using Dolittle.Services.Contracts; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriterActor.when_pinging; + +public class and_writing_fails : given.a_wrapped_stream_writer +{ + static a_message ping_message; + static Exception exception; + + Establish context = () => + { + exception = new Exception(); + + message_converter + .Setup(_ => _.SetPing(Moq.It.IsAny(), Moq.It.IsAny())) + .Callback((message, _) => ping_message = message); + + original_writer + .Setup(_ => _.WriteAsync(Moq.It.IsAny())) + .Returns(Task.FromException(exception)); + }; + + static Exception result; + Because of = () => result = Catch.Exception(() => writer.MaybeWritePing()); + + It should_not_write_the_ping_message_to_the_original_stream = () => original_writer.Verify(_ => _.WriteAsync(ping_message), Moq.Times.Never); + It should_not_fail_with_the_original_exception = () => result.ShouldBeNull(); +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_pinging/and_writing_succeeds.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_pinging/and_writing_succeeds.cs new file mode 100644 index 000000000..2dc5d622b --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_pinging/and_writing_succeeds.cs @@ -0,0 +1,29 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading.Tasks; +using Dolittle.Runtime.Services.ReverseCalls.given; +using Dolittle.Services.Contracts; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriterActor.when_pinging; + +public class and_writing_succeeds : given.a_wrapped_stream_writer +{ + static a_message ping_message; + + Establish context = () => + { + message_converter + .Setup(_ => _.SetPing(Moq.It.IsAny(), Moq.It.IsAny())) + .Callback((message, _) => ping_message = message); + + original_writer + .Setup(_ => _.WriteAsync(Moq.It.IsAny())) + .Returns(Task.CompletedTask); + }; + + Because of = () => writer.MaybeWritePing(); + + It should_not_write_the_ping_message_to_the_original_stream = () => original_writer.Verify(_ => _.WriteAsync(ping_message), Moq.Times.Never); +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_setting_write_options.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_setting_write_options.cs new file mode 100644 index 000000000..a1aad87f2 --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_setting_write_options.cs @@ -0,0 +1,18 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Grpc.Core; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriterActor; + +public class when_setting_write_options : given.a_wrapped_stream_writer +{ + static WriteOptions options; + + Establish context = () => options = new WriteOptions(); + + Because of = () => writer.WriteOptions = options; + + It should_set_the_options_of_the_original_stream = () => original_writer.VerifySet(_ => _.WriteOptions = options); +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_writing/and_writing_fails.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_writing/and_writing_fails.cs new file mode 100644 index 000000000..0436b0aaa --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_writing/and_writing_fails.cs @@ -0,0 +1,31 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading.Tasks; +using Dolittle.Runtime.Services.ReverseCalls.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriterActor.when_writing; + +public class and_writing_fails : given.a_wrapped_stream_writer +{ + static a_message message; + static Exception exception; + + Establish context = () => + { + message = new a_message(); + exception = new Exception(); + + original_writer + .Setup(_ => _.WriteAsync(message)) + .Returns(Task.FromException(exception)); + }; + + static Exception result; + Because of = () => result = Catch.Exception(() => writer.WriteAsync(message).GetAwaiter().GetResult()); + + It should_write_the_message_to_the_original_stream = () => original_writer.Verify(_ => _.WriteAsync(message)); + It should_fail_with_the_original_exception = () => result.ShouldEqual(exception); +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_writing/and_writing_fails_once_then_succeeds.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_writing/and_writing_fails_once_then_succeeds.cs new file mode 100644 index 000000000..b985ca5d1 --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_writing/and_writing_fails_once_then_succeeds.cs @@ -0,0 +1,41 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading.Tasks; +using Dolittle.Runtime.Services.ReverseCalls.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriterActor.when_writing; + +public class and_writing_fails_once_then_succeeds : given.a_wrapped_stream_writer +{ + static a_message first_message; + static Exception exception; + static a_message second_message; + + Establish context = () => + { + first_message = new a_message(); + exception = new Exception(); + second_message = new a_message(); + + original_writer + .Setup(_ => _.WriteAsync(first_message)) + .Returns(Task.FromException(exception)); + original_writer + .Setup(_ => _.WriteAsync(second_message)) + .Returns(Task.CompletedTask); + }; + + static Exception result; + Because of = () => + { + result = Catch.Exception(() => writer.WriteAsync(first_message).GetAwaiter().GetResult()); + writer.WriteAsync(second_message).GetAwaiter().GetResult(); + }; + + It should_write_the_first_message_to_the_original_stream = () => original_writer.Verify(_ => _.WriteAsync(first_message)); + It should_fail_with_the_original_exception = () => result.ShouldEqual(exception); + It should_write_the_second_message_to_the_original_stream = () => original_writer.Verify(_ => _.WriteAsync(second_message)); +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_writing/and_writing_succeeds.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_writing/and_writing_succeeds.cs new file mode 100644 index 000000000..030fd3b83 --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_writing/and_writing_succeeds.cs @@ -0,0 +1,26 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading.Tasks; +using Dolittle.Runtime.Services.ReverseCalls.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriterActor.when_writing; + +public class and_writing_succeeds : given.a_wrapped_stream_writer +{ + static a_message message; + + Establish context = () => + { + message = new a_message(); + + original_writer + .Setup(_ => _.WriteAsync(message)) + .Returns(Task.CompletedTask); + }; + + Because of = () => writer.WriteAsync(message).GetAwaiter().GetResult(); + + It should_write_the_message_to_the_original_stream = () => original_writer.Verify(_ => _.WriteAsync(message)); +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_writing/concurrently.cs b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_writing/concurrently.cs new file mode 100644 index 000000000..146f796e6 --- /dev/null +++ b/Specifications/Services/ReverseCalls/for_ReverseCallStreamWriterActor/when_writing/concurrently.cs @@ -0,0 +1,111 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Services.ReverseCalls.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.ReverseCalls.for_ReverseCallStreamWriterActor.when_writing; + +public class concurrently : given.a_wrapped_stream_writer +{ + static a_message first_message; + static a_message second_message; + static a_message third_message; + static TaskCompletionSource first_message_write; + static TaskCompletionSource second_message_write; + static TaskCompletionSource third_message_write; + static int[] call_order; + + Establish context = () => + { + first_message = new a_message(); + second_message = new a_message(); + third_message = new a_message(); + + first_message_write = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + second_message_write = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + third_message_write = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + call_order = new int[3]; + var current_call = 1; + + original_writer + .Setup(_ => _.WriteAsync(first_message)) + .Callback(() => call_order[0] = current_call++) + .Returns(first_message_write.Task); + original_writer + .Setup(_ => _.WriteAsync(second_message)) + .Callback(() => call_order[1] = current_call++) + .Returns(second_message_write.Task); + original_writer + .Setup(_ => _.WriteAsync(third_message)) + .Callback(() => call_order[2] = current_call++) + .Returns(third_message_write.Task); + }; + + static bool first_write_first_check; + static bool second_write_first_check; + static bool third_write_first_check; + static bool first_write_second_check; + static bool second_write_second_check; + static bool third_write_second_check; + static bool first_write_third_check; + static bool second_write_third_check; + static bool third_write_third_check; + + private Because of = () => + { + var stopWatch = new Stopwatch(); + stopWatch.Start(); + Task first_write_status = writer.WriteAsync(first_message); + Task second_write_status = writer.WriteAsync(second_message); + Task third_write_status = writer.WriteAsync(third_message); + + Thread.Sleep(20); + first_write_first_check = first_write_status.IsCompleted; + second_write_first_check = second_write_status.IsCompleted; + third_write_first_check = third_write_status.IsCompleted; + + first_message_write.SetResult(); + third_message_write.SetResult(); + Thread.Sleep(20); + first_write_second_check = first_write_status.IsCompleted; + second_write_second_check = second_write_status.IsCompleted; + third_write_second_check = third_write_status.IsCompleted; + + second_message_write.SetResult(); + Thread.Sleep(20); + first_write_third_check = first_write_status.IsCompleted; + second_write_third_check = second_write_status.IsCompleted; + third_write_third_check = third_write_status.IsCompleted; + }; + + It should_not_have_completed_any_writes_after_the_first_check = () => + { + first_write_first_check.ShouldBeFalse(); + second_write_first_check.ShouldBeFalse(); + third_write_first_check.ShouldBeFalse(); + }; + It should_have_completed_the_first_after_the_second_check = () => + { + first_write_second_check.ShouldBeTrue(); + second_write_second_check.ShouldBeFalse(); + third_write_second_check.ShouldBeFalse(); + }; + It should_have_completed_all_writes_after_the_third_check = () => + { + first_write_third_check.ShouldBeTrue(); + second_write_third_check.ShouldBeTrue(); + third_write_third_check.ShouldBeTrue(); + }; + + It should_call_write_on_the_original_stream_in_order = () => + { + call_order[0].ShouldEqual(1); + call_order[1].ShouldEqual(2); + call_order[2].ShouldEqual(3); + }; +} \ No newline at end of file diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/given/all_dependencies.cs b/Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/given/all_dependencies.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/given/all_dependencies.cs rename to Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/given/all_dependencies.cs diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_reading/and_stream_throws_an_exception.cs b/Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_reading/and_stream_throws_an_exception.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_reading/and_stream_throws_an_exception.cs rename to Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_reading/and_stream_throws_an_exception.cs diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_reading/and_there_are_no_messages.cs b/Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_reading/and_there_are_no_messages.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_reading/and_there_are_no_messages.cs rename to Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_reading/and_there_are_no_messages.cs diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_reading/and_there_are_two_messages.cs b/Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_reading/and_there_are_two_messages.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_reading/and_there_are_two_messages.cs rename to Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_reading/and_there_are_two_messages.cs diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_subscribing_to_message_received/and_stream_throws_an_exception.cs b/Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_subscribing_to_message_received/and_stream_throws_an_exception.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_subscribing_to_message_received/and_stream_throws_an_exception.cs rename to Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_subscribing_to_message_received/and_stream_throws_an_exception.cs diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_subscribing_to_message_received/and_there_are_no_messages.cs b/Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_subscribing_to_message_received/and_there_are_no_messages.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_subscribing_to_message_received/and_there_are_no_messages.cs rename to Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_subscribing_to_message_received/and_there_are_no_messages.cs diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_subscribing_to_message_received/and_there_are_two_messages.cs b/Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_subscribing_to_message_received/and_there_are_two_messages.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_subscribing_to_message_received/and_there_are_two_messages.cs rename to Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_subscribing_to_message_received/and_there_are_two_messages.cs diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_stream_throws_an_exception_on_the_first_message.cs b/Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_stream_throws_an_exception_on_the_first_message.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_stream_throws_an_exception_on_the_first_message.cs rename to Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_stream_throws_an_exception_on_the_first_message.cs diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_stream_throws_an_exception_on_the_second_message.cs b/Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_stream_throws_an_exception_on_the_second_message.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_stream_throws_an_exception_on_the_second_message.cs rename to Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_stream_throws_an_exception_on_the_second_message.cs diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_the_first_message_does_not_contain_arguments.cs b/Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_the_first_message_does_not_contain_arguments.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_the_first_message_does_not_contain_arguments.cs rename to Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_the_first_message_does_not_contain_arguments.cs diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_the_first_message_does_not_contain_context.cs b/Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_the_first_message_does_not_contain_context.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_the_first_message_does_not_contain_context.cs rename to Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_the_first_message_does_not_contain_context.cs diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_there_are_no_messages.cs b/Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_there_are_no_messages.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_there_are_no_messages.cs rename to Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_there_are_no_messages.cs diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_there_are_two_messages.cs b/Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_there_are_two_messages.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_there_are_two_messages.cs rename to Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_there_are_two_messages.cs diff --git a/Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_there_are_two_messages_with_arguments_context.cs b/Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_there_are_two_messages_with_arguments_context.cs similarity index 100% rename from Specifications/Services/ReverseCall/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_there_are_two_messages_with_arguments_context.cs rename to Specifications/Services/ReverseCalls/for_WrappedAsyncStreamReader/when_waiting_for_reverse_call_context/and_there_are_two_messages_with_arguments_context.cs diff --git a/Specifications/Services/ReverseCall/given/a_message.cs b/Specifications/Services/ReverseCalls/given/a_message.cs similarity index 100% rename from Specifications/Services/ReverseCall/given/a_message.cs rename to Specifications/Services/ReverseCalls/given/a_message.cs diff --git a/Specifications/Services/ReverseCall/given/all_dependencies.cs b/Specifications/Services/ReverseCalls/given/all_dependencies.cs similarity index 100% rename from Specifications/Services/ReverseCall/given/all_dependencies.cs rename to Specifications/Services/ReverseCalls/given/all_dependencies.cs diff --git a/Specifications/Services/ReverseCall/given/an_async_stream_reader.cs b/Specifications/Services/ReverseCalls/given/an_async_stream_reader.cs similarity index 100% rename from Specifications/Services/ReverseCall/given/an_async_stream_reader.cs rename to Specifications/Services/ReverseCalls/given/an_async_stream_reader.cs diff --git a/Specifications/Services/Services.csproj b/Specifications/Services/Services.csproj index ee98e1e57..137585dd1 100755 --- a/Specifications/Services/Services.csproj +++ b/Specifications/Services/Services.csproj @@ -4,6 +4,7 @@ Dolittle.Runtime.Services.Specs + Dolittle.Runtime.Services @@ -12,4 +13,8 @@ + + + + diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/given/a_dispatcher.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/given/a_dispatcher.cs new file mode 100644 index 000000000..e855a9413 --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/given/a_dispatcher.cs @@ -0,0 +1,45 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Autofac.Extensions.DependencyInjection; +using Dolittle.Runtime.Actors; +using Dolittle.Runtime.Services.Actors; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Machine.Specifications; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Moq; +using Proto; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.given; + +public class a_dispatcher : for_ReverseCallDispatcher.given.a_dispatcher +{ + + static ActorSystem actor_system; + + private Establish context = () => + { + actor_system = new ActorSystem(); + var host = Host.CreateDefaultBuilder() + .UseServiceProviderFactory(new AutofacServiceProviderFactory()) + .ConfigureServices(_ => _ + .AddSingleton(execution_context_creator.Object) + .AddSingleton(Mock.Of())) + .Build(); + + var propsCreator = new CreateProps(host.Services); + dispatcher = new ReverseCallDispatcherActor.Wrapper( + actor_system, + propsCreator, + RequestId.Generate(), + pinged_connection.Object, + new MyProtocol()); + }; + + private Cleanup cleanup = () => + { + dispatcher.Dispose(); + actor_system.DisposeAsync().AsTask().GetAwaiter().GetResult(); + }; +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_accepting/and_it_has_already_been_accepted.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_accepting/and_it_has_already_been_accepted.cs new file mode 100644 index 000000000..3852026b7 --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_accepting/and_it_has_already_been_accepted.cs @@ -0,0 +1,27 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_accepting; + +public class and_it_has_already_been_accepted : given.a_dispatcher +{ + static MyConnectResponse connect_response; + static Exception exception; + + Establish context = () => + { + connect_response = new MyConnectResponse(); + client_to_runtime_stream.Setup(_ => _.MoveNext(Moq.It.IsAny())).Returns(Task.FromResult(false)); + dispatcher.Accept(connect_response, CancellationToken.None).GetAwaiter().GetResult(); + }; + + Because of = () => exception = Catch.Exception(() => dispatcher.Accept(connect_response, CancellationToken.None).GetAwaiter().GetResult()); + + It should_fail_because_accept_has_already_been_called = () => exception.ShouldBeOfExactType(); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_accepting/and_it_has_already_been_rejected.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_accepting/and_it_has_already_been_rejected.cs new file mode 100644 index 000000000..97c980b89 --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_accepting/and_it_has_already_been_rejected.cs @@ -0,0 +1,27 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_accepting; + +public class and_it_has_already_been_rejected : given.a_dispatcher +{ + static MyConnectResponse connect_response; + static Exception exception; + + Establish context = () => + { + connect_response = new MyConnectResponse(); + client_to_runtime_stream.Setup(_ => _.MoveNext(Moq.It.IsAny())).Returns(Task.FromResult(false)); + dispatcher.Reject(connect_response, CancellationToken.None).GetAwaiter().GetResult(); + }; + + Because of = () => exception = Catch.Exception(() => dispatcher.Accept(connect_response, CancellationToken.None).GetAwaiter().GetResult()); + + It should_fail_because_dispatcher_has_already_been_rejected = () => exception.ShouldBeOfExactType(); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_accepting/and_the_token_is_cancelled_after_receiving_the_first_message.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_accepting/and_the_token_is_cancelled_after_receiving_the_first_message.cs new file mode 100644 index 000000000..7e6de3ead --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_accepting/and_the_token_is_cancelled_after_receiving_the_first_message.cs @@ -0,0 +1,32 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_accepting; + +public class and_the_token_is_cancelled_after_receiving_the_first_message : given.a_dispatcher +{ + static CancellationTokenSource cts; + Establish context = () => + { + cts = new CancellationTokenSource(); + client_to_runtime_stream + .Setup(_ => _.MoveNext(Moq.It.IsAny())) + .Returns(Task.FromResult(true)) + .Callback(() => cts.Cancel()); + }; + + static Task task; + Because of = () => + { + task = dispatcher.Accept(new MyConnectResponse(), cts.Token); + task.GetAwaiter().GetResult(); + }; + + It should_move_client_stream_once = () => client_to_runtime_stream.Verify(_ => _.MoveNext(Moq.It.IsAny()), Moq.Times.Once); + It should_return_from_the_accept_call = () => task.IsCompleted.ShouldBeTrue(); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_accepting/and_there_are_no_more_client_responses.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_accepting/and_there_are_no_more_client_responses.cs new file mode 100644 index 000000000..93f0d3f84 --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_accepting/and_there_are_no_more_client_responses.cs @@ -0,0 +1,27 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_accepting; + +public class and_there_are_no_more_client_responses : given.a_dispatcher +{ + static MyConnectResponse connect_response; + Establish context = () => + { + connect_response = new MyConnectResponse(); + client_to_runtime_stream.Setup(_ => _.MoveNext(Moq.It.IsAny())).Returns(Task.FromResult(false)); + }; + + Because of = () => + { + dispatcher.Accept(connect_response, CancellationToken.None).GetAwaiter().GetResult(); + }; + + It should_write_one_message = () => runtime_to_client_stream.Verify(_ => _.WriteAsync(Moq.It.Is(_ => _.ConnectResponse.Equals(connect_response))), Moq.Times.Once); + It should_move_client_stream_once = () => client_to_runtime_stream.Verify(_ => _.MoveNext(Moq.It.IsAny()), Moq.Times.Once); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_accepting/with_a_connect_response.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_accepting/with_a_connect_response.cs new file mode 100644 index 000000000..5842dd765 --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_accepting/with_a_connect_response.cs @@ -0,0 +1,21 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_accepting; + +public class with_a_connect_response : given.a_dispatcher +{ + static MyConnectResponse connect_response; + static MyConnectResponse received_connect_response; + + Establish context = () => connect_response = new MyConnectResponse(); + + Because of = () => dispatcher.Accept(connect_response, new CancellationTokenSource(200).Token).GetAwaiter().GetResult(); + + It should_write_the_connection_response = () => runtime_to_client_stream.Verify(_ => _.WriteAsync(Moq.It.Is(_ => _.ConnectResponse == connect_response)), Moq.Times.Once); + It should_write_a_connection_response = () => runtime_to_client_stream.Verify(_ => _.WriteAsync(Moq.It.IsAny()), Moq.Times.Once); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_calling/and_it_receives_a_response_with_another_callid.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_calling/and_it_receives_a_response_with_another_callid.cs new file mode 100644 index 000000000..0dcfa56bb --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_calling/and_it_receives_a_response_with_another_callid.cs @@ -0,0 +1,57 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Protobuf; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Dolittle.Services.Contracts; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_calling; + +public class and_it_receives_a_response_with_another_callid : given.a_dispatcher +{ + static MyRequest request; + static MyResponse response_from_client; + + Establish context = () => + { + request = new MyRequest(); + response_from_client = new MyResponse(); + + var stream_reader = new MockStreamReader(); + + pinged_connection + .SetupGet(_ => _.RuntimeStream) + .Returns(stream_reader); + + runtime_to_client_stream + .Setup(_ => _.WriteAsync(Moq.It.IsAny())) + .Callback(server_message => + { + if (server_message.Request != request) + { + return; + } + + response_from_client.Context = new ReverseCallResponseContext + { CallId = ReverseCallId.New().ToProtobuf() }; + + stream_reader.ReceiveMessage(new MyClientMessage() { Response = response_from_client }); + }) + .Returns(Task.FromResult(true)); + + _ = dispatcher.Accept(new MyConnectResponse(), CancellationToken.None); + }; + + static Task response; + Because of = () => + { + response = dispatcher.Call(request, execution_context, CancellationToken.None); + Thread.Sleep(50); + }; + + It should_write_a_message_with_the_request = () => runtime_to_client_stream.Verify(_ => _.WriteAsync(Moq.It.Is(_ => _.Request == request)), Moq.Times.Once); + It should_not_have_received_a_response = () => response.IsCompleted.ShouldBeFalse(); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_calling/and_it_receives_a_response_with_the_correct_callid.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_calling/and_it_receives_a_response_with_the_correct_callid.cs new file mode 100644 index 000000000..123373fe5 --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_calling/and_it_receives_a_response_with_the_correct_callid.cs @@ -0,0 +1,57 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Protobuf; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Dolittle.Services.Contracts; +using Machine.Specifications; +using ExecutionContext = Dolittle.Runtime.Execution.ExecutionContext; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_calling; + +public class and_it_receives_a_response_with_the_correct_callid : given.a_dispatcher +{ + static MyRequest request; + static ExecutionContext execution_context_in_request; + static MyResponse response_from_client; + + Establish context = () => + { + request = new MyRequest(); + response_from_client = new MyResponse(); + + var stream_reader = new MockStreamReader(); + + pinged_connection + .SetupGet(_ => _.RuntimeStream) + .Returns(stream_reader); + + runtime_to_client_stream + .Setup(_ => _.WriteAsync(Moq.It.IsAny())) + .Callback(server_message => + { + if (server_message.Request != request) + { + return; + } + + execution_context_in_request = server_message.Request.Context.ExecutionContext.ToExecutionContext(); + response_from_client.Context = new ReverseCallResponseContext + { CallId = server_message.Request.Context.CallId }; + + stream_reader.ReceiveMessage(new MyClientMessage() { Response = response_from_client }); + }) + .Returns(Task.FromResult(true)); + + _ = dispatcher.Accept(new MyConnectResponse(), CancellationToken.None); + }; + + static MyResponse response; + Because of = () => response = dispatcher.Call(request, execution_context, CancellationToken.None).GetAwaiter().GetResult(); + + It should_write_a_message_with_the_request = () => runtime_to_client_stream.Verify(_ => _.WriteAsync(Moq.It.Is(_ => _.Request == request)), Moq.Times.Once); + It should_set_the_current_execution_context_in_the_request = () => execution_context_in_request.ShouldEqual(execution_context); + It should_return_the_received_response = () => response.ShouldEqual(response_from_client); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_calling/and_reverse_call_has_already_completed.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_calling/and_reverse_call_has_already_completed.cs new file mode 100644 index 000000000..3848595c3 --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_calling/and_reverse_call_has_already_completed.cs @@ -0,0 +1,19 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_calling; + +public class and_reverse_call_has_already_completed : given.a_dispatcher +{ + Establish context = () => dispatcher.Accept(new MyConnectResponse(), new CancellationToken(true)).GetAwaiter().GetResult(); + + static Exception exception; + Because of = () => exception = Catch.Exception(() => dispatcher.Call(new MyRequest(), execution_context, CancellationToken.None).GetAwaiter().GetResult()); + + It should_fail = () => exception.ShouldBeOfExactType(); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_calling/with_two_requests.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_calling/with_two_requests.cs new file mode 100644 index 000000000..33167f565 --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_calling/with_two_requests.cs @@ -0,0 +1,74 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Dolittle.Services.Contracts; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_calling; + +[Ignore("This hangs most of the times")] +public class with_two_requests : given.a_dispatcher +{ + static MyRequest first_request; + static MyRequest second_request; + static MyResponse response_to_first_from_client; + static MyResponse response_to_second_from_client; + + Establish context = () => + { + first_request = new MyRequest(); + second_request = new MyRequest(); + response_to_first_from_client = new MyResponse(); + response_to_second_from_client = new MyResponse(); + + var stream_reader = new MockStreamReader(); + + pinged_connection + .SetupGet(_ => _.RuntimeStream) + .Returns(stream_reader); + + runtime_to_client_stream + .Setup(_ => _.WriteAsync(Moq.It.IsAny())) + .Callback(server_message => + { + if (server_message.Request == first_request) + { + response_to_first_from_client.Context = new ReverseCallResponseContext + { CallId = server_message.Request.Context.CallId }; + return; + } + + if (server_message.Request == second_request) + { + response_to_second_from_client.Context = new ReverseCallResponseContext + { CallId = server_message.Request.Context.CallId }; + + stream_reader.ReceiveMessage(new MyClientMessage() { Response = response_to_second_from_client }); + stream_reader.ReceiveMessage(new MyClientMessage() { Response = response_to_first_from_client }); + } + + }) + .Returns(Task.FromResult(true)); + + _ = dispatcher.Accept(new MyConnectResponse(), CancellationToken.None); + }; + + static MyResponse first_response; + static MyResponse second_response; + Because of = () => + { + var first_call = dispatcher.Call(first_request, execution_context, CancellationToken.None); + var second_call = dispatcher.Call(second_request, execution_context, CancellationToken.None); + + first_response = first_call.GetAwaiter().GetResult(); + second_response = second_call.GetAwaiter().GetResult(); + }; + + It should_write_a_message_with_the_first_request = () => runtime_to_client_stream.Verify(_ => _.WriteAsync(Moq.It.Is(_ => _.Request == first_request)), Moq.Times.Once); + It should_write_a_message_with_the_second_request = () => runtime_to_client_stream.Verify(_ => _.WriteAsync(Moq.It.Is(_ => _.Request == second_request)), Moq.Times.Once); + It should_return_the_first_response_to_the_first_request = () => first_response.ShouldEqual(response_to_first_from_client); + It should_return_the_second_response_to_the_second_request = () => second_response.ShouldEqual(response_to_second_from_client); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_first_message_in_client_stream_is_not_connect_arguments.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_first_message_in_client_stream_is_not_connect_arguments.cs new file mode 100644 index 000000000..ae02bb193 --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_first_message_in_client_stream_is_not_connect_arguments.cs @@ -0,0 +1,25 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_receiving_arguments; + +public class and_first_message_in_client_stream_is_not_connect_arguments : given.a_dispatcher +{ + static bool result; + + Establish context = () => + { + client_to_runtime_stream.Setup(_ => _.MoveNext(Moq.It.IsAny())).Returns(Task.FromResult(true)); + client_to_runtime_stream.SetupGet(_ => _.Current).Returns(new MyClientMessage()); + }; + + Because of = () => result = dispatcher.ReceiveArguments(CancellationToken.None).GetAwaiter().GetResult(); + + It should_return_false = () => result.ShouldBeFalse(); + It should_not_set_arguments = () => dispatcher.Arguments.ShouldBeNull(); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_receiving_correct_connect_arguments.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_receiving_correct_connect_arguments.cs new file mode 100644 index 000000000..a91f3aa99 --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_receiving_correct_connect_arguments.cs @@ -0,0 +1,43 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Protobuf; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Dolittle.Services.Contracts; +using Google.Protobuf.WellKnownTypes; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_receiving_arguments; + +public class and_receiving_correct_connect_arguments : given.a_dispatcher +{ + static bool result; + static MyConnectArguments arguments; + + Establish context = () => + { + arguments = new MyConnectArguments + { + Context = new ReverseCallArgumentsContext + { + ExecutionContext = execution_context.ToProtobuf(), + PingInterval = Duration.FromTimeSpan(new TimeSpan(0, 0, 1)) + } + }; + + client_to_runtime_stream + .Setup(_ => _.MoveNext(Moq.It.IsAny())) + .Returns(Task.FromResult(true)); + client_to_runtime_stream + .SetupGet(_ => _.Current) + .Returns(new MyClientMessage { Arguments = arguments }); + }; + + Because of = () => result = dispatcher.ReceiveArguments(CancellationToken.None).GetAwaiter().GetResult(); + + It should_return_true = () => result.ShouldBeTrue(); + It should_have_the_correct_arguments = () => dispatcher.Arguments.ShouldEqual(arguments); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_registration_arguments_call_context_does_not_have_execution_context.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_registration_arguments_call_context_does_not_have_execution_context.cs new file mode 100644 index 000000000..788dbb6e7 --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_registration_arguments_call_context_does_not_have_execution_context.cs @@ -0,0 +1,26 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Dolittle.Services.Contracts; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_receiving_arguments; + +public class and_registration_arguments_call_context_does_not_have_execution_context : given.a_dispatcher +{ + static bool result; + + Establish context = () => + { + client_to_runtime_stream.Setup(_ => _.MoveNext(Moq.It.IsAny())).Returns(Task.FromResult(true)); + client_to_runtime_stream.SetupGet(_ => _.Current).Returns(new MyClientMessage { Arguments = new MyConnectArguments { Context = new ReverseCallArgumentsContext() } }); + }; + + Because of = () => result = dispatcher.ReceiveArguments(CancellationToken.None).GetAwaiter().GetResult(); + + It should_return_false = () => result.ShouldBeFalse(); + It should_not_set_arguments = () => dispatcher.Arguments.ShouldBeNull(); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_registration_arguments_does_not_have_call_context.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_registration_arguments_does_not_have_call_context.cs new file mode 100644 index 000000000..61a2c9865 --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_registration_arguments_does_not_have_call_context.cs @@ -0,0 +1,25 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_receiving_arguments; + +public class and_registration_arguments_does_not_have_call_context : given.a_dispatcher +{ + static bool result; + + Establish context = () => + { + client_to_runtime_stream.Setup(_ => _.MoveNext(Moq.It.IsAny())).Returns(Task.FromResult(true)); + client_to_runtime_stream.SetupGet(_ => _.Current).Returns(new MyClientMessage { Arguments = new MyConnectArguments() }); + }; + + Because of = () => result = dispatcher.ReceiveArguments(CancellationToken.None).GetAwaiter().GetResult(); + + It should_return_false = () => result.ShouldBeFalse(); + It should_not_set_arguments = () => dispatcher.Arguments.ShouldBeNull(); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_there_are_no_messages_in_client_stream.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_there_are_no_messages_in_client_stream.cs new file mode 100644 index 000000000..3a82f3c6e --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_there_are_no_messages_in_client_stream.cs @@ -0,0 +1,23 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; +using System.Threading.Tasks; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_receiving_arguments; + +public class and_there_are_no_messages_in_client_stream : given.a_dispatcher +{ + static bool result; + + Establish context = () => + { + client_to_runtime_stream.Setup(_ => _.MoveNext(Moq.It.IsAny())).Returns(Task.FromResult(false)); + }; + + Because of = () => result = dispatcher.ReceiveArguments(CancellationToken.None).GetAwaiter().GetResult(); + + It should_return_false = () => result.ShouldBeFalse(); + It should_not_set_arguments = () => dispatcher.Arguments.ShouldBeNull(); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_trying_to_receive_them_twice.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_trying_to_receive_them_twice.cs new file mode 100644 index 000000000..ab284787c --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_receiving_arguments/and_trying_to_receive_them_twice.cs @@ -0,0 +1,48 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Dolittle.Runtime.Protobuf; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Dolittle.Services.Contracts; +using Google.Protobuf.WellKnownTypes; +using Machine.Specifications; +using Moq; +using It = Machine.Specifications.It; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_receiving_arguments; + +public class and_trying_to_receive_them_twice : given.a_dispatcher +{ + static MyConnectArguments arguments; + + Establish context = () => + { + arguments = new MyConnectArguments + { + Context = new ReverseCallArgumentsContext + { + ExecutionContext = execution_context.ToProtobuf(), + PingInterval = Duration.FromTimeSpan(new TimeSpan(0, 0, 1)) + } + }; + + client_to_runtime_stream + .Setup(_ => _.MoveNext(Moq.It.IsAny())) + .Returns(Task.FromResult(true)); + client_to_runtime_stream + .SetupGet(_ => _.Current) + .Returns(new MyClientMessage { Arguments = arguments }); + }; + static Exception exception; + Because of = () => + { + dispatcher.ReceiveArguments(CancellationToken.None).GetAwaiter().GetResult(); + exception = Catch.Exception((Action) (() => dispatcher.ReceiveArguments(CancellationToken.None).GetAwaiter().GetResult())); + }; + + It should_throw_exception_on_second_try = () => exception.ShouldBeOfExactType(); + It shouldnt_have_tried_to_read_the_stream_again = () => client_to_runtime_stream.Verify(_ => _.MoveNext(Moq.It.IsAny()), Times.Once); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_rejecting/and_it_has_already_been_accepted.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_rejecting/and_it_has_already_been_accepted.cs new file mode 100644 index 000000000..2542448f7 --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_rejecting/and_it_has_already_been_accepted.cs @@ -0,0 +1,20 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_rejecting; + +public class and_it_has_already_been_accepted : given.a_dispatcher +{ + static Exception exception; + + Establish context = () => dispatcher.Accept(new MyConnectResponse(), CancellationToken.None).GetAwaiter().GetResult(); + + Because of = () => exception = Catch.Exception(() => dispatcher.Reject(new MyConnectResponse(), CancellationToken.None).GetAwaiter().GetResult()); + + It should_fail_because_accept_has_already_been_called = () => exception.ShouldBeOfExactType(); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_rejecting/and_it_has_already_been_rejected.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_rejecting/and_it_has_already_been_rejected.cs new file mode 100644 index 000000000..05e3ee729 --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_rejecting/and_it_has_already_been_rejected.cs @@ -0,0 +1,27 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Threading; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_rejecting; + +public class and_it_has_already_been_rejected : given.a_dispatcher +{ + static MyConnectResponse connect_response; + static Exception exception; + + Establish context = () => + { + connect_response = new MyConnectResponse(); + dispatcher.Reject(connect_response, CancellationToken.None).GetAwaiter().GetResult(); + }; + + Because of = () => exception = Catch.Exception(() => dispatcher.Reject(new MyConnectResponse(), CancellationToken.None).GetAwaiter().GetResult()); + + It should_fail_because_dispatcher_has_already_been_rejected = () => exception.ShouldBeOfExactType(); + It should_write_the_first_response = () => runtime_to_client_stream.Verify(_ => _.WriteAsync(Moq.It.Is(_ => _.ConnectResponse == connect_response)), Moq.Times.Once); + It should_not_write_anything_else = () => runtime_to_client_stream.VerifyNoOtherCalls(); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/actor/when_rejecting/with_a_connect_response.cs b/Specifications/Services/for_ReverseCallDispatcher/actor/when_rejecting/with_a_connect_response.cs new file mode 100644 index 000000000..46a3d94ee --- /dev/null +++ b/Specifications/Services/for_ReverseCallDispatcher/actor/when_rejecting/with_a_connect_response.cs @@ -0,0 +1,19 @@ +// Copyright (c) Dolittle. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Threading; +using Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; +using Machine.Specifications; + +namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.actor.when_rejecting; + +public class with_a_connect_response : given.a_dispatcher +{ + static MyConnectResponse connect_response; + + Establish context = () => connect_response = new MyConnectResponse(); + + Because of = () => dispatcher.Reject(connect_response, CancellationToken.None).GetAwaiter().GetResult(); + + It should_write_the_response = () => runtime_to_client_stream.Verify(_ => _.WriteAsync(Moq.It.Is(_ => _.ConnectResponse == connect_response)), Moq.Times.Once); +} \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/given/CallContext.cs b/Specifications/Services/for_ReverseCallDispatcher/given/CallContext.cs index d15a85b11..6a1851b93 100644 --- a/Specifications/Services/for_ReverseCallDispatcher/given/CallContext.cs +++ b/Specifications/Services/for_ReverseCallDispatcher/given/CallContext.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Grpc.Core; @@ -9,31 +10,35 @@ namespace Dolittle.Runtime.Services.for_ReverseCallDispatcher.given; public class CallContext : ServerCallContext -{ - public CallContext() +{ + readonly Metadata _requestHeaders; + readonly CancellationToken _cancellationToken; + readonly Metadata _responseTrailers; + readonly AuthContext _authContext; + readonly Dictionary _userState; + WriteOptions? _writeOptions; + + public Metadata? ResponseHeaders { get; private set; } + + private CallContext(Metadata requestHeaders, CancellationToken cancellationToken) { - RequestHeadersCore = new Metadata(); + _requestHeaders = requestHeaders; + _cancellationToken = cancellationToken; + _responseTrailers = new Metadata(); + _authContext = new AuthContext(string.Empty, new Dictionary>()); + _userState = new Dictionary(); } - protected override string MethodCore => "SpecMethod"; - - protected override string HostCore => throw new NotImplementedException(); - - protected override string PeerCore => throw new NotImplementedException(); - - protected override DateTime DeadlineCore => throw new NotImplementedException(); - - protected override Metadata RequestHeadersCore { get; } - - protected override CancellationToken CancellationTokenCore => CancellationToken.None; - - protected override Metadata ResponseTrailersCore => throw new NotImplementedException(); - - protected override Status StatusCore { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - - protected override WriteOptions WriteOptionsCore { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - - protected override AuthContext AuthContextCore => throw new NotImplementedException(); + protected override string MethodCore => "MethodName"; + protected override string HostCore => "HostName"; + protected override string PeerCore => "PeerName"; + protected override DateTime DeadlineCore { get; } + protected override Metadata RequestHeadersCore => _requestHeaders; + protected override CancellationToken CancellationTokenCore => _cancellationToken; + protected override Metadata ResponseTrailersCore => _responseTrailers; + protected override Status StatusCore { get; set; } + protected override WriteOptions? WriteOptionsCore { get => _writeOptions; set { _writeOptions = value; } } + protected override AuthContext AuthContextCore => _authContext; protected override ContextPropagationToken CreatePropagationTokenCore(ContextPropagationOptions options) { @@ -42,6 +47,19 @@ protected override ContextPropagationToken CreatePropagationTokenCore(ContextPro protected override Task WriteResponseHeadersAsyncCore(Metadata responseHeaders) { - throw new NotImplementedException(); + if (ResponseHeaders != null) + { + throw new InvalidOperationException("Response headers have already been written."); + } + + ResponseHeaders = responseHeaders; + return Task.CompletedTask; + } + + protected override IDictionary UserStateCore => _userState; + + public static CallContext Create(Metadata? requestHeaders = null, CancellationToken cancellationToken = default) + { + return new CallContext(requestHeaders ?? new Metadata(), cancellationToken); } } \ No newline at end of file diff --git a/Specifications/Services/for_ReverseCallDispatcher/when_calling/and_it_receives_a_response_with_another_callid.cs b/Specifications/Services/for_ReverseCallDispatcher/when_calling/and_it_receives_a_response_with_another_callid.cs index 52d9a9e40..1221d4ca8 100644 --- a/Specifications/Services/for_ReverseCallDispatcher/when_calling/and_it_receives_a_response_with_another_callid.cs +++ b/Specifications/Services/for_ReverseCallDispatcher/when_calling/and_it_receives_a_response_with_another_callid.cs @@ -42,7 +42,7 @@ public class and_it_receives_a_response_with_another_callid : given.a_dispatcher }) .Returns(Task.FromResult(true)); - Task.Run(() => dispatcher.Accept(new MyConnectResponse(), CancellationToken.None)); + _ = dispatcher.Accept(new MyConnectResponse(), CancellationToken.None); }; static Task response; diff --git a/Specifications/Services/for_ReverseCallDispatcher/when_calling/and_it_receives_a_response_with_the_correct_callid.cs b/Specifications/Services/for_ReverseCallDispatcher/when_calling/and_it_receives_a_response_with_the_correct_callid.cs index c9cbcf03f..031ce1f08 100644 --- a/Specifications/Services/for_ReverseCallDispatcher/when_calling/and_it_receives_a_response_with_the_correct_callid.cs +++ b/Specifications/Services/for_ReverseCallDispatcher/when_calling/and_it_receives_a_response_with_the_correct_callid.cs @@ -44,8 +44,8 @@ public class and_it_receives_a_response_with_the_correct_callid : given.a_dispat stream_reader.ReceiveMessage(new MyClientMessage() { Response = response_from_client }); }) .Returns(Task.FromResult(true)); - - Task.Run(() => dispatcher.Accept(new MyConnectResponse(), CancellationToken.None)); + + _ = dispatcher.Accept(new MyConnectResponse(), CancellationToken.None); }; static MyResponse response; diff --git a/Specifications/Services/for_ReverseCallDispatcher/when_calling/with_two_requests.cs b/Specifications/Services/for_ReverseCallDispatcher/when_calling/with_two_requests.cs index 4e6c51c9e..779b7ae71 100644 --- a/Specifications/Services/for_ReverseCallDispatcher/when_calling/with_two_requests.cs +++ b/Specifications/Services/for_ReverseCallDispatcher/when_calling/with_two_requests.cs @@ -52,8 +52,8 @@ public class with_two_requests : given.a_dispatcher }) .Returns(Task.FromResult(true)); - - Task.Run(() => dispatcher.Accept(new MyConnectResponse(), CancellationToken.None)); + + _ = dispatcher.Accept(new MyConnectResponse(), CancellationToken.None); }; static MyResponse first_response; diff --git a/specs.props b/specs.props index d2d494c48..b8281d0af 100644 --- a/specs.props +++ b/specs.props @@ -4,17 +4,21 @@ net7.0 true - IDE1006;IDE0044;IDE0052;CA2211;RCS1169;RCS1018;RCS1213 + IDE1006;IDE0044;IDE0051;IDE0052;CA2211;CS0612;CS0169;CS8981;RCS1169;RCS1018;RCS1213 + + + $(NuGetPackageRoot)dolittle.contracts/$(ContractsVersion)/protos/ + diff --git a/versions.props b/versions.props index b63e991ca..88840daeb 100644 --- a/versions.props +++ b/versions.props @@ -4,7 +4,7 @@ 7.2.0 1.1.2 2.4.2 - 7.6.0 + 7.8.0 3.1.0 2.* 3.125.5 @@ -18,9 +18,10 @@ 3.1.6 16.4.0 6.0.0 - 2.10.1 + 2.19.2 1.0.0 - 4.13.* + 4.18.* + 6.10.0 2.2.0 13.0.1 5.1.0