├── .dockerignore
├── .editorconfig
├── .gitattributes
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── dependabot.yml
└── workflows
│ ├── code_quality.yml.txt
│ ├── preview.yml
│ ├── publish.yml
│ ├── pull-request-docs.yml
│ ├── pull-request.yml
│ └── test-results.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Directory.Packages.props
├── Eventuous.sln
├── Eventuous.sln.DotSettings
├── LICENSE
├── README.md
├── docker-compose.yml
├── docs
├── README.md
├── babel.config.js
├── docs
│ ├── application
│ │ ├── app-service.md
│ │ ├── command-api.md
│ │ ├── command-map.mdx
│ │ ├── func-service.md
│ │ └── index.mdx
│ ├── diagnostics
│ │ ├── _category_.json
│ │ └── details.md
│ ├── domain
│ │ ├── aggregate.md
│ │ ├── domain-events.md
│ │ └── state.md
│ ├── faq
│ │ ├── _category_.json
│ │ ├── compare.md
│ │ ├── compatibility.md
│ │ └── persistence.md
│ ├── gateway
│ │ ├── implementation
│ │ │ └── index.md
│ │ └── index.mdx
│ ├── infra
│ │ ├── _category_.json
│ │ ├── elastic
│ │ │ └── index.md
│ │ ├── esdb
│ │ │ └── index.md
│ │ ├── kafka
│ │ │ └── index.md
│ │ ├── mongodb
│ │ │ └── index.md
│ │ ├── mssql
│ │ │ └── index.md
│ │ ├── postgres
│ │ │ └── index.md
│ │ ├── pubsub
│ │ │ └── index.md
│ │ └── rabbitmq
│ │ │ └── index.md
│ ├── intro.mdx
│ ├── persistence
│ │ ├── aggregate-store
│ │ │ ├── images
│ │ │ │ ├── reading-dark.png
│ │ │ │ ├── reading.png
│ │ │ │ ├── replication-dark.png
│ │ │ │ └── replication.png
│ │ │ └── index.mdx
│ │ ├── aggregate-stream.md
│ │ ├── event-store.md
│ │ ├── index.mdx
│ │ └── serialisation.md
│ ├── producers
│ │ ├── implementation.md
│ │ ├── index.mdx
│ │ └── providers.md
│ ├── prologue
│ │ ├── introduction.md
│ │ ├── quick-start.md
│ │ └── the-right-way
│ │ │ ├── images
│ │ │ ├── flaming-bus.jpg
│ │ │ ├── the-right-way-dark.png
│ │ │ └── the-right-way.png
│ │ │ └── index.mdx
│ ├── read-models
│ │ ├── rm-concept.md
│ │ └── supported-projectors.md
│ ├── subscriptions
│ │ ├── checkpoint
│ │ │ ├── images
│ │ │ │ ├── commit-handler-dark.png
│ │ │ │ └── commit-handler.png
│ │ │ └── index.mdx
│ │ ├── eventhandler
│ │ │ └── index.md
│ │ ├── pipes
│ │ │ ├── images
│ │ │ │ ├── concurrent-filter-dark.png
│ │ │ │ ├── concurrent-filter.png
│ │ │ │ ├── default-pipe-dark.png
│ │ │ │ ├── default-pipe.png
│ │ │ │ ├── partitioning-filter-dark.png
│ │ │ │ └── partitioning-filter.png
│ │ │ └── index.mdx
│ │ ├── sub-base
│ │ │ └── index.md
│ │ ├── subs-concept
│ │ │ ├── images
│ │ │ │ ├── subscriptions-dark.png
│ │ │ │ └── subscriptions.png
│ │ │ └── index.mdx
│ │ └── subs-diagnostics
│ │ │ ├── images
│ │ │ └── sub-trace.png
│ │ │ └── index.md
│ └── whats-new.mdx
├── docusaurus.config.ts
├── package.json
├── pnpm-lock.yaml
├── sidebars.ts
├── src
│ ├── components
│ │ ├── HomepageFeatures
│ │ │ ├── index.tsx
│ │ │ └── styles.module.css
│ │ └── highlight.jsx
│ ├── css
│ │ └── custom.css
│ ├── pages
│ │ ├── index.module.css
│ │ └── index.tsx
│ └── plugins
│ │ ├── posthog
│ │ ├── index.js
│ │ └── posthog.js
│ │ └── segment
│ │ ├── index.js
│ │ └── segment.js
├── static
│ ├── .nojekyll
│ ├── _redirects
│ └── img
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ ├── featured-background.jpg
│ │ ├── logo.png
│ │ ├── logo.svg
│ │ ├── site.webmanifest
│ │ └── social-card.png
├── tsconfig.json
├── versioned_docs
│ ├── version-0.14
│ │ ├── application
│ │ │ ├── app-service.md
│ │ │ ├── command-api.md
│ │ │ ├── command-map.mdx
│ │ │ ├── func-service.md
│ │ │ └── index.mdx
│ │ ├── diagnostics
│ │ │ ├── _category_.json
│ │ │ └── index.md
│ │ ├── domain
│ │ │ ├── aggregate.md
│ │ │ ├── domain-events.md
│ │ │ └── state.md
│ │ ├── faq
│ │ │ ├── _category_.json
│ │ │ ├── compare.md
│ │ │ ├── compatibility.md
│ │ │ └── persistence.md
│ │ ├── gateway
│ │ │ ├── implementation
│ │ │ │ └── index.md
│ │ │ └── index.mdx
│ │ ├── infra
│ │ │ ├── _category_.json
│ │ │ ├── elastic
│ │ │ │ └── index.md
│ │ │ ├── esdb
│ │ │ │ └── index.md
│ │ │ ├── kafka
│ │ │ │ └── index.md
│ │ │ ├── mongodb
│ │ │ │ └── index.md
│ │ │ ├── mssql
│ │ │ │ └── index.md
│ │ │ ├── postgres
│ │ │ │ └── index.md
│ │ │ ├── pubsub
│ │ │ │ └── index.md
│ │ │ └── rabbitmq
│ │ │ │ └── index.md
│ │ ├── intro.mdx
│ │ ├── persistence
│ │ │ ├── aggregate-store
│ │ │ │ ├── images
│ │ │ │ │ ├── reading-dark.png
│ │ │ │ │ ├── reading.png
│ │ │ │ │ ├── replication-dark.png
│ │ │ │ │ └── replication.png
│ │ │ │ └── index.mdx
│ │ │ ├── aggregate-stream.md
│ │ │ ├── event-store.md
│ │ │ ├── index.mdx
│ │ │ └── serialisation.md
│ │ ├── producers
│ │ │ ├── implementation.md
│ │ │ ├── index.mdx
│ │ │ └── providers.md
│ │ ├── prologue
│ │ │ ├── introduction.md
│ │ │ ├── quick-start.md
│ │ │ └── the-right-way
│ │ │ │ ├── images
│ │ │ │ ├── flaming-bus.jpg
│ │ │ │ ├── the-right-way-dark.png
│ │ │ │ └── the-right-way.png
│ │ │ │ └── index.mdx
│ │ ├── read-models
│ │ │ ├── rm-concept.md
│ │ │ └── supported-projectors.md
│ │ └── subscriptions
│ │ │ ├── checkpoint
│ │ │ ├── images
│ │ │ │ ├── commit-handler-dark.png
│ │ │ │ └── commit-handler.png
│ │ │ └── index.mdx
│ │ │ ├── eventhandler
│ │ │ └── index.md
│ │ │ ├── pipes
│ │ │ ├── images
│ │ │ │ ├── concurrent-filter-dark.png
│ │ │ │ ├── concurrent-filter.png
│ │ │ │ ├── default-pipe-dark.png
│ │ │ │ ├── default-pipe.png
│ │ │ │ ├── partitioning-filter-dark.png
│ │ │ │ └── partitioning-filter.png
│ │ │ └── index.mdx
│ │ │ ├── sub-base
│ │ │ └── index.md
│ │ │ ├── subs-concept
│ │ │ ├── images
│ │ │ │ ├── subscriptions-dark.png
│ │ │ │ └── subscriptions.png
│ │ │ └── index.mdx
│ │ │ └── subs-diagnostics
│ │ │ ├── images
│ │ │ └── sub-trace.png
│ │ │ └── index.md
│ └── version-0.15
│ │ ├── application
│ │ ├── _result.mdx
│ │ ├── _service_http.mdx
│ │ ├── _service_no_throw.mdx
│ │ ├── _service_registration.mdx
│ │ ├── app-service.mdx
│ │ ├── command-api.md
│ │ ├── func-service.mdx
│ │ └── index.mdx
│ │ ├── diagnostics
│ │ ├── index.mdx
│ │ ├── logs.md
│ │ ├── metrics.md
│ │ ├── opentelemetry.md
│ │ └── traces.md
│ │ ├── domain
│ │ ├── aggregate.md
│ │ ├── domain-events.md
│ │ └── state.md
│ │ ├── faq
│ │ ├── _category_.json
│ │ ├── compare.md
│ │ ├── compatibility.md
│ │ └── persistence.md
│ │ ├── gateway
│ │ ├── implementation
│ │ │ └── index.md
│ │ └── index.mdx
│ │ ├── infra
│ │ ├── _category_.json
│ │ ├── elastic
│ │ │ └── index.md
│ │ ├── esdb
│ │ │ └── index.md
│ │ ├── kafka
│ │ │ └── index.md
│ │ ├── mongodb
│ │ │ └── index.md
│ │ ├── mssql
│ │ │ └── index.md
│ │ ├── postgres
│ │ │ └── index.md
│ │ ├── pubsub
│ │ │ └── index.md
│ │ └── rabbitmq
│ │ │ └── index.md
│ │ ├── intro.mdx
│ │ ├── persistence
│ │ ├── aggregate-store.mdx
│ │ ├── aggregate-stream.md
│ │ ├── event-store.mdx
│ │ ├── images
│ │ │ ├── reading-dark.png
│ │ │ ├── reading.png
│ │ │ ├── replication-dark.png
│ │ │ └── replication.png
│ │ ├── index.mdx
│ │ └── serialisation.md
│ │ ├── producers
│ │ ├── implementation.md
│ │ ├── index.mdx
│ │ └── providers.md
│ │ ├── prologue
│ │ ├── introduction.md
│ │ ├── quick-start.md
│ │ └── the-right-way
│ │ │ ├── images
│ │ │ ├── flaming-bus.jpg
│ │ │ ├── the-right-way-dark.png
│ │ │ └── the-right-way.png
│ │ │ └── index.mdx
│ │ ├── read-models
│ │ ├── rm-concept.md
│ │ └── supported-projectors.md
│ │ ├── subscriptions
│ │ ├── checkpoint
│ │ │ ├── images
│ │ │ │ ├── commit-handler-dark.png
│ │ │ │ └── commit-handler.png
│ │ │ └── index.mdx
│ │ ├── eventhandler
│ │ │ └── index.md
│ │ ├── pipes
│ │ │ ├── images
│ │ │ │ ├── concurrent-filter-dark.png
│ │ │ │ ├── concurrent-filter.png
│ │ │ │ ├── default-pipe-dark.png
│ │ │ │ ├── default-pipe.png
│ │ │ │ ├── partitioning-filter-dark.png
│ │ │ │ └── partitioning-filter.png
│ │ │ └── index.mdx
│ │ ├── sub-base
│ │ │ └── index.md
│ │ ├── subs-concept
│ │ │ ├── images
│ │ │ │ ├── subscriptions-dark.png
│ │ │ │ └── subscriptions.png
│ │ │ └── index.mdx
│ │ └── subs-diagnostics
│ │ │ ├── images
│ │ │ └── sub-trace.png
│ │ │ └── index.md
│ │ └── whats-new.mdx
├── versioned_sidebars
│ ├── version-0.14-sidebars.json
│ └── version-0.15-sidebars.json
└── versions.json
├── e-logo.png
├── props
└── Common.props
├── qodana.yaml
├── samples
├── Directory.Build.props
├── esdb
│ ├── Bookings.Domain
│ │ ├── Bookings.Domain.csproj
│ │ ├── Bookings
│ │ │ ├── Booking.cs
│ │ │ ├── BookingEvents.cs
│ │ │ ├── BookingId.cs
│ │ │ └── BookingState.cs
│ │ ├── DomainModule.cs
│ │ ├── Money.cs
│ │ ├── RoomId.cs
│ │ ├── Services.cs
│ │ └── StayPeriod.cs
│ ├── Bookings.Payments
│ │ ├── Application
│ │ │ ├── CommandApi.cs
│ │ │ └── CommandService.cs
│ │ ├── Bookings.Payments.csproj
│ │ ├── Domain
│ │ │ ├── Money.cs
│ │ │ ├── Payment.cs
│ │ │ └── PaymentEvents.cs
│ │ ├── Infrastructure
│ │ │ ├── Logging.cs
│ │ │ └── Mongo.cs
│ │ ├── Integration
│ │ │ └── Payments.cs
│ │ ├── Program.cs
│ │ ├── Registrations.cs
│ │ └── appsettings.json
│ ├── Bookings
│ │ ├── .dockerignore
│ │ ├── Application
│ │ │ ├── BookingsCommandService.cs
│ │ │ ├── BookingsQueryService.cs
│ │ │ ├── Commands.cs
│ │ │ └── Queries
│ │ │ │ ├── BookingDocument.cs
│ │ │ │ ├── BookingStateProjection.cs
│ │ │ │ ├── MyBookings.cs
│ │ │ │ └── MyBookingsProjection.cs
│ │ ├── Bookings.csproj
│ │ ├── Dockerfile
│ │ ├── HttpApi
│ │ │ └── Bookings
│ │ │ │ ├── CommandApi.cs
│ │ │ │ ├── CommandApiWithCustomResult.cs
│ │ │ │ └── QueryApi.cs
│ │ ├── Infrastructure
│ │ │ └── Mongo.cs
│ │ ├── Integration
│ │ │ └── Payments.cs
│ │ ├── Program.cs
│ │ ├── Registrations.cs
│ │ └── appsettings.json
│ ├── deploy
│ │ └── cloudrun
│ │ │ ├── .gitignore
│ │ │ ├── Pulumi.dev.yaml
│ │ │ ├── Pulumi.yaml
│ │ │ ├── index.ts
│ │ │ ├── package.json
│ │ │ ├── tsconfig.json
│ │ │ └── yarn.lock
│ ├── docker-compose.yml
│ ├── grafana
│ │ ├── __inputs.json
│ │ └── datasources.yml
│ └── prometheus
│ │ └── prometheus.yml
└── postgres
│ ├── Bookings.Domain
│ └── Bookings.Domain.csproj
│ ├── Bookings.Payments
│ ├── Bookings.Payments.csproj
│ ├── Integration
│ │ └── Payments.cs
│ ├── Program.cs
│ ├── Registrations.cs
│ └── appsettings.json
│ ├── Bookings
│ ├── .dockerignore
│ ├── Application
│ │ ├── BookingsCommandService.cs
│ │ ├── Commands.cs
│ │ └── Queries
│ │ │ ├── BookingDocument.cs
│ │ │ ├── BookingStateProjection.cs
│ │ │ ├── MyBookings.cs
│ │ │ └── MyBookingsProjection.cs
│ ├── Bookings.csproj
│ ├── Dockerfile
│ ├── HttpApi
│ │ └── Bookings
│ │ │ ├── CommandApi.cs
│ │ │ └── QueryApi.cs
│ ├── Infrastructure
│ │ ├── Logging.cs
│ │ ├── Mongo.cs
│ │ └── Telemetry.cs
│ ├── Integration
│ │ └── Payments.cs
│ ├── Program.cs
│ ├── Registrations.cs
│ └── appsettings.json
│ ├── README.md
│ ├── deploy
│ └── cloudrun
│ │ ├── .gitignore
│ │ ├── Pulumi.dev.yaml
│ │ ├── Pulumi.yaml
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── yarn.lock
│ ├── docker-compose.yml
│ ├── grafana
│ ├── __inputs.json
│ └── datasources.yml
│ └── prometheus
│ └── prometheus.yml
├── src
├── Benchmarks
│ └── Benchmarks
│ │ ├── Benchmarks.csproj
│ │ ├── GapDetectionBenchmarks.cs
│ │ ├── Program.cs
│ │ ├── Tools
│ │ └── DynamicType.cs
│ │ └── TypeMapBenchmark.cs
├── Core
│ ├── Eventuous.Core.slnf
│ ├── src
│ │ ├── Eventuous.Application
│ │ │ ├── AggregateService
│ │ │ │ ├── CommandHandlerBuilder.cs
│ │ │ │ ├── CommandHandlersMap.cs
│ │ │ │ ├── CommandService.Async.cs
│ │ │ │ ├── CommandService.Sync.cs
│ │ │ │ ├── CommandService.cs
│ │ │ │ └── CommandServiceDelegates.cs
│ │ │ ├── Diagnostics
│ │ │ │ ├── ApplicationEventSource.cs
│ │ │ │ ├── CommandServiceActivity.cs
│ │ │ │ ├── CommandServiceMetrics.cs
│ │ │ │ └── TracedCommandService.cs
│ │ │ ├── Eventuous.Application.csproj
│ │ │ ├── Eventuous.Application.csproj.DotSettings
│ │ │ ├── Exceptions
│ │ │ │ ├── ExceptionMessages.cs
│ │ │ │ ├── ExceptionMessages.restext
│ │ │ │ └── Exceptions.cs
│ │ │ ├── ExpectedState.cs
│ │ │ ├── FunctionalService
│ │ │ │ ├── CommandHandlerBuilder.cs
│ │ │ │ ├── CommandService.cs
│ │ │ │ ├── FuncHandlerDelegateExtensions.cs
│ │ │ │ ├── FuncServiceDelegates.cs
│ │ │ │ └── HandlersMap.cs
│ │ │ ├── ICommandService.cs
│ │ │ ├── MessageMap.cs
│ │ │ ├── Persistence
│ │ │ │ ├── ProposedAppend.cs
│ │ │ │ └── WriterExtensions.cs
│ │ │ ├── Result.cs
│ │ │ ├── Shared
│ │ │ │ └── IDefineAppendAmendment.cs
│ │ │ └── ThrowingCommandService.cs
│ │ ├── Eventuous.Diagnostics
│ │ │ ├── ActivityExtensions.cs
│ │ │ ├── ActivityStatus.cs
│ │ │ ├── DiagnosticName.cs
│ │ │ ├── DummyActivityListener.cs
│ │ │ ├── Eventuous.Diagnostics.csproj
│ │ │ ├── Eventuous.Diagnostics.csproj.DotSettings
│ │ │ ├── EventuousDiagnostics.cs
│ │ │ ├── GenericListener.cs
│ │ │ ├── MetadataExtensions.cs
│ │ │ ├── Metrics
│ │ │ │ ├── GenericObserver.cs
│ │ │ │ ├── Measure.cs
│ │ │ │ └── MetricsListener.cs
│ │ │ ├── Tags
│ │ │ │ ├── IWithCustomTags.cs
│ │ │ │ ├── MetaMappings.cs
│ │ │ │ ├── MetaTags.cs
│ │ │ │ └── TracingMeta.cs
│ │ │ ├── TelemetryTags.cs
│ │ │ └── Tracing
│ │ │ │ └── Constants.cs
│ │ ├── Eventuous.Domain
│ │ │ ├── Aggregate.cs
│ │ │ ├── Eventuous.Domain.csproj
│ │ │ ├── Eventuous.Domain.csproj.DotSettings
│ │ │ ├── Exceptions
│ │ │ │ ├── DomainException.cs
│ │ │ │ ├── ExceptionMessages.cs
│ │ │ │ ├── ExceptionMessages.restext
│ │ │ │ └── Exceptions.cs
│ │ │ ├── Id.cs
│ │ │ └── State.cs
│ │ ├── Eventuous.Persistence
│ │ │ ├── AggregateFactory.cs
│ │ │ ├── AggregateStore
│ │ │ │ ├── AggregatePersistenceExtensions.cs
│ │ │ │ ├── AggregateStore.cs
│ │ │ │ ├── AggregateStoreExceptions.cs
│ │ │ │ ├── AggregateStoreExtensions.cs
│ │ │ │ ├── AggregateStoreWithArchive.cs
│ │ │ │ └── IAggregateStore.cs
│ │ │ ├── AmendEvent.cs
│ │ │ ├── AppendEventsResult.cs
│ │ │ ├── Diagnostics
│ │ │ │ ├── PersistenceEventSource.cs
│ │ │ │ ├── PersistenceMetrics.cs
│ │ │ │ └── Tracing
│ │ │ │ │ ├── BaseTracer.cs
│ │ │ │ │ ├── TracedEventReader.cs
│ │ │ │ │ ├── TracedEventStore.cs
│ │ │ │ │ └── TracedEventWriter.cs
│ │ │ ├── EventStore
│ │ │ │ ├── EventStoreExceptions.cs
│ │ │ │ ├── IEventReader.cs
│ │ │ │ ├── IEventStore.cs
│ │ │ │ ├── IEventWriter.cs
│ │ │ │ ├── StoreFunctions.cs
│ │ │ │ ├── TieredEventReader.cs
│ │ │ │ └── TieredEventStore.cs
│ │ │ ├── Eventuous.Persistence.csproj
│ │ │ ├── Eventuous.Persistence.csproj.DotSettings
│ │ │ ├── ExpectedStreamVersion.cs
│ │ │ ├── StateStore
│ │ │ │ ├── FoldedEventStream.cs
│ │ │ │ ├── IStateStore.cs
│ │ │ │ ├── StateStore.cs
│ │ │ │ └── StateStoreFunctions.cs
│ │ │ ├── StreamEvent.cs
│ │ │ ├── StreamNameFactory.cs
│ │ │ └── StreamNameMap.cs
│ │ ├── Eventuous.Producers
│ │ │ ├── AckProduce.cs
│ │ │ ├── BaseProducer.cs
│ │ │ ├── Chunk.cs
│ │ │ ├── Diagnostics
│ │ │ │ ├── ProducerActivity.cs
│ │ │ │ ├── ProducerEventSource.cs
│ │ │ │ └── ProducerTracingOptions.cs
│ │ │ ├── Eventuous.Producers.csproj
│ │ │ ├── IProducer.cs
│ │ │ ├── ProducedMessage.cs
│ │ │ ├── ProducerExtensions.cs
│ │ │ └── RegistrationExtensions.cs
│ │ ├── Eventuous.Serialization
│ │ │ ├── DefaultEventSerializer.cs
│ │ │ ├── DefaultMetadataSerializer.cs
│ │ │ ├── Eventuous.Serialization.csproj
│ │ │ ├── IEventSerializer.cs
│ │ │ ├── IMetadataSerializer.cs
│ │ │ └── MetadataDeserializationException.cs
│ │ ├── Eventuous.Shared
│ │ │ ├── Eventuous.Shared.csproj
│ │ │ ├── Eventuous.Shared.csproj.DotSettings
│ │ │ ├── Exceptions
│ │ │ │ ├── ExceptionMessages.cs
│ │ │ │ ├── ExceptionMessages.restext
│ │ │ │ └── Exceptions.cs
│ │ │ ├── Meta
│ │ │ │ ├── MetaTags.cs
│ │ │ │ ├── Metadata.cs
│ │ │ │ └── MetadataExtensions.cs
│ │ │ ├── Store
│ │ │ │ └── StreamName.cs
│ │ │ ├── Tools
│ │ │ │ ├── Ensure.cs
│ │ │ │ ├── TaskExtensions.cs
│ │ │ │ ├── TaskRunner.cs
│ │ │ │ └── TypeExtensions.cs
│ │ │ └── TypeMap
│ │ │ │ ├── ITypeMapper.cs
│ │ │ │ ├── TypeMap.cs
│ │ │ │ ├── TypeMapEventSource.cs
│ │ │ │ ├── TypeMapper.cs
│ │ │ │ └── TypeMapperExtensions.cs
│ │ ├── Eventuous.Subscriptions
│ │ │ ├── Channels
│ │ │ │ ├── ChannelExtensions.cs
│ │ │ │ ├── ChannelFullException.cs
│ │ │ │ ├── ChannelWorkerBase.cs
│ │ │ │ └── ChannelWorkers.cs
│ │ │ ├── Checkpoints
│ │ │ │ ├── Checkpoint.cs
│ │ │ │ ├── CheckpointCommitHandler.cs
│ │ │ │ ├── CommitPositionSequence.cs
│ │ │ │ ├── ICheckpointStore.cs
│ │ │ │ ├── MeasuredCheckpointStore.cs
│ │ │ │ └── NoOpCheckpointStore.cs
│ │ │ ├── Consumers
│ │ │ │ ├── DefaultConsumer.cs
│ │ │ │ ├── IMessageConsumer.cs
│ │ │ │ └── MessageConsumeContextConverter.cs
│ │ │ ├── Context
│ │ │ │ ├── AsyncConsumeContext.cs
│ │ │ │ ├── ContextBaggageExtensions.cs
│ │ │ │ ├── ContextExtensions.cs
│ │ │ │ ├── ContextItemKeys.cs
│ │ │ │ ├── ContextItems.cs
│ │ │ │ ├── ContextResultExtensions.cs
│ │ │ │ ├── IMessageConsumeContext.cs
│ │ │ │ ├── MessageConsumeContext.cs
│ │ │ │ └── WrappedConsumeContext.cs
│ │ │ ├── Diagnostics
│ │ │ │ ├── CheckpointCommitMetrics.cs
│ │ │ │ ├── HealthReport.cs
│ │ │ │ ├── SubscriptionActivity.cs
│ │ │ │ ├── SubscriptionGapMeasure.cs
│ │ │ │ ├── SubscriptionHealth.cs
│ │ │ │ ├── SubscriptionMetrics.cs
│ │ │ │ └── SubscriptionsEventSource.cs
│ │ │ ├── DropReason.cs
│ │ │ ├── EventSubscription.cs
│ │ │ ├── EventSubscriptionWithCheckpoint.cs
│ │ │ ├── Eventuous.Subscriptions.csproj
│ │ │ ├── Eventuous.Subscriptions.csproj.DotSettings
│ │ │ ├── Exceptions.cs
│ │ │ ├── Filters
│ │ │ │ ├── AsyncHandlingFilter.cs
│ │ │ │ ├── ConsumePipe.cs
│ │ │ │ ├── ConsumePipeExtensions.cs
│ │ │ │ ├── ConsumerFilter.cs
│ │ │ │ ├── IConsumeFilter.cs
│ │ │ │ ├── MessageFilter.cs
│ │ │ │ ├── Partitioning
│ │ │ │ │ ├── MurmurHash3.cs
│ │ │ │ │ └── Partitioner.cs
│ │ │ │ ├── PartitioningFilter.cs
│ │ │ │ └── TracingFilter.cs
│ │ │ ├── Handlers
│ │ │ │ ├── BaseEventHandler.cs
│ │ │ │ ├── EventHandler.cs
│ │ │ │ ├── EventHandlingResult.cs
│ │ │ │ ├── EventHandlingStatus.cs
│ │ │ │ ├── IEventHandler.cs
│ │ │ │ └── TracedEventHandler.cs
│ │ │ ├── IMessageSubscription.cs
│ │ │ ├── Logging
│ │ │ │ ├── CheckpointLogging.cs
│ │ │ │ ├── InternalLogger.cs
│ │ │ │ ├── Logger.cs
│ │ │ │ └── SubscriptionLogging.cs
│ │ │ ├── MetaSerializerExtensions.cs
│ │ │ ├── Properties
│ │ │ │ └── InternalVisibleTo.cs
│ │ │ ├── Registrations
│ │ │ │ ├── KeyedServiceProvider.cs
│ │ │ │ ├── NamedRegistrations.cs
│ │ │ │ ├── SubscriptionBuilder.cs
│ │ │ │ ├── SubscriptionBuilderExtensions.cs
│ │ │ │ └── SubscriptionRegistrationExtensions.cs
│ │ │ ├── SubscriptionHostedService.cs
│ │ │ └── SubscriptionOptions.cs
│ │ └── Eventuous
│ │ │ └── Eventuous.csproj
│ └── test
│ │ ├── Eventuous.Tests.Application
│ │ ├── BookingFuncService.cs
│ │ ├── CommandServiceTests.cs
│ │ ├── Eventuous.Tests.Application.csproj
│ │ ├── FunctionalServiceTests.cs
│ │ ├── Helpers.cs
│ │ ├── ServiceTestBase.Amendments.cs
│ │ ├── ServiceTestBase.OnAny.cs
│ │ ├── ServiceTestBase.OnExisting.cs
│ │ ├── ServiceTestBase.OnNew.cs
│ │ ├── ServiceTestBase.cs
│ │ └── StateWithIdTests.cs
│ │ ├── Eventuous.Tests.Persistence.Base
│ │ ├── Eventuous.Tests.Persistence.Base.csproj
│ │ ├── Fixtures
│ │ │ ├── DomainFixture.cs
│ │ │ ├── Helpers.cs
│ │ │ └── StoreFixtureBase.cs
│ │ └── Store
│ │ │ ├── Append.cs
│ │ │ ├── OtherMethods.cs
│ │ │ ├── Read.cs
│ │ │ └── TieredStoreTests.cs
│ │ ├── Eventuous.Tests.Subscriptions.Base
│ │ ├── Eventuous.Tests.Subscriptions.Base.csproj
│ │ ├── Eventuous.Tests.Subscriptions.Base.csproj.DotSettings
│ │ ├── Fixtures
│ │ │ ├── SubscriptionExtensions.cs
│ │ │ ├── SubscriptionFixtureBase.cs
│ │ │ ├── TestEventHandler.cs
│ │ │ └── TracedHandler.cs
│ │ ├── SubscribeToAll.cs
│ │ ├── SubscribeToStream.cs
│ │ └── SubscriptionTestBase.cs
│ │ ├── Eventuous.Tests.Subscriptions
│ │ ├── ConsumePipeTests.cs
│ │ ├── DefaultConsumerTests.cs
│ │ ├── Eventuous.Tests.Subscriptions.csproj
│ │ ├── HandlingStatusTests.cs
│ │ ├── RegistrationTests.cs
│ │ ├── SequenceTests.cs
│ │ └── TestContext.cs
│ │ └── Eventuous.Tests
│ │ ├── AggregateWithId
│ │ └── OperateOnAggregateWithId.cs
│ │ ├── Aggregates
│ │ ├── OperateOnExistingSpec.cs
│ │ └── TwoAggregateOpsSpec.cs
│ │ ├── Eventuous.Tests.csproj
│ │ ├── Fixtures
│ │ ├── IdGenerator.cs
│ │ └── NaiveFixture.cs
│ │ ├── ForgotToSetId.cs
│ │ ├── StoringEvents.cs
│ │ ├── StoringEventsWithCustomStream.cs
│ │ ├── StreamNameMapTests.cs
│ │ ├── StreamNameTests.cs
│ │ └── TypeRegistrationTests.cs
├── Diagnostics
│ ├── docker-compose.yml
│ ├── src
│ │ ├── Eventuous.Diagnostics.Logging
│ │ │ ├── Eventuous.Diagnostics.Logging.csproj
│ │ │ ├── LoggingEventListener.cs
│ │ │ └── README.md
│ │ ├── Eventuous.Diagnostics.OpenTelemetry
│ │ │ ├── Eventuous.Diagnostics.OpenTelemetry.csproj
│ │ │ ├── MeterProviderBuilderExtensions.cs
│ │ │ └── TracerProviderBuilderExtensions.cs
│ │ └── Eventuous.Diagnostics
│ │ │ ├── DiagnosticName.cs
│ │ │ ├── Eventuous.Diagnostics.csproj
│ │ │ └── Properties
│ │ │ └── InternalVisibleTo.cs
│ └── test
│ │ └── Eventuous.Tests.OpenTelemetry
│ │ ├── Eventuous.Tests.OpenTelemetry.csproj
│ │ ├── Fakes
│ │ ├── MessageCounter.cs
│ │ ├── MetricValue.cs
│ │ ├── TestExporter.cs
│ │ └── TestHandler.cs
│ │ ├── Fixtures
│ │ └── MetricsSubscriptionFixtureBase.cs
│ │ └── MetricsTests.cs
├── Directory.Build.props
├── Directory.Build.targets
├── Directory.Testable.targets
├── Directory.Untestable.targets
├── EventStore
│ ├── Eventuous.EventStore.slnf
│ ├── docker-compose.yml
│ ├── src
│ │ └── Eventuous.EventStore
│ │ │ ├── EsdbEventStore.cs
│ │ │ ├── Eventuous.EventStore.csproj
│ │ │ ├── Eventuous.EventStore.csproj.DotSettings
│ │ │ ├── Producers
│ │ │ ├── EventStoreProduceOptions.cs
│ │ │ └── EventStoreProducer.cs
│ │ │ ├── README.md
│ │ │ ├── StreamRevisionExtensions.cs
│ │ │ └── Subscriptions
│ │ │ ├── AllPersistentSubscription.cs
│ │ │ ├── AllStreamSubscription.cs
│ │ │ ├── ConsumePipeExtensions.cs
│ │ │ ├── Diagnostics
│ │ │ ├── AllStreamSubscriptionMeasure.cs
│ │ │ ├── BaseSubscriptionMeasure.cs
│ │ │ └── StreamSubscriptionMeasure.cs
│ │ │ ├── EsdbMappings.cs
│ │ │ ├── EventStoreCatchUpSubscriptionBase.cs
│ │ │ ├── EventStoreExtensions.cs
│ │ │ ├── Options
│ │ │ ├── AllPersistentSubscriptionOptions.cs
│ │ │ ├── AllStreamSubscriptionOptions.cs
│ │ │ ├── CatchUpSubscriptionOptions.cs
│ │ │ ├── EventStoreSubscriptionOptions.cs
│ │ │ ├── EventStoreSubscriptionWithCheckpointOptions.cs
│ │ │ ├── PersistentSubscriptionOptions.cs
│ │ │ ├── StreamPersistentSubscriptionOptions.cs
│ │ │ └── StreamSubscriptionOptions.cs
│ │ │ ├── PersistentSubscriptionBase.cs
│ │ │ ├── StreamPersistentSubscription.cs
│ │ │ └── StreamSubscription.cs
│ └── test
│ │ └── Eventuous.Tests.EventStore
│ │ ├── AppServiceTests.cs
│ │ ├── Eventuous.Tests.EventStore.csproj
│ │ ├── Fixtures
│ │ ├── DomainFixture.cs
│ │ ├── EsdbContainer.cs
│ │ ├── StoreFixture.cs
│ │ └── TestCheckpointStore.cs
│ │ ├── Limiter.cs
│ │ ├── Metrics
│ │ ├── MetricsFixture.cs
│ │ └── MetricsTests.cs
│ │ ├── ProducerTracesTests.cs
│ │ ├── RegistrationTests.cs
│ │ ├── Store
│ │ ├── AggregateStoreTests.cs
│ │ ├── EventStoreAggregateTests.cs
│ │ ├── StoreTests.cs
│ │ └── TieredStoreTests.cs
│ │ └── Subscriptions
│ │ ├── CustomDependenciesTests.cs
│ │ ├── Fixtures
│ │ ├── CatchUpSubscriptionFixture.cs
│ │ ├── LegacySubscriptionFixture.cs
│ │ └── PersistentSubscriptionFixture.cs
│ │ ├── PublishAndSubscribeManyPartitionedTests.cs
│ │ ├── PublishAndSubscribeManyTests.cs
│ │ ├── PublishAndSubscribeOneTests.cs
│ │ ├── StreamPersistentPublishAndSubscribeManyTests.cs
│ │ ├── StreamSubscriptionDeletedEventsTests.cs
│ │ ├── StreamSubscriptionWithLinksTests.cs
│ │ ├── SubscribeTests.cs
│ │ └── SubscriptionIgnoredMessagesTests.cs
├── Experimental
│ └── src
│ │ ├── ElasticPlayground
│ │ ├── CombinedStore.cs
│ │ ├── ConfigureElastic.cs
│ │ ├── ConnectorAndArchive.cs
│ │ ├── ElasticOnly.cs
│ │ ├── ElasticPlayground.csproj
│ │ ├── Generator.cs
│ │ ├── MiscExtensions.cs
│ │ ├── OnlyArchive.cs
│ │ ├── Program.cs
│ │ ├── ResultExtensions.cs
│ │ └── docker-compose.yml
│ │ ├── Eventuous.ElasticSearch
│ │ ├── Eventuous.ElasticSearch.csproj
│ │ ├── Index
│ │ │ ├── IndexConfig.cs
│ │ │ └── IndexSetup.cs
│ │ ├── Producers
│ │ │ └── ElasticProducer.cs
│ │ ├── Projections
│ │ │ └── ElasticCheckpointStore.cs
│ │ └── Store
│ │ │ ├── ElasticEventStore.cs
│ │ │ ├── ElasticSerializer.cs
│ │ │ └── PersistedEvent.cs
│ │ └── Eventuous.Spyglass
│ │ ├── Accessor.cs
│ │ ├── Eventuous.Spyglass.csproj
│ │ ├── InsidePeek.cs
│ │ ├── RegistrationExtensions.cs
│ │ └── SpyglassApi.cs
├── Extensions
│ ├── src
│ │ ├── Eventuous.Extensions.AspNetCore
│ │ │ ├── Diagnostics
│ │ │ │ └── ExtensionsEventSource.cs
│ │ │ ├── Eventuous.Extensions.AspNetCore.csproj
│ │ │ ├── Http
│ │ │ │ ├── CommandHttpApiBase.cs
│ │ │ │ ├── CommandServiceRouteBuilder.cs
│ │ │ │ ├── ContentTypes.cs
│ │ │ │ ├── ControllerAttributes.cs
│ │ │ │ ├── HttpCommandAttribute.cs
│ │ │ │ ├── HttpCommandMapping.cs
│ │ │ │ ├── HttpCommandMappingExt.cs
│ │ │ │ ├── ResultExtensions.cs
│ │ │ │ └── RouteHandlerBuilderExt.cs
│ │ │ └── Logging
│ │ │ │ └── AppBuilderLoggingExtensions.cs
│ │ ├── Eventuous.Extensions.DependencyInjection
│ │ │ ├── Eventuous.Extensions.DependencyInjection.csproj
│ │ │ ├── LoggingServiceProviderExtensions.cs
│ │ │ ├── README.md
│ │ │ └── Registrations
│ │ │ │ ├── AggregateFactory.cs
│ │ │ │ ├── AggregateStore.cs
│ │ │ │ ├── Services.cs
│ │ │ │ ├── StoreWithArchive.cs
│ │ │ │ └── Stores.cs
│ │ ├── Eventuous.Extensions.Logging
│ │ │ ├── Eventuous.Extensions.Logging.csproj
│ │ │ └── LoggerFactoryExtensions.cs
│ │ └── Eventuous.Subscriptions.Polly
│ │ │ ├── Eventuous.Subscriptions.Polly.csproj
│ │ │ ├── PollyEventHandler.cs
│ │ │ └── SubscriptionBuilderExtensions.cs
│ └── test
│ │ ├── Eventuous.Sut.AspNetCore
│ │ ├── BookingApi.cs
│ │ ├── BookingService.cs
│ │ ├── Eventuous.Sut.AspNetCore.csproj
│ │ ├── Program.cs
│ │ ├── TestConfig.cs
│ │ ├── TestData.cs
│ │ └── appsettings.json
│ │ ├── Eventuous.Tests.DependencyInjection
│ │ ├── AggregateFactoryRegistrationTests.cs
│ │ ├── Eventuous.Tests.DependencyInjection.csproj
│ │ └── Sut
│ │ │ ├── FakeStore.cs
│ │ │ ├── TestAggregate.cs
│ │ │ └── TestDependency.cs
│ │ └── Eventuous.Tests.Extensions.AspNetCore
│ │ ├── AggregateCommandsTests.MapAggregateContractToCommandExplicitlyWithoutRouteWithGenericAttr_factory=Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1[Program].verified.txt
│ │ ├── AggregateCommandsTests.MapAggregateContractToCommandExplicitlyWithoutRoute_factory=Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1[Program].verified.txt
│ │ ├── AggregateCommandsTests.MapAggregateContractToCommandExplicitly_factory=Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1[Program].verified.txt
│ │ ├── AggregateCommandsTests.MapEnrichedCommand_factory=Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1[Program].verified.txt
│ │ ├── AggregateCommandsTests.cs
│ │ ├── ControllerTests.cs
│ │ ├── DiscoveredCommandsTests.CallDiscoveredCommandRoute_factory=Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1[Program].verified.txt
│ │ ├── DiscoveredCommandsTests.cs
│ │ ├── Eventuous.Tests.Extensions.AspNetCore.csproj
│ │ └── Fixture
│ │ ├── Commands.cs
│ │ ├── Enricher.cs
│ │ ├── Module.cs
│ │ ├── ServerFixture.cs
│ │ ├── TestAggregate.cs
│ │ └── TestBaseWithLogs.cs
├── Gateway
│ ├── src
│ │ └── Eventuous.Gateway
│ │ │ ├── Eventuous.Gateway.csproj
│ │ │ ├── GatewayHandler.cs
│ │ │ ├── GatewayHandlerFactory.cs
│ │ │ ├── GatewayMessage.cs
│ │ │ ├── GatewayMetaHelper.cs
│ │ │ ├── GatewayProducer.cs
│ │ │ ├── IGatewayTransform.cs
│ │ │ └── Registrations
│ │ │ └── GatewayRegistrations.cs
│ └── test
│ │ └── Eventuous.Tests.Gateway
│ │ ├── Eventuous.Tests.Gateway.csproj
│ │ └── RegistrationTests.cs
├── GooglePubSub
│ ├── src
│ │ ├── Eventuous.GooglePubSub.CloudRun
│ │ │ ├── CloudRunPubSubSubscription.cs
│ │ │ ├── CloudRunPubSubSubscriptionOptions.cs
│ │ │ ├── EndpointMappingExtensions.cs
│ │ │ └── Eventuous.GooglePubSub.CloudRun.csproj
│ │ └── Eventuous.GooglePubSub
│ │ │ ├── Eventuous.GooglePubSub.csproj
│ │ │ ├── Producers
│ │ │ ├── ClientCache.cs
│ │ │ ├── GooglePubSubProducer.cs
│ │ │ ├── PubSubProduceOptions.cs
│ │ │ └── PubSubProducerOptions.cs
│ │ │ ├── PubSubAttributes.cs
│ │ │ ├── README.md
│ │ │ ├── Shared
│ │ │ └── PubSub.cs
│ │ │ └── Subscriptions
│ │ │ ├── GooglePubSubSubscription.cs
│ │ │ └── PubSubSubscriptionOptions.cs
│ └── test
│ │ └── Eventuous.Tests.GooglePubSub
│ │ ├── Eventuous.Tests.GooglePubSub.csproj
│ │ ├── PubSubFixture.cs
│ │ └── PubSubTests.cs
├── Kafka
│ ├── docker-compose.yml
│ ├── src
│ │ └── Eventuous.Kafka
│ │ │ ├── Eventuous.Kafka.csproj
│ │ │ ├── KafkaHeaderKeys.cs
│ │ │ ├── MetadataExtensions.cs
│ │ │ ├── Producers
│ │ │ ├── KafkaBasicProducer.cs
│ │ │ ├── KafkaProduceOptions.cs
│ │ │ └── KafkaProducerOptions.cs
│ │ │ ├── README.md
│ │ │ └── Subscriptions
│ │ │ ├── KafkaBasicSubscription.cs
│ │ │ └── KafkaSubscriptionOptions.cs
│ ├── start.sh
│ └── test
│ │ └── Eventuous.Tests.Kafka
│ │ ├── BasicProducerTests.cs
│ │ ├── Eventuous.Tests.Kafka.csproj
│ │ └── KafkaFixture.cs
├── Mongo
│ ├── docker-compose.yml
│ ├── src
│ │ └── Eventuous.Projections.MongoDB
│ │ │ ├── Eventuous.Projections.MongoDB.csproj
│ │ │ ├── Eventuous.Projections.MongoDB.csproj.DotSettings
│ │ │ ├── Functional.cs
│ │ │ ├── MongoCheckpointStore.cs
│ │ │ ├── MongoOperationBuilder.cs
│ │ │ ├── MongoProjector.cs
│ │ │ ├── Operations
│ │ │ ├── BulkBuilder.cs
│ │ │ ├── DeleteBuilder.cs
│ │ │ ├── InsertBuilder.cs
│ │ │ └── UpdateBuilder.cs
│ │ │ ├── Options.cs
│ │ │ ├── README.md
│ │ │ └── Tools
│ │ │ ├── Document.cs
│ │ │ ├── MongoCollectionExtensions.cs
│ │ │ ├── MongoCollectionName.cs
│ │ │ ├── MongoDatabaseExtensions.cs
│ │ │ └── MongoDefaults.cs
│ └── test
│ │ └── Eventuous.Tests.Projections.MongoDB
│ │ ├── Eventuous.Tests.Projections.MongoDB.csproj
│ │ ├── Fixtures
│ │ ├── DomainFixture.cs
│ │ └── IntegrationFixture.cs
│ │ ├── ProjectWithBuilder.cs
│ │ ├── ProjectWithBulkBuilder.cs
│ │ ├── ProjectingWithTypedHandlers.cs
│ │ └── ProjectionTestBase.cs
├── Postgres
│ ├── src
│ │ └── Eventuous.Postgresql
│ │ │ ├── Eventuous.Postgresql.csproj
│ │ │ ├── Extensions
│ │ │ ├── PostgresExtensions.cs
│ │ │ └── RegistrationExtensions.cs
│ │ │ ├── PostgresStore.cs
│ │ │ ├── Projections
│ │ │ └── PostgresProjector.cs
│ │ │ ├── Schema.cs
│ │ │ ├── SchemaInitializer.cs
│ │ │ ├── Scripts
│ │ │ ├── 1_Schema.sql
│ │ │ ├── 2_AppendEvents.sql
│ │ │ ├── 3_CheckStream.sql
│ │ │ ├── 4_ReadAllForwards.sql
│ │ │ ├── 5_ReadStreamBackwards.sql
│ │ │ ├── 6_ReadStreamForwards.sql
│ │ │ ├── 7_ReadStreamSub.sql
│ │ │ └── 8_TruncateStream.sql
│ │ │ └── Subscriptions
│ │ │ ├── PostgresAllStreamSubscription.cs
│ │ │ ├── PostgresCheckpointStore.cs
│ │ │ ├── PostgresStreamSubscription.cs
│ │ │ └── PostgresSubscriptionBase.cs
│ └── test
│ │ └── Eventuous.Tests.Postgres
│ │ ├── Eventuous.Tests.Postgres.csproj
│ │ ├── Fixtures
│ │ └── PostgresContainer.cs
│ │ ├── Metrics
│ │ ├── MetricsFixture.cs
│ │ └── MetricsTests.cs
│ │ ├── Projections
│ │ └── ProjectorTests.cs
│ │ ├── Registrations
│ │ └── RegistrationTests.cs
│ │ ├── Store
│ │ ├── StoreFixture.cs
│ │ ├── StoreTests.cs
│ │ └── TieredStoreTests.cs
│ │ └── Subscriptions
│ │ ├── SubscribeTests.cs
│ │ └── SubscriptionFixture.cs
├── RabbitMq
│ ├── docker-compose.yml
│ ├── src
│ │ └── Eventuous.RabbitMq
│ │ │ ├── Diagnostics
│ │ │ └── RabbitMqTelemetryTags.cs
│ │ │ ├── Eventuous.RabbitMq.csproj
│ │ │ ├── Producers
│ │ │ ├── ExchangeCache.cs
│ │ │ ├── RabbitMqProduceOptions.cs
│ │ │ └── RabbitMqProducer.cs
│ │ │ ├── README.md
│ │ │ ├── Shared
│ │ │ └── RabbitMqExchangeOptions.cs
│ │ │ └── Subscriptions
│ │ │ ├── RabbitMqSubscription.cs
│ │ │ ├── RabbitMqSubscriptionOptions.cs
│ │ │ └── Timestamp.cs
│ └── test
│ │ └── Eventuous.Tests.RabbitMq
│ │ ├── Eventuous.Tests.RabbitMq.csproj
│ │ ├── RabbitMqFixture.cs
│ │ └── SubscriptionSpec.cs
├── Redis
│ ├── docker-compose.yml
│ ├── src
│ │ └── Eventuous.Redis
│ │ │ ├── Eventuous.Redis.csproj
│ │ │ ├── Module.cs
│ │ │ ├── RedisKeys.cs
│ │ │ ├── RedisStore.cs
│ │ │ ├── Scripts
│ │ │ └── AppendEvents.lua
│ │ │ ├── Subscriptions
│ │ │ ├── ReceivedEvent.cs
│ │ │ ├── RedisAllStreamSubscription.cs
│ │ │ ├── RedisCheckpointStore.cs
│ │ │ ├── RedisStreamSubscription.cs
│ │ │ └── RedisSubscriptionBase.cs
│ │ │ └── Tools
│ │ │ └── Conversions.cs
│ └── test
│ │ └── Eventuous.Tests.Redis
│ │ ├── Eventuous.Tests.Redis.csproj
│ │ ├── Fixtures
│ │ ├── DomainFixture.cs
│ │ ├── IntegrationFixture.cs
│ │ └── SubscriptionFixture.cs
│ │ ├── Store
│ │ ├── Append.cs
│ │ ├── Helpers.cs
│ │ └── Read.cs
│ │ └── Subscriptions
│ │ ├── SubscribeToAll.cs
│ │ └── SubscribeToStream.cs
├── Relational
│ └── src
│ │ └── Eventuous.Sql.Base
│ │ ├── Eventuous.Sql.Base.csproj
│ │ ├── PersistedEvent.cs
│ │ ├── Producers
│ │ └── PostgresProducer.cs
│ │ ├── ReaderExtensions.cs
│ │ ├── SqlEventStoreBase.cs
│ │ └── Subscriptions
│ │ ├── SqlSubscriptionBase.cs
│ │ └── SqlSubscriptionOptionsBase.cs
├── SqlServer
│ ├── src
│ │ └── Eventuous.SqlServer
│ │ │ ├── ConnectionFactory.cs
│ │ │ ├── Eventuous.SqlServer.csproj
│ │ │ ├── Extensions
│ │ │ ├── RegistrationExtensions.cs
│ │ │ └── SqlExtensions.cs
│ │ │ ├── Projections
│ │ │ ├── SqlServerConnectionOptions.cs
│ │ │ └── SqlServerProjector.cs
│ │ │ ├── Schema.cs
│ │ │ ├── SchemaInitializer.cs
│ │ │ ├── Scripts
│ │ │ ├── 1_Schema.sql
│ │ │ ├── 2_AppendEvents.sql
│ │ │ ├── 3_CheckStream.sql
│ │ │ ├── 4_ReadAllForwards.sql
│ │ │ ├── 5_ReadStreamBackwards.sql
│ │ │ ├── 6_ReadStreamForwards.sql
│ │ │ ├── 7_ReadStreamSub.sql
│ │ │ └── 8_TruncateStream.sql
│ │ │ ├── SqlServerStore.cs
│ │ │ └── Subscriptions
│ │ │ ├── SqlServerAllStreamSubscription.cs
│ │ │ ├── SqlServerCheckpointStore.cs
│ │ │ ├── SqlServerStreamSubscription.cs
│ │ │ ├── SqlServerStreamSubscriptionOptions.cs
│ │ │ └── SqlServerSubscriptionBase.cs
│ └── test
│ │ └── Eventuous.Tests.SqlServer
│ │ ├── Eventuous.Tests.SqlServer.csproj
│ │ ├── Fixtures
│ │ └── SqlContainer.cs
│ │ ├── Limiter.cs
│ │ ├── Metrics
│ │ ├── MetricsFixture.cs
│ │ └── MetricsTests.cs
│ │ ├── Projections
│ │ └── ProjectorTests.cs
│ │ ├── Registrations
│ │ └── RegistrationTests.cs
│ │ ├── Store
│ │ ├── StoreFixture.cs
│ │ ├── StoreTests.cs
│ │ └── TieredStoreTests.cs
│ │ └── Subscriptions
│ │ ├── SubscribeTests.cs
│ │ └── SubscriptionFixture.cs
└── Testing
│ └── src
│ └── Eventuous.Testing
│ ├── AggregateFactoryExtensions.cs
│ ├── AggregateSpec.cs
│ ├── AggregateWithIdSpec.cs
│ ├── CommandServiceFixture.cs
│ ├── Eventuous.Testing.csproj
│ └── InMemoryEventStore.cs
└── test
├── Directory.Build.props
├── Directory.Build.targets
├── Eventuous.Sut.App
├── BookingService.cs
├── Commands.cs
└── Eventuous.Sut.App.csproj
├── Eventuous.Sut.Domain
├── Booking.cs
├── BookingEvents.cs
├── BookingState.cs
├── Eventuous.Sut.Domain.csproj
├── Money.cs
└── StayPeriod.cs
├── Eventuous.TestHelpers.TUnit
├── Assertions.cs
├── Eventuous.TestHelpers.TUnit.csproj
├── Logging
│ ├── LoggingExtensions.cs
│ └── TUnitLogger.cs
└── TestEventListener.cs
├── Eventuous.TestHelpers
├── Eventuous.TestHelpers.csproj
├── RecordedTrace.cs
├── TestHelper.cs
└── TestPrimitives.cs
└── xunit.runner.json
/.dockerignore:
--------------------------------------------------------------------------------
1 | # Git
2 | **/.git
3 | **/.gitattributes
4 | **/.gitignore
5 |
6 | # GitLab
7 | **/.gitlab-ci.yml
8 |
9 | # JetBrains
10 | **/.idea/
11 | **/*DotSettings*
12 |
13 | # Node
14 | **/logs
15 | **/*.log
16 | **/npm-debug.log*
17 | **/yarn-debug.log*
18 | **/yarn-error.log*
19 | **/node_modules/
20 |
21 | # Visual Studio Code
22 | **/.vs
23 | **/.vscode
24 | **/*.code-workspace
25 |
26 | # .Net
27 | **/bin/
28 | **/obj/
29 | **/wwwroot/
30 | **/*.trx
31 |
32 | # Docker
33 | **/Dockerfile*
34 | **/docker-compose*
35 |
36 | # macOS
37 | **/*.DS_Store
38 | **/.AppleDouble
39 | **/.LSOverride
40 | **/._*
41 |
42 | # Others
43 | **/*.md
44 |
45 |
46 | tools/
47 | docs/
48 | artifacts/
49 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: Eventuous
4 |
5 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 |
8 | - package-ecosystem: "nuget"
9 | directory: "/"
10 | open-pull-requests-limit: 0
11 | schedule:
12 | interval: "daily"
--------------------------------------------------------------------------------
/.github/workflows/code_quality.yml.txt:
--------------------------------------------------------------------------------
1 | name: Qodana
2 | on:
3 | workflow_dispatch:
4 | pull_request:
5 | push:
6 | branches:
7 | - dev
8 |
9 | jobs:
10 | qodana:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v3
14 | with:
15 | fetch-depth: 0
16 | -
17 | name: 'Qodana Scan'
18 | uses: JetBrains/qodana-action@v2023.2
19 | with:
20 | pr-mode: false
21 | env:
22 | QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
--------------------------------------------------------------------------------
/.github/workflows/pull-request-docs.yml:
--------------------------------------------------------------------------------
1 | name: Build and test PRs with docs
2 |
3 | on:
4 | pull_request:
5 | paths:
6 | - docs/**
7 |
8 | jobs:
9 | docs:
10 | runs-on: ubuntu-latest
11 | steps:
12 | -
13 | name: Install pnpm
14 | uses: pnpm/action-setup@v4
15 | with:
16 | version: 9
17 | -
18 | name: Checkout
19 | uses: actions/checkout@v4
20 | -
21 | name: Build docs
22 | run: |
23 | cd docs
24 | pnpm install
25 | pnpm build
26 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing guidelines
2 |
3 | Here are simple rules that we expect to be followed by contributors:
4 |
5 | - Preferrably, open an issue before submitting a contribution, unless there's an existing issue you are solving.
6 | - Restrain yourself from rants and complaints when you contribute in issues and PR discussions. Respect the people who maintain this project.
7 | - Avoid large PRs addressing multiple issues at once.
8 | - Avoid making unrelated changes like reformatting the code in places that aren't related to the actual change.
9 | - Use the code formats of the repository, we have them in the `.editorconfig` file. Reformat the code accordingly if you copy it from somewhere.
10 | - Only contribute with your own work, or if you have a permission from the others to contribute their code.
11 |
12 | Thanks for contributing!
13 |
--------------------------------------------------------------------------------
/Eventuous.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
3 | True
4 | True
5 | True
--------------------------------------------------------------------------------
/docs/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
3 | };
4 |
--------------------------------------------------------------------------------
/docs/docs/diagnostics/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Diagnostics",
3 | "position": 9,
4 | "link": {
5 | "type": "generated-index",
6 | "description": "Observability of systems powered by Eventuous."
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/docs/faq/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "FAQ",
3 | "position": 100,
4 | "link": {
5 | "type": "generated-index",
6 | "description": "Find answers to most common questions here."
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/docs/faq/compatibility.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Compatibility"
3 | description: "Platforms and SDKs"
4 | ---
5 |
6 | ## Only .NET 6+? Why not .NET Framework 3.5?
7 |
8 | Eventuous uses the latest features of C#, like records and advanced pattern matching. Therefore, we rely on compiler versions which supports C# 11.
9 |
10 | We also aim to support the current application hosting model that only got consistent and stable in .NET 6+.
11 |
12 | Eventuous supports .NET Core 3.1, but it's not a priority. Some packages only support .NET 6 and .NET 7 as they need the latest features like minimal API. Right now, Eventuous provides packages for the following runtimes:
13 |
14 | - .NET Core 3.1
15 | - .NET 6
16 | - .NET 7
17 |
18 | Targets will be added and removed when getting our of support or when new versions get released.
19 |
20 |
--------------------------------------------------------------------------------
/docs/docs/infra/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Infrastructure",
3 | "position": 10,
4 | "link": {
5 | "type": "generated-index",
6 | "description": "Supported infrastructure."
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/docs/infra/elastic/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Elasticsearch"
3 | description: "Storing and archiving events in Elasticsearch"
4 | ---
5 |
6 | WIP
--------------------------------------------------------------------------------
/docs/docs/infra/mssql/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Microsoft SQL Server"
3 | description: "Supported Microsoft SQL Server infrastructure"
4 | sidebar_position: 4
5 | ---
6 |
7 |
--------------------------------------------------------------------------------
/docs/docs/infra/rabbitmq/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "RabbitMQ"
3 | description: "Producers and subscriptions for RabbitMQ"
4 | sidebar_position: 5
5 | ---
6 |
7 | WIP
--------------------------------------------------------------------------------
/docs/docs/persistence/aggregate-store/images/reading-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/persistence/aggregate-store/images/reading-dark.png
--------------------------------------------------------------------------------
/docs/docs/persistence/aggregate-store/images/reading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/persistence/aggregate-store/images/reading.png
--------------------------------------------------------------------------------
/docs/docs/persistence/aggregate-store/images/replication-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/persistence/aggregate-store/images/replication-dark.png
--------------------------------------------------------------------------------
/docs/docs/persistence/aggregate-store/images/replication.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/persistence/aggregate-store/images/replication.png
--------------------------------------------------------------------------------
/docs/docs/persistence/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Persistence"
3 | weight: 300
4 | description: >
5 | Event-sourced persistence abstractions and implementations.
6 | ---
7 | import DocCardList from '@theme/DocCardList';
8 |
9 | As mentioned in the [Prologue](../prologue), Event Sourcing is a way to persist state. Therefore, the way to handle _persistence_ is one of the fundamental differences of event-sourced systems, compared with state-based systems.
10 |
11 | Read more about essential concepts of event-sourced persistence.
12 |
13 | :::info
14 | Make sure to read about [events serialisation](serialisation).
15 | :::
16 |
17 |
--------------------------------------------------------------------------------
/docs/docs/producers/providers.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Available producers"
3 | description: "List of producers available in Eventuous"
4 | ---
5 |
6 | Eventuous supports the following producers:
7 |
8 | - [EventStoreDB](../infra/esdb/index.md#producer)
9 | - [Apache Kafka](../infra/kafka/index.md#producer)
10 | - [RabbitMQ](../infra/rabbitmq/index.md#producer)
11 | - [Google PubSub](../infra/pubsub/index.md#producer)
12 | - [Elasticsearch](../infra/elastic/index.md)
--------------------------------------------------------------------------------
/docs/docs/prologue/quick-start.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Quick start"
3 | description: "Sample application"
4 | sidebar_position: 2
5 | ---
6 |
7 | You can find a bookings sample application in the following sample repositories:
8 | - [.NET EventStoreDB write => MongoDB read](https://github.com/Eventuous/dotnet-sample)
9 | - [.NET PostgreSQL write => MongoDB read](https://github.com/Eventuous/dotnet-sample-postgres)
10 |
11 | All samples are being updated with the latest features and improvements.
12 |
--------------------------------------------------------------------------------
/docs/docs/prologue/the-right-way/images/flaming-bus.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/prologue/the-right-way/images/flaming-bus.jpg
--------------------------------------------------------------------------------
/docs/docs/prologue/the-right-way/images/the-right-way-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/prologue/the-right-way/images/the-right-way-dark.png
--------------------------------------------------------------------------------
/docs/docs/prologue/the-right-way/images/the-right-way.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/prologue/the-right-way/images/the-right-way.png
--------------------------------------------------------------------------------
/docs/docs/read-models/supported-projectors.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Supported projectors
3 | description: Built-in projectors supported by Eventuous.
4 | ---
5 |
6 | Eventuous supports the following projection targets:
7 |
8 | - MongoDB using [MongoDB projections](/docs/infra/mongodb)
9 | - PostgreSQL using [PostgreSQL projections](/docs/infra/postgres/#projections)
10 |
11 | You can project to any other database using a custom projector, which can be built as a [custom event handler](/docs/subscriptions/eventhandler/#custom-handlers).
--------------------------------------------------------------------------------
/docs/docs/subscriptions/checkpoint/images/commit-handler-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/subscriptions/checkpoint/images/commit-handler-dark.png
--------------------------------------------------------------------------------
/docs/docs/subscriptions/checkpoint/images/commit-handler.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/subscriptions/checkpoint/images/commit-handler.png
--------------------------------------------------------------------------------
/docs/docs/subscriptions/pipes/images/concurrent-filter-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/subscriptions/pipes/images/concurrent-filter-dark.png
--------------------------------------------------------------------------------
/docs/docs/subscriptions/pipes/images/concurrent-filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/subscriptions/pipes/images/concurrent-filter.png
--------------------------------------------------------------------------------
/docs/docs/subscriptions/pipes/images/default-pipe-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/subscriptions/pipes/images/default-pipe-dark.png
--------------------------------------------------------------------------------
/docs/docs/subscriptions/pipes/images/default-pipe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/subscriptions/pipes/images/default-pipe.png
--------------------------------------------------------------------------------
/docs/docs/subscriptions/pipes/images/partitioning-filter-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/subscriptions/pipes/images/partitioning-filter-dark.png
--------------------------------------------------------------------------------
/docs/docs/subscriptions/pipes/images/partitioning-filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/subscriptions/pipes/images/partitioning-filter.png
--------------------------------------------------------------------------------
/docs/docs/subscriptions/subs-concept/images/subscriptions-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/subscriptions/subs-concept/images/subscriptions-dark.png
--------------------------------------------------------------------------------
/docs/docs/subscriptions/subs-concept/images/subscriptions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/subscriptions/subs-concept/images/subscriptions.png
--------------------------------------------------------------------------------
/docs/docs/subscriptions/subs-diagnostics/images/sub-trace.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/docs/subscriptions/subs-diagnostics/images/sub-trace.png
--------------------------------------------------------------------------------
/docs/docs/whats-new.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 2
3 | ---
4 |
5 | # What's new in vNext
6 |
--------------------------------------------------------------------------------
/docs/src/components/HomepageFeatures/styles.module.css:
--------------------------------------------------------------------------------
1 | .features {
2 | display: flex;
3 | align-items: center;
4 | padding: 2rem 0;
5 | width: 100%;
6 | }
7 |
8 | .featureSvg {
9 | height: 200px;
10 | width: 200px;
11 | }
12 |
--------------------------------------------------------------------------------
/docs/src/components/highlight.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default function Highlight({children, color}) {
4 | return (
5 |
12 | {children}
13 |
14 | );
15 | }
--------------------------------------------------------------------------------
/docs/src/pages/index.module.css:
--------------------------------------------------------------------------------
1 | /**
2 | * CSS files with the .module.css suffix will be treated as CSS modules
3 | * and scoped locally.
4 | */
5 |
6 | .heroBanner {
7 | padding: 4rem 0;
8 | text-align: center;
9 | position: relative;
10 | overflow: hidden;
11 | }
12 |
13 | @media screen and (max-width: 996px) {
14 | .heroBanner {
15 | padding: 2rem;
16 | }
17 | }
18 |
19 | .buttons {
20 | display: flex;
21 | align-items: center;
22 | justify-content: center;
23 | }
24 |
--------------------------------------------------------------------------------
/docs/src/plugins/posthog/posthog.js:
--------------------------------------------------------------------------------
1 | import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
2 |
3 | export default (function () {
4 | if (!ExecutionEnvironment.canUseDOM) {
5 | return null;
6 | }
7 |
8 | return {
9 | onRouteUpdate() {
10 | window.posthog.capture('$pageview');
11 | },
12 | };
13 | })();
--------------------------------------------------------------------------------
/docs/src/plugins/segment/index.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = function (context, fromOptions) {
4 | const isProd = true; //process.env.NODE_ENV === 'production';
5 |
6 | return {
7 | name: 'segment',
8 |
9 | getClientModules() {
10 | return isProd ? [path.resolve(__dirname, './segment')] : [];
11 | },
12 | };
13 | };
--------------------------------------------------------------------------------
/docs/src/plugins/segment/segment.js:
--------------------------------------------------------------------------------
1 | import ExecutionEnvironment from "@docusaurus/ExecutionEnvironment";
2 |
3 | export default (function () {
4 | if (!ExecutionEnvironment.canUseDOM) {
5 | return null;
6 | }
7 |
8 | return {
9 | onRouteUpdate() {
10 | // if (!window.analytics) return;
11 |
12 | // setTimeout(() => window.analytics.page(), 0);
13 | },
14 | };
15 | })();
--------------------------------------------------------------------------------
/docs/static/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/static/.nojekyll
--------------------------------------------------------------------------------
/docs/static/_redirects:
--------------------------------------------------------------------------------
1 | /docs/sinks/elasticsearch/ https://connect.eventuous.dev/docs/sinks/elasticsearch/ 301
2 | /docs/deployment/ https://connect.eventuous.dev/docs/deployment/ 301
3 | /docs/custom-connector/ https://connect.eventuous.dev/docs/custom-connector/ 301
4 | /docs/category/sinks https://connect.eventuous.dev/docs/category/sinks 301
5 | /docs/category/projectors https://connect.eventuous.dev/docs/category/projectors 301
6 | /docs/sinks/grpc/ https://connect.eventuous.dev/docs/sinks/grpc/ 301
7 | /docs/projectors/grpc/ https://connect.eventuous.dev/docs/projectors/grpc/ 301
8 | /docs/sinks/sqlserver/ https://connect.eventuous.dev/docs/sinks/sqlserver/ 301
9 | /docs/sinks/mongodb/ https://connect.eventuous.dev/docs/sinks/mongodb/ 301
--------------------------------------------------------------------------------
/docs/static/img/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/static/img/android-chrome-192x192.png
--------------------------------------------------------------------------------
/docs/static/img/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/static/img/android-chrome-512x512.png
--------------------------------------------------------------------------------
/docs/static/img/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/static/img/apple-touch-icon.png
--------------------------------------------------------------------------------
/docs/static/img/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/static/img/favicon-16x16.png
--------------------------------------------------------------------------------
/docs/static/img/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/static/img/favicon-32x32.png
--------------------------------------------------------------------------------
/docs/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/static/img/favicon.ico
--------------------------------------------------------------------------------
/docs/static/img/featured-background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/static/img/featured-background.jpg
--------------------------------------------------------------------------------
/docs/static/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/static/img/logo.png
--------------------------------------------------------------------------------
/docs/static/img/site.webmanifest:
--------------------------------------------------------------------------------
1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
--------------------------------------------------------------------------------
/docs/static/img/social-card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/static/img/social-card.png
--------------------------------------------------------------------------------
/docs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // This file is not used in compilation. It is here just for a nice editor experience.
3 | "extends": "@tsconfig/docusaurus/tsconfig.json",
4 | "compilerOptions": {
5 | "baseUrl": "."
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/diagnostics/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Diagnostics",
3 | "position": 9,
4 | "link": {
5 | "type": "generated-index",
6 | "description": "Observability of applications build with Eventuous. WIP"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/diagnostics/index.md:
--------------------------------------------------------------------------------
1 | # Diagnostics
2 |
3 | Eventuous provides built-in metrics and traces for:
4 | - Event store
5 | - Subscriptions, consumers, and event handlers
6 | - Command services
7 |
8 | The built-in diagnostics integrate with [OpenTelemetry](https://opentelemetry.io/) and [Prometheus](https://prometheus.io/).
9 |
10 | The documentation for diagnostics is not complete yet. Please refer to the [samples](https://github.com/eventuous/dotnet-sample) for now. You can also find more information about diagnostics for subscriptions on the [subscriptions diagnostics](../subscriptions/subs-diagnostics) page.
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/faq/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "FAQ",
3 | "position": 100,
4 | "link": {
5 | "type": "generated-index",
6 | "description": "Find answers to most common questions here."
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/faq/compatibility.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Compatibility"
3 | description: "Platforms and SDKs"
4 | ---
5 |
6 | ## Only .NET 6+? Why not .NET Framework 3.5?
7 |
8 | Eventuous uses the latest features of C#, like records and advanced pattern matching. Therefore, we rely on compiler versions which supports C# 11.
9 |
10 | We also aim to support the current application hosting model that only got consistent and stable in .NET 6+.
11 |
12 | Eventuous supports .NET Core 3.1, but it's not a priority. Some packages only support .NET 6 and .NET 7 as they need the latest features like minimal API. Right now, Eventuous provides packages for the following runtimes:
13 |
14 | - .NET Core 3.1
15 | - .NET 6
16 | - .NET 7
17 |
18 | Targets will be added and removed when getting our of support or when new versions get released.
19 |
20 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/infra/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Infrastructure",
3 | "position": 10,
4 | "link": {
5 | "type": "generated-index",
6 | "description": "Supported infrastructure."
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/infra/elastic/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Elasticsearch"
3 | description: "Storing and archiving events in Elasticsearch"
4 | ---
5 |
6 | WIP
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/infra/kafka/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Apache Kafka"
3 | description: "Producers and subscriptions for Kafka"
4 | ---
5 |
6 | WIP
7 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/infra/mssql/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Microsoft SQL Server"
3 | description: "Supported Microsoft SQL Server infrastructure"
4 | sidebar_position: 4
5 | ---
6 |
7 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/infra/pubsub/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Google PubSub"
3 | description: "Producers and subscriptions for Google PubSub"
4 | sidebar_position: 6
5 | ---
6 |
7 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/infra/rabbitmq/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "RabbitMQ"
3 | description: "Producers and subscriptions for RabbitMQ"
4 | sidebar_position: 5
5 | ---
6 |
7 | WIP
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/persistence/aggregate-store/images/reading-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/persistence/aggregate-store/images/reading-dark.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/persistence/aggregate-store/images/reading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/persistence/aggregate-store/images/reading.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/persistence/aggregate-store/images/replication-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/persistence/aggregate-store/images/replication-dark.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/persistence/aggregate-store/images/replication.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/persistence/aggregate-store/images/replication.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/persistence/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Persistence"
3 | weight: 300
4 | description: >
5 | Event-sourced persistence abstractions and implementations.
6 | ---
7 | import DocCardList from '@theme/DocCardList';
8 |
9 | As mentioned in the [Prologue](../prologue), Event Sourcing is a way to persist state. Therefore, the way to handle _persistence_ is one of the fundamental differences of event-sourced systems, compared with state-based systems.
10 |
11 | Read more about essential concepts of event-sourced persistence.
12 |
13 | :::info
14 | Make sure to read about [events serialisation](serialisation).
15 | :::
16 |
17 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/producers/providers.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Available producers"
3 | description: "List of producers available in Eventuous"
4 | ---
5 |
6 | Eventuous supports the following producers:
7 |
8 | - [RabbitMQ](../infra/rabbitmq)
9 | - [EventStoreDB](../infra/esdb/#producer)
10 | - [Google PubSub](../infra/pubsub)
11 | - [Apache Kafka](../infra/kafka)
12 | - [Elasticsearch](../infra/elastic)
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/prologue/quick-start.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Quick start"
3 | description: "Sample application"
4 | sidebar_position: 2
5 | ---
6 |
7 | You can find a bookings sample application in the following sample repositories:
8 | - [.NET EventStoreDB write => MongoDB read](https://github.com/Eventuous/dotnet-sample)
9 | - [.NET PostgreSQL write => MongoDB read](https://github.com/Eventuous/dotnet-sample-postgres)
10 |
11 | All samples are being updated with the latest features and improvements.
12 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/prologue/the-right-way/images/flaming-bus.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/prologue/the-right-way/images/flaming-bus.jpg
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/prologue/the-right-way/images/the-right-way-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/prologue/the-right-way/images/the-right-way-dark.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/prologue/the-right-way/images/the-right-way.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/prologue/the-right-way/images/the-right-way.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/read-models/supported-projectors.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Supported projectors
3 | description: Built-in projectors supported by Eventuous.
4 | ---
5 |
6 | Eventuous supports the following projection targets:
7 |
8 | - MongoDB using [MongoDB projections](/docs/infra/mongodb)
9 | - PostgreSQL using [PostgreSQL projections](/docs/infra/postgres/#projections)
10 |
11 | You can project to any other database using a custom projector, which can be built as a [custom event handler](/docs/subscriptions/eventhandler/#custom-handlers).
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/subscriptions/checkpoint/images/commit-handler-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/subscriptions/checkpoint/images/commit-handler-dark.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/subscriptions/checkpoint/images/commit-handler.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/subscriptions/checkpoint/images/commit-handler.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/subscriptions/pipes/images/concurrent-filter-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/subscriptions/pipes/images/concurrent-filter-dark.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/subscriptions/pipes/images/concurrent-filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/subscriptions/pipes/images/concurrent-filter.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/subscriptions/pipes/images/default-pipe-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/subscriptions/pipes/images/default-pipe-dark.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/subscriptions/pipes/images/default-pipe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/subscriptions/pipes/images/default-pipe.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/subscriptions/pipes/images/partitioning-filter-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/subscriptions/pipes/images/partitioning-filter-dark.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/subscriptions/pipes/images/partitioning-filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/subscriptions/pipes/images/partitioning-filter.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/subscriptions/subs-concept/images/subscriptions-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/subscriptions/subs-concept/images/subscriptions-dark.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/subscriptions/subs-concept/images/subscriptions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/subscriptions/subs-concept/images/subscriptions.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.14/subscriptions/subs-diagnostics/images/sub-trace.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.14/subscriptions/subs-diagnostics/images/sub-trace.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/application/_service_http.mdx:
--------------------------------------------------------------------------------
1 | ## Application HTTP API
2 |
3 | The most common use case is to connect the command service to an HTTP API using controllers or minimal API mappings.
4 |
5 | Read the [Command API](./command-api) feature documentation for more details.
6 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/application/_service_no_throw.mdx:
--------------------------------------------------------------------------------
1 | :::caution Handling failures
2 | The last point above translates to: the command service **does not throw exceptions**. It [returns](#result) an instance of `Result.Error` instead. It is your responsibility to handle the error.
3 | :::
4 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/application/_service_registration.mdx:
--------------------------------------------------------------------------------
1 | ## Bootstrap
2 |
3 | If you registered an implementation of `IEventStore` in the DI container, you can also register the command service:
4 |
5 | ```csharp title="Program.cs"
6 | builder.Services.AddCommandService();
7 | ```
8 |
9 | The `AddCommandService` extension will register the `BookingService`, and also as `ICommandService`, as a singleton. Remember that all the DI extensions are part of the `Eventuous.Extensions.DependencyInjection` NuGet package.
10 |
11 | When you also use `AddControllers`, you get the command service injected to your controllers.
12 |
13 | You can simplify your application and avoid creating HTTP endpoints explicitly (as controllers or minimal API endpoints) if you use the [command API feature](command-api.md).
14 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/diagnostics/logs.md:
--------------------------------------------------------------------------------
1 | # Logging
2 |
3 | Eventuous uses the ASP.NET Core logging with `ILoggerFactory` and `ILogger`, so you can use the standard logging facilities to log diagnostics. For internal logging, Eventuous uses multiple [event sources](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/eventsource), which you can collect and analyse with tools like `dotnet-trace`.
4 |
5 | It's also possible to expose internal Eventuous logs using the `UseEventuousLogs` extension for `IHost`, which is available as part of `Eventuous.Extensions.DependencyInjection` package.
6 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/faq/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "FAQ",
3 | "position": 100,
4 | "link": {
5 | "type": "generated-index",
6 | "description": "Find answers to most common questions here."
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/faq/compatibility.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Compatibility"
3 | description: "Platforms and SDKs"
4 | ---
5 |
6 | ## Only .NET 6+? Why not .NET Framework 3.5?
7 |
8 | Eventuous uses the latest features of C#, like records and advanced pattern matching. Therefore, we rely on compiler versions which supports C# 11.
9 |
10 | We also aim to support the current application hosting model that only got consistent and stable in .NET 6+.
11 |
12 | Eventuous supports .NET Core 3.1, but it's not a priority. Some packages only support .NET 6 and .NET 8 as they need the latest features like minimal API. Right now, Eventuous provides packages for the following runtimes:
13 |
14 | - .NET 6
15 | - .NET 8
16 |
17 | Targets will be added and removed when getting our of support or when new versions get released.
18 |
19 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/infra/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Infrastructure",
3 | "position": 10,
4 | "link": {
5 | "type": "generated-index",
6 | "description": "Supported infrastructure."
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/infra/elastic/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Elasticsearch"
3 | description: "Storing and archiving events in Elasticsearch"
4 | ---
5 |
6 | WIP
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/persistence/images/reading-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/persistence/images/reading-dark.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/persistence/images/reading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/persistence/images/reading.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/persistence/images/replication-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/persistence/images/replication-dark.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/persistence/images/replication.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/persistence/images/replication.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/persistence/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Persistence"
3 | weight: 300
4 | description: >
5 | Event-sourced persistence abstractions and implementations.
6 | ---
7 | import DocCardList from '@theme/DocCardList';
8 |
9 | As mentioned in the [Prologue](../prologue), Event Sourcing is a way to persist state. Therefore, the way to handle _persistence_ is one of the fundamental differences of event-sourced systems, compared with state-based systems.
10 |
11 | Read more about essential concepts of event-sourced persistence.
12 |
13 | :::info
14 | Make sure to read about [events serialisation](serialisation).
15 | :::
16 |
17 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/producers/providers.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Available producers"
3 | description: "List of producers available in Eventuous"
4 | ---
5 |
6 | Eventuous supports the following producers:
7 |
8 | - [EventStoreDB](../infra/esdb/index.md#producer)
9 | - [Apache Kafka](../infra/kafka/index.md#producer)
10 | - [RabbitMQ](../infra/rabbitmq/index.md#producer)
11 | - [Google PubSub](../infra/pubsub/index.md#producer)
12 | - [Elasticsearch](../infra/elastic/index.md)
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/prologue/quick-start.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Quick start"
3 | description: "Sample application"
4 | sidebar_position: 2
5 | ---
6 |
7 | You can find a bookings sample application in the following sample repositories:
8 | - [.NET EventStoreDB write => MongoDB read](https://github.com/Eventuous/dotnet-sample)
9 | - [.NET PostgreSQL write => MongoDB read](https://github.com/Eventuous/dotnet-sample-postgres)
10 |
11 | All samples are being updated with the latest features and improvements.
12 |
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/prologue/the-right-way/images/flaming-bus.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/prologue/the-right-way/images/flaming-bus.jpg
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/prologue/the-right-way/images/the-right-way-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/prologue/the-right-way/images/the-right-way-dark.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/prologue/the-right-way/images/the-right-way.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/prologue/the-right-way/images/the-right-way.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/read-models/supported-projectors.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Supported projectors
3 | description: Built-in projectors supported by Eventuous.
4 | ---
5 |
6 | Eventuous supports the following projection targets:
7 |
8 | - MongoDB using [MongoDB projections](/docs/infra/mongodb)
9 | - PostgreSQL using [PostgreSQL projections](/docs/infra/postgres/#projections)
10 |
11 | You can project to any other database using a custom projector, which can be built as a [custom event handler](/docs/subscriptions/eventhandler/#custom-handlers).
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/subscriptions/checkpoint/images/commit-handler-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/subscriptions/checkpoint/images/commit-handler-dark.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/subscriptions/checkpoint/images/commit-handler.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/subscriptions/checkpoint/images/commit-handler.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/subscriptions/pipes/images/concurrent-filter-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/subscriptions/pipes/images/concurrent-filter-dark.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/subscriptions/pipes/images/concurrent-filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/subscriptions/pipes/images/concurrent-filter.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/subscriptions/pipes/images/default-pipe-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/subscriptions/pipes/images/default-pipe-dark.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/subscriptions/pipes/images/default-pipe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/subscriptions/pipes/images/default-pipe.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/subscriptions/pipes/images/partitioning-filter-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/subscriptions/pipes/images/partitioning-filter-dark.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/subscriptions/pipes/images/partitioning-filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/subscriptions/pipes/images/partitioning-filter.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/subscriptions/subs-concept/images/subscriptions-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/subscriptions/subs-concept/images/subscriptions-dark.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/subscriptions/subs-concept/images/subscriptions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/subscriptions/subs-concept/images/subscriptions.png
--------------------------------------------------------------------------------
/docs/versioned_docs/version-0.15/subscriptions/subs-diagnostics/images/sub-trace.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/docs/versioned_docs/version-0.15/subscriptions/subs-diagnostics/images/sub-trace.png
--------------------------------------------------------------------------------
/docs/versions.json:
--------------------------------------------------------------------------------
1 | [
2 | "0.15",
3 | "0.14"
4 | ]
5 |
--------------------------------------------------------------------------------
/e-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eventuous/eventuous/035e3921d9f90bca3fd40551a890cdf4075fff4d/e-logo.png
--------------------------------------------------------------------------------
/props/Common.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/qodana.yaml:
--------------------------------------------------------------------------------
1 | version: "1.0"
2 | linter: jetbrains/qodana-dotnet:2023.2
3 | dotnet:
4 | solution: Eventuous.sln
--------------------------------------------------------------------------------
/samples/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0
4 | enable
5 | enable
6 | preview
7 | false
8 | $([System.IO.Directory]::GetParent($(MSBuildThisFileDirectory)).Parent.FullName)
9 | $(RepoRoot)\src\Core\src
10 | $(RepoRoot)\src
11 | Debug;Release
12 |
13 |
14 |
--------------------------------------------------------------------------------
/samples/esdb/Bookings.Domain/Bookings.Domain.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Debug;Release
4 | AnyCPU
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/samples/esdb/Bookings.Domain/Bookings/BookingId.cs:
--------------------------------------------------------------------------------
1 | using Eventuous;
2 |
3 | namespace Bookings.Domain.Bookings;
4 |
5 | public record BookingId(string Value) : Id(Value);
--------------------------------------------------------------------------------
/samples/esdb/Bookings.Domain/DomainModule.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 | using System.Runtime.CompilerServices;
3 | using Eventuous;
4 |
5 | namespace Bookings.Domain;
6 |
7 | static class DomainModule {
8 | [ModuleInitializer]
9 | [SuppressMessage("Usage", "CA2255", MessageId = "The \'ModuleInitializer\' attribute should not be used in libraries")]
10 | internal static void InitializeDomainModule() => TypeMap.RegisterKnownEventTypes();
11 | }
--------------------------------------------------------------------------------
/samples/esdb/Bookings.Domain/RoomId.cs:
--------------------------------------------------------------------------------
1 | using Eventuous;
2 |
3 | namespace Bookings.Domain;
4 |
5 | public record RoomId(string Value) : Id(Value);
--------------------------------------------------------------------------------
/samples/esdb/Bookings.Domain/Services.cs:
--------------------------------------------------------------------------------
1 | namespace Bookings.Domain;
2 |
3 | public static class Services {
4 | public delegate ValueTask IsRoomAvailable(RoomId roomId, StayPeriod period);
5 |
6 | public delegate Money ConvertCurrency(Money from, string targetCurrency);
7 | }
--------------------------------------------------------------------------------
/samples/esdb/Bookings.Domain/StayPeriod.cs:
--------------------------------------------------------------------------------
1 | using Eventuous;
2 | using NodaTime;
3 |
4 | namespace Bookings.Domain;
5 |
6 | public record StayPeriod {
7 | public LocalDate CheckIn { get; }
8 | public LocalDate CheckOut { get; }
9 |
10 | internal StayPeriod() { }
11 |
12 | public StayPeriod(LocalDate checkIn, LocalDate checkOut) {
13 | if (checkIn > checkOut) throw new DomainException("Check in date must be before check out date");
14 |
15 | (CheckIn, CheckOut) = (checkIn, checkOut);
16 | }
17 | }
--------------------------------------------------------------------------------
/samples/esdb/Bookings.Payments/Application/CommandApi.cs:
--------------------------------------------------------------------------------
1 | using Bookings.Payments.Domain;
2 | using Eventuous;
3 | using Eventuous.Extensions.AspNetCore;
4 | using Microsoft.AspNetCore.Mvc;
5 | using static Bookings.Payments.Application.PaymentCommands;
6 |
7 | namespace Bookings.Payments.Application;
8 |
9 | [Route("payment")]
10 | public class CommandApi(ICommandService service) : CommandHttpApiBase(service) {
11 | [HttpPost]
12 | public Task.Ok>> RegisterPayment([FromBody] RecordPayment cmd, CancellationToken cancellationToken)
13 | => Handle(cmd, cancellationToken);
14 | }
--------------------------------------------------------------------------------
/samples/esdb/Bookings.Payments/Domain/Payment.cs:
--------------------------------------------------------------------------------
1 | using Eventuous;
2 | using static Bookings.Payments.Domain.PaymentEvents;
3 |
4 | namespace Bookings.Payments.Domain;
5 |
6 | public class Payment : Aggregate {
7 | public void ProcessPayment(string bookingId, Money amount, string method, string provider)
8 | => Apply(new PaymentRecorded(bookingId, amount.Amount, amount.Currency, method, provider));
9 | }
10 |
11 | public record PaymentState : State {
12 | public string BookingId { get; init; } = null!;
13 | public float Amount { get; init; }
14 |
15 | public PaymentState() {
16 | On((state, recorded) => state with { BookingId = recorded.BookingId, Amount = recorded.Amount });
17 | }
18 | }
19 |
20 | public record PaymentId(string Value) : Id(Value);
21 |
--------------------------------------------------------------------------------
/samples/esdb/Bookings.Payments/Domain/PaymentEvents.cs:
--------------------------------------------------------------------------------
1 | using Eventuous;
2 |
3 | namespace Bookings.Payments.Domain;
4 |
5 | public static class PaymentEvents {
6 | [EventType("PaymentRecorded")]
7 | public record PaymentRecorded(string BookingId, float Amount, string Currency, string Method, string Provider);
8 | }
9 |
--------------------------------------------------------------------------------
/samples/esdb/Bookings.Payments/Infrastructure/Mongo.cs:
--------------------------------------------------------------------------------
1 | using MongoDB.Driver;
2 | using MongoDB.Driver.Core.Extensions.DiagnosticSources;
3 |
4 | namespace Bookings.Payments.Infrastructure;
5 |
6 | public static class Mongo {
7 | public static IMongoDatabase ConfigureMongo(IConfiguration configuration) {
8 | var settings = MongoClientSettings.FromConnectionString(configuration["Mongo:ConnectionString"]);
9 | settings.ClusterConfigurator = cb => cb.Subscribe(new DiagnosticsActivityEventSubscriber());
10 | return new MongoClient(settings).GetDatabase(configuration["Mongo:Database"]);
11 | }
12 | }
--------------------------------------------------------------------------------
/samples/esdb/Bookings.Payments/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Mongo": {
3 | "ConnectionString": "mongodb://mongoadmin:secret@localhost:27017",
4 | "Database": "Payments"
5 | },
6 | "EventStore": {
7 | "ConnectionString": "esdb://localhost:2113?tls=false"
8 | },
9 | "Logging": {
10 | "LogLevel": {
11 | "Default": "Debug",
12 | "Microsoft.AspNetCore": "Warning"
13 | }
14 | },
15 | "AllowedHosts": "*"
16 | }
17 |
--------------------------------------------------------------------------------
/samples/esdb/Bookings/.dockerignore:
--------------------------------------------------------------------------------
1 | **/.dockerignore
2 | **/.env
3 | **/.git
4 | **/.gitignore
5 | **/.project
6 | **/.settings
7 | **/.toolstarget
8 | **/.vs
9 | **/.vscode
10 | **/.idea
11 | **/*.*proj.user
12 | **/*.dbmdl
13 | **/*.jfm
14 | **/azds.yaml
15 | **/bin
16 | **/charts
17 | **/docker-compose*
18 | **/Dockerfile*
19 | **/node_modules
20 | **/npm-debug.log
21 | **/obj
22 | **/secrets.dev.yaml
23 | **/values.dev.yaml
24 | LICENSE
25 | README.md
--------------------------------------------------------------------------------
/samples/esdb/Bookings/Application/BookingsQueryService.cs:
--------------------------------------------------------------------------------
1 | using Bookings.Application.Queries;
2 | using Eventuous.Projections.MongoDB.Tools;
3 | using MongoDB.Driver;
4 |
5 | namespace Bookings.Application;
6 |
7 | public class BookingsQueryService(IMongoDatabase database) {
8 | public async Task GetUserBookings(string userId) => await database.LoadDocument(userId);
9 | }
10 |
--------------------------------------------------------------------------------
/samples/esdb/Bookings/Application/Commands.cs:
--------------------------------------------------------------------------------
1 | namespace Bookings.Application;
2 |
3 | public static class BookingCommands {
4 | public record BookRoom(
5 | string BookingId,
6 | string GuestId,
7 | string RoomId,
8 | DateTime CheckInDate,
9 | DateTime CheckOutDate,
10 | float BookingPrice,
11 | float PrepaidAmount,
12 | string Currency,
13 | DateTimeOffset BookingDate
14 | );
15 |
16 | public record RecordPayment(string BookingId, float PaidAmount, string Currency, string PaymentId, string PaidBy);
17 | }
--------------------------------------------------------------------------------
/samples/esdb/Bookings/Application/Queries/BookingDocument.cs:
--------------------------------------------------------------------------------
1 | using Eventuous.Projections.MongoDB.Tools;
2 | using NodaTime;
3 |
4 | // ReSharper disable UnusedAutoPropertyAccessor.Global
5 | namespace Bookings.Application.Queries;
6 |
7 | public record BookingDocument(string Id) : ProjectedDocument(Id) {
8 | public string GuestId { get; init; } = null!;
9 | public string RoomId { get; init; } = null!;
10 | public LocalDate CheckInDate { get; init; }
11 | public LocalDate CheckOutDate { get; init; }
12 | public float BookingPrice { get; init; }
13 | public float PaidAmount { get; init; }
14 | public float Outstanding { get; init; }
15 | public bool Paid { get; init; }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/esdb/Bookings/Application/Queries/MyBookings.cs:
--------------------------------------------------------------------------------
1 | using Eventuous.Projections.MongoDB.Tools;
2 | using NodaTime;
3 |
4 | // ReSharper disable CollectionNeverUpdated.Global
5 |
6 | namespace Bookings.Application.Queries;
7 |
8 | public record MyBookings(string Id) : ProjectedDocument(Id) {
9 | public List Bookings { get; init; } = [];
10 |
11 | public record Booking(string BookingId, LocalDate CheckInDate, LocalDate CheckOutDate, float Price);
12 | }
13 |
--------------------------------------------------------------------------------
/samples/esdb/Bookings/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
2 | WORKDIR /app
3 |
4 | FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
5 | WORKDIR /src
6 | COPY . .
7 | RUN dotnet restore "Bookings/Bookings.csproj"
8 | WORKDIR "/src/Bookings"
9 | RUN dotnet build "Bookings.csproj" -c Release -o /app/build
10 |
11 | FROM build AS publish
12 | RUN dotnet publish "Bookings.csproj" -c Release -o /app/publish
13 |
14 | FROM base AS final
15 | WORKDIR /app
16 | COPY --from=publish /app/publish .
17 | ENTRYPOINT ["dotnet", "Bookings.dll"]
18 |
--------------------------------------------------------------------------------
/samples/esdb/Bookings/HttpApi/Bookings/QueryApi.cs:
--------------------------------------------------------------------------------
1 | using Bookings.Domain.Bookings;
2 | using Eventuous;
3 | using Microsoft.AspNetCore.Mvc;
4 |
5 | namespace Bookings.HttpApi.Bookings;
6 |
7 | [Route("/bookings")]
8 | public class QueryApi(IEventStore store) : ControllerBase {
9 | readonly StreamNameMap _streamNameMap = new();
10 |
11 | [HttpGet]
12 | [Route("{id}")]
13 | public async Task GetBooking(string id, CancellationToken cancellationToken) {
14 | var booking = await store.LoadState(_streamNameMap, new(id), cancellationToken: cancellationToken);
15 |
16 | return booking.State;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/samples/esdb/Bookings/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Mongo": {
3 | "ConnectionString": "mongodb://localhost:27017",
4 | "User": "mongoadmin",
5 | "Password": "secret",
6 | "Database": "Bookings"
7 | },
8 | "EventStore": {
9 | "ConnectionString": "esdb://localhost:2113?tls=false"
10 | },
11 | "AllowedHosts": "*"
12 | }
13 |
--------------------------------------------------------------------------------
/samples/esdb/deploy/cloudrun/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 | /node_modules/
3 |
--------------------------------------------------------------------------------
/samples/esdb/deploy/cloudrun/Pulumi.dev.yaml:
--------------------------------------------------------------------------------
1 | config:
2 | cloudrun:esdbConnectionString:
3 | secure: AAABAKUgHNKrbteWTPdchE2RY5ylwiVqxpW2ONz3gXXnxrXrIt/51Zv/J072LgF1mK/NCMUogwpOjLAmdw8LL+G7oLxia3CvYod7lZNsbZOficHj2PE2ylICMt94/ONgQMX1H5JfjyqW6LXmChOV
4 | cloudrun:mongoConnectionString:
5 | secure: AAABAInFo85SooX04/SqvBOQT0oFJK9Safq2WBdt9LeGCW+8zBBfQ7iKrVG0CJceIN+ksDX3IVtk0E97oASgoOILME98t2ndNpTSruMogg==
6 | cloudrun:otelEndpoint: https://api.honeycomb.io
7 | cloudrun:otelHeaders:
8 | secure: AAABAOFb1napHEajKJ8i6tunpIwh/iW3bE25DZv7kRtV6fO2w++F+WrU67GzOtJudV2ig5cWy2KSn5snthaoXeWQIl3lzLlaRlJDwyZz0q5G5ECYWckzj8HEhb3Cs/pkxazAcPvrmBXDExhEhwYu0Q==
9 | cloudrun:vpcConnectorName: vpc-connector-044a222
10 | gcp:project: esc-platform-advocacy
11 | gcp:region: europe-west2
12 |
--------------------------------------------------------------------------------
/samples/esdb/deploy/cloudrun/Pulumi.yaml:
--------------------------------------------------------------------------------
1 | name: cloudrun
2 | runtime: nodejs
3 | description: Eventuous sample application deployment to Google Cloud Run
4 |
--------------------------------------------------------------------------------
/samples/esdb/deploy/cloudrun/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cloudrun",
3 | "devDependencies": {
4 | "@types/node": "^20.14.2"
5 | },
6 | "dependencies": {
7 | "@pulumi/docker": "^4.5.4",
8 | "@pulumi/gcp": "^7.27.0",
9 | "@pulumi/pulumi": "^3.120.0",
10 | "@opentelemetry/api": "^1.9.0"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/samples/esdb/deploy/cloudrun/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "outDir": "bin",
5 | "target": "es2016",
6 | "module": "commonjs",
7 | "moduleResolution": "node",
8 | "sourceMap": true,
9 | "experimentalDecorators": true,
10 | "pretty": true,
11 | "noFallthroughCasesInSwitch": true,
12 | "noImplicitReturns": true,
13 | "forceConsistentCasingInFileNames": true
14 | },
15 | "files": [
16 | "index.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/samples/esdb/grafana/__inputs.json:
--------------------------------------------------------------------------------
1 | {
2 | "__inputs": [
3 | {
4 | "name": "DS_PROMETHEUS",
5 | "label": "prometheus",
6 | "description": "Default data source",
7 | "type": "datasource",
8 | "pluginId": "prometheus",
9 | "pluginName": "Prometheus"
10 | }
11 | ]
12 | }
--------------------------------------------------------------------------------
/samples/esdb/grafana/datasources.yml:
--------------------------------------------------------------------------------
1 | apiVersion: 1
2 |
3 | datasources:
4 | - name: prometheus
5 | type: prometheus
6 | access: proxy
7 | orgId: 1
8 | url: http://prometheus:9090
9 | isDefault: true
10 | version: 1
11 | editable: false
--------------------------------------------------------------------------------
/samples/esdb/prometheus/prometheus.yml:
--------------------------------------------------------------------------------
1 | global:
2 | scrape_interval: 5s
3 |
4 | scrape_configs:
5 | - job_name: 'prometheus'
6 | static_configs:
7 | - targets: ['localhost:9090']
8 | - job_name: 'bookings'
9 | static_configs:
10 | - targets:
11 | - 'host.docker.internal:5000'
--------------------------------------------------------------------------------
/samples/postgres/Bookings.Domain/Bookings.Domain.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Debug;Release
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/samples/postgres/Bookings.Payments/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Mongo": {
3 | "ConnectionString": "mongodb://mongoadmin:secret@localhost:27017",
4 | "Database": "Payments"
5 | },
6 | "Postgres": {
7 | "ConnectionString": "Host=localhost;Username=postgres;Password=secret;Database=eventuous;Include Error Detail=true;",
8 | "Schema": "payments",
9 | "InitializeDatabase": true
10 | },
11 | "RabbitMq": {
12 | "ConnectionString": "amqp://guest:guest@localhost:5672/"
13 | },
14 | "Logging": {
15 | "LogLevel": {
16 | "Default": "Debug",
17 | "Microsoft.AspNetCore": "Warning"
18 | }
19 | },
20 | "AllowedHosts": "*"
21 | }
22 |
--------------------------------------------------------------------------------
/samples/postgres/Bookings/.dockerignore:
--------------------------------------------------------------------------------
1 | **/.dockerignore
2 | **/.env
3 | **/.git
4 | **/.gitignore
5 | **/.project
6 | **/.settings
7 | **/.toolstarget
8 | **/.vs
9 | **/.vscode
10 | **/.idea
11 | **/*.*proj.user
12 | **/*.dbmdl
13 | **/*.jfm
14 | **/azds.yaml
15 | **/bin
16 | **/charts
17 | **/docker-compose*
18 | **/Dockerfile*
19 | **/node_modules
20 | **/npm-debug.log
21 | **/obj
22 | **/secrets.dev.yaml
23 | **/values.dev.yaml
24 | LICENSE
25 | README.md
--------------------------------------------------------------------------------
/samples/postgres/Bookings/Application/Commands.cs:
--------------------------------------------------------------------------------
1 | namespace Bookings.Application;
2 |
3 | public static class BookingCommands {
4 | public record BookRoom(
5 | string BookingId,
6 | string GuestId,
7 | string RoomId,
8 | DateTime CheckInDate,
9 | DateTime CheckOutDate,
10 | float BookingPrice,
11 | float PrepaidAmount,
12 | string Currency,
13 | DateTimeOffset BookingDate
14 | );
15 |
16 | public record RecordPayment(string BookingId, float PaidAmount, string Currency, string PaymentId, string PaidBy);
17 | }
--------------------------------------------------------------------------------
/samples/postgres/Bookings/Application/Queries/BookingDocument.cs:
--------------------------------------------------------------------------------
1 | using Eventuous.Projections.MongoDB.Tools;
2 | using NodaTime;
3 |
4 | // ReSharper disable UnusedAutoPropertyAccessor.Global
5 |
6 | namespace Bookings.Application.Queries;
7 |
8 | public record BookingDocument(string Id) : ProjectedDocument(Id) {
9 | public string? GuestId { get; init; }
10 | public string? RoomId { get; init; }
11 | public LocalDate CheckInDate { get; init; }
12 | public LocalDate CheckOutDate { get; init; }
13 | public float BookingPrice { get; init; }
14 | public float PaidAmount { get; init; }
15 | public float Outstanding { get; init; }
16 | public bool Paid { get; init; }
17 | }
18 |
--------------------------------------------------------------------------------
/samples/postgres/Bookings/Application/Queries/MyBookings.cs:
--------------------------------------------------------------------------------
1 | using Eventuous.Projections.MongoDB.Tools;
2 | using NodaTime;
3 |
4 | namespace Bookings.Application.Queries;
5 |
6 | public record MyBookings : ProjectedDocument {
7 | public MyBookings(string id) : base(id) { }
8 |
9 | public List Bookings { get; init; } = new();
10 |
11 | public record Booking(string BookingId, LocalDate CheckInDate, LocalDate CheckOutDate, float Price);
12 | }
--------------------------------------------------------------------------------
/samples/postgres/Bookings/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
2 | WORKDIR /app
3 |
4 | FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
5 | WORKDIR /src
6 | COPY . .
7 | RUN dotnet restore "Bookings/Bookings.csproj"
8 | WORKDIR "/src/Bookings"
9 | RUN dotnet build "Bookings.csproj" -c Release -o /app/build
10 |
11 | FROM build AS publish
12 | RUN dotnet publish "Bookings.csproj" -c Release -o /app/publish
13 |
14 | FROM base AS final
15 | WORKDIR /app
16 | COPY --from=publish /app/publish .
17 | ENTRYPOINT ["dotnet", "Bookings.dll"]
18 |
--------------------------------------------------------------------------------
/samples/postgres/Bookings/HttpApi/Bookings/QueryApi.cs:
--------------------------------------------------------------------------------
1 | using Bookings.Domain.Bookings;
2 | using Eventuous;
3 | using Microsoft.AspNetCore.Mvc;
4 |
5 | namespace Bookings.HttpApi.Bookings;
6 |
7 | [Route("/bookings")]
8 | public class QueryApi(IEventReader store) : ControllerBase {
9 | readonly StreamNameMap _streamNameMap = new();
10 |
11 | [HttpGet]
12 | [Route("{id}")]
13 | public async Task GetBooking(string id, CancellationToken cancellationToken) {
14 | var booking = await store.LoadState(_streamNameMap, new(id), cancellationToken: cancellationToken);
15 |
16 | return booking.State;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/samples/postgres/Bookings/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Mongo": {
3 | "ConnectionString": "mongodb://localhost:27017",
4 | "User": "mongoadmin",
5 | "Password": "secret",
6 | "Database": "Bookings"
7 | },
8 | "Postgres": {
9 | "ConnectionString": "Host=localhost;Username=postgres;Password=secret;Database=eventuous;Include Error Detail=true;",
10 | "Schema": "bookings",
11 | "InitializeDatabase": true
12 | },
13 | "RabbitMq": {
14 | "ConnectionString": "amqp://guest:guest@localhost:5672/"
15 | },
16 | "AllowedHosts": "*"
17 | }
18 |
--------------------------------------------------------------------------------
/samples/postgres/deploy/cloudrun/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 | /node_modules/
3 |
--------------------------------------------------------------------------------
/samples/postgres/deploy/cloudrun/Pulumi.dev.yaml:
--------------------------------------------------------------------------------
1 | config:
2 | cloudrun:esdbConnectionString:
3 | secure: AAABAKUgHNKrbteWTPdchE2RY5ylwiVqxpW2ONz3gXXnxrXrIt/51Zv/J072LgF1mK/NCMUogwpOjLAmdw8LL+G7oLxia3CvYod7lZNsbZOficHj2PE2ylICMt94/ONgQMX1H5JfjyqW6LXmChOV
4 | cloudrun:mongoConnectionString:
5 | secure: AAABAInFo85SooX04/SqvBOQT0oFJK9Safq2WBdt9LeGCW+8zBBfQ7iKrVG0CJceIN+ksDX3IVtk0E97oASgoOILME98t2ndNpTSruMogg==
6 | cloudrun:otelEndpoint: https://api.honeycomb.io
7 | cloudrun:otelHeaders:
8 | secure: AAABAOFb1napHEajKJ8i6tunpIwh/iW3bE25DZv7kRtV6fO2w++F+WrU67GzOtJudV2ig5cWy2KSn5snthaoXeWQIl3lzLlaRlJDwyZz0q5G5ECYWckzj8HEhb3Cs/pkxazAcPvrmBXDExhEhwYu0Q==
9 | cloudrun:vpcConnectorName: vpc-connector-044a222
10 | gcp:project: esc-platform-advocacy
11 | gcp:region: europe-west2
12 |
--------------------------------------------------------------------------------
/samples/postgres/deploy/cloudrun/Pulumi.yaml:
--------------------------------------------------------------------------------
1 | name: cloudrun
2 | runtime: nodejs
3 | description: Eventuous sample application deployment to Google Cloud Run
4 |
--------------------------------------------------------------------------------
/samples/postgres/deploy/cloudrun/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cloudrun",
3 | "devDependencies": {
4 | "@types/node": "^20.14.2"
5 | },
6 | "dependencies": {
7 | "@pulumi/docker": "^4.5.4",
8 | "@pulumi/gcp": "^7.27.0",
9 | "@pulumi/pulumi": "^3.120.0",
10 | "@opentelemetry/api": "^1.9.0"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/samples/postgres/deploy/cloudrun/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "outDir": "bin",
5 | "target": "es2016",
6 | "module": "commonjs",
7 | "moduleResolution": "node",
8 | "sourceMap": true,
9 | "experimentalDecorators": true,
10 | "pretty": true,
11 | "noFallthroughCasesInSwitch": true,
12 | "noImplicitReturns": true,
13 | "forceConsistentCasingInFileNames": true
14 | },
15 | "files": [
16 | "index.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/samples/postgres/grafana/__inputs.json:
--------------------------------------------------------------------------------
1 | {
2 | "__inputs": [
3 | {
4 | "name": "DS_PROMETHEUS",
5 | "label": "prometheus",
6 | "description": "Default data source",
7 | "type": "datasource",
8 | "pluginId": "prometheus",
9 | "pluginName": "Prometheus"
10 | }
11 | ]
12 | }
--------------------------------------------------------------------------------
/samples/postgres/grafana/datasources.yml:
--------------------------------------------------------------------------------
1 | apiVersion: 1
2 |
3 | datasources:
4 | - name: prometheus
5 | type: prometheus
6 | access: proxy
7 | orgId: 1
8 | url: http://prometheus:9090
9 | isDefault: true
10 | version: 1
11 | editable: false
--------------------------------------------------------------------------------
/samples/postgres/prometheus/prometheus.yml:
--------------------------------------------------------------------------------
1 | global:
2 | scrape_interval: 5s
3 |
4 | scrape_configs:
5 | - job_name: 'prometheus'
6 | static_configs:
7 | - targets: ['localhost:9090']
8 | - job_name: 'bookings'
9 | static_configs:
10 | - targets:
11 | - 'host.docker.internal:5000'
--------------------------------------------------------------------------------
/src/Benchmarks/Benchmarks/Benchmarks.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Exe
4 | false
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/Benchmarks/Benchmarks/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using BenchmarkDotNet.Running;
3 |
4 | BenchmarkRunner.Run(Assembly.GetExecutingAssembly());
5 |
--------------------------------------------------------------------------------
/src/Core/Eventuous.Core.slnf:
--------------------------------------------------------------------------------
1 | {
2 | "solution": {
3 | "path": "..\\..\\Eventuous.sln",
4 | "projects": [
5 | "src\\Core\\src\\Eventuous\\Eventuous.csproj",
6 | "src\\Core\\src\\Eventuous.Subscriptions\\Eventuous.Subscriptions.csproj",
7 | "src\\Core\\src\\Eventuous.Producers\\Eventuous.Producers.csproj",
8 | "src\\Core\\test\\Eventuous.Tests\\Eventuous.Tests.csproj",
9 | "test\\Eventuous.Sut.Domain\\Eventuous.Sut.Domain.csproj",
10 | "test\\Eventuous.Sut.App\\Eventuous.Sut.App.csproj"
11 | ]
12 | }
13 | }
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Application/AggregateService/CommandServiceDelegates.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ.All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous;
5 |
6 | public static class CommandServiceDelegates {
7 | internal delegate ValueTask HandleUntypedCommand(TAggregate aggregate, object command, CancellationToken cancellationToken)
8 | where TAggregate : Aggregate where TState : State, new();
9 |
10 | internal delegate ValueTask GetIdFromUntypedCommand(object command, CancellationToken cancellationToken) where TId : Id;
11 | }
12 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Application/Eventuous.Application.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
3 | True
4 | True
5 | True
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Application/Exceptions/ExceptionMessages.restext:
--------------------------------------------------------------------------------
1 | AggregateIdEmpty=Aggregate id {0} cannot have an empty value
2 | MissingCommandHandler=No handler found for command {0}
3 | DuplicateTypeKey=Type {0} has already been added to the map
4 | DuplicateCommandHandler=Command handler for {0} already registered
5 | MissingCommandMap=No map found between {0} and {1}
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Application/Exceptions/Exceptions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous;
5 |
6 | using static ExceptionMessages;
7 |
8 | public static class Exceptions {
9 | public class CommandHandlerNotFound(Type type) : Exception(MissingCommandHandler(type));
10 |
11 | public class CommandHandlerNotFound() : CommandHandlerNotFound(typeof(T));
12 |
13 | public class CommandHandlerAlreadyRegistered() : Exception(DuplicateCommandHandler());
14 |
15 | public class DuplicateTypeException() : ArgumentException(DuplicateTypeKey(), typeof(T).FullName);
16 |
17 | public class MessageMappingException() : Exception(MissingCommandMap());
18 | }
19 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Application/ExpectedState.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous;
5 |
6 | public enum ExpectedState {
7 | New,
8 | Existing,
9 | Any,
10 | Unknown
11 | }
12 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Application/ICommandService.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | // ReSharper disable UnusedTypeParameter
5 |
6 | namespace Eventuous;
7 |
8 | public interface ICommandService where TState : State, new() {
9 | Task> Handle(TCommand command, CancellationToken cancellationToken) where TCommand : class;
10 | }
11 |
12 | public interface ICommandService : ICommandService
13 | where T : Aggregate
14 | where TState : State, new()
15 | where TId : Id;
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Application/Persistence/ProposedAppend.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ.All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Runtime.InteropServices;
5 |
6 | namespace Eventuous.Persistence;
7 |
8 | [StructLayout(LayoutKind.Auto)]
9 | public record struct ProposedEvent(object Data, Metadata Metadata);
10 |
11 | [StructLayout(LayoutKind.Auto)]
12 | public record struct ProposedAppend(StreamName StreamName, ExpectedStreamVersion ExpectedVersion, ProposedEvent[] Events);
13 |
14 | public delegate ProposedAppend AmendAppend(ProposedAppend originalEvent, T context);
15 |
16 | delegate ProposedAppend AmendAppend(ProposedAppend originalEvent, object context);
17 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Application/Shared/IDefineAppendAmendment.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ.All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using Eventuous.Persistence;
5 |
6 | namespace Eventuous.Shared;
7 |
8 | public interface IDefineAppendAmendment where TCommand : class {
9 | ///
10 | /// Amends the proposed append before it gets stored.
11 | ///
12 | /// A function to amend the proposed append
13 | ///
14 | void AmendAppend(AmendAppend amendAppend);
15 | }
16 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Diagnostics/ActivityStatus.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Diagnostics;
5 |
6 | public record ActivityStatus(ActivityStatusCode StatusCode, string? Description, Exception? Exception) {
7 | public static ActivityStatus Ok(string? description = null)
8 | => new(ActivityStatusCode.Ok, description, null);
9 |
10 | public static ActivityStatus Error(Exception? exception = null, string? description = null)
11 | => new(ActivityStatusCode.Error, description ?? exception?.Message, exception);
12 | }
13 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Diagnostics/DiagnosticName.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Diagnostics;
5 |
6 | static class DiagnosticName {
7 | public const string BaseName = "eventuous";
8 | }
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Diagnostics/DummyActivityListener.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Diagnostics;
5 |
6 | public static class DummyActivityListener {
7 | public static ActivityListener Create()
8 | => new() {
9 | ShouldListenTo = x => x.Name.StartsWith(EventuousDiagnostics.InstrumentationName),
10 | Sample = (ref ActivityCreationOptions _) => ActivitySamplingResult.AllData
11 | };
12 | }
13 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Diagnostics/Eventuous.Diagnostics.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Diagnostics/Eventuous.Diagnostics.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Diagnostics/Metrics/GenericObserver.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Diagnostics.Metrics;
5 |
6 | class GenericObserver(Action? onNext, Action? onCompleted = null) : IObserver {
7 | public void OnCompleted() => _onCompleted();
8 |
9 | public void OnError(Exception error) { }
10 |
11 | public void OnNext(T value) => _onNext(value);
12 |
13 | readonly Action _onNext = onNext ?? (_ => { });
14 | readonly Action _onCompleted = onCompleted ?? (() => { });
15 | }
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Diagnostics/Metrics/Measure.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Diagnostics.Metrics;
5 |
6 | public sealed class Measure(DiagnosticSource diagnosticSource, object context) : IDisposable {
7 | public static Measure Start(DiagnosticSource source, object context) => new(source, context);
8 |
9 | public const string EventName = "Stopped";
10 |
11 | public void SetError() => _error = true;
12 |
13 | void Record() {
14 | var stoppedAt = DateTime.UtcNow;
15 | var duration = stoppedAt - _startedAt;
16 | diagnosticSource.Write(EventName, new MeasureContext(duration, _error, context));
17 | }
18 |
19 | readonly DateTime _startedAt = DateTime.UtcNow;
20 |
21 | bool _error;
22 |
23 | public void Dispose() => Record();
24 | }
25 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Diagnostics/Metrics/MetricsListener.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Diagnostics.Metrics;
5 |
6 | namespace Eventuous.Diagnostics.Metrics;
7 |
8 | public sealed class MetricsListener(string name, Histogram duration, Counter errors, Func getTags) : GenericListener(name), IDisposable {
9 | protected override void OnEvent(KeyValuePair data) {
10 | if (data.Key != Measure.EventName || data.Value is not MeasureContext { Context: T context } ctx) return;
11 |
12 | var tags = getTags(context);
13 |
14 | duration.Record(ctx.Duration.TotalMilliseconds, tags);
15 | if (ctx.Error) errors.Add(1, tags);
16 | }
17 | }
18 |
19 | record MeasureContext(TimeSpan Duration, bool Error, object Context);
20 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Diagnostics/Tags/IWithCustomTags.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Diagnostics;
5 |
6 | public interface IWithCustomTags {
7 | void SetCustomTags(TagList customTags);
8 | }
9 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Diagnostics/Tags/MetaTags.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Diagnostics;
5 |
6 | public static class DiagnosticTags {
7 | public const string TraceId = "$traceId";
8 | public const string SpanId = "$spanId";
9 | }
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Diagnostics/Tags/TracingMeta.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Diagnostics;
5 |
6 | public record TracingMeta(string? TraceId, string? SpanId) {
7 | bool IsValid() => TraceId != null && SpanId != null;
8 |
9 | public ActivityContext? ToActivityContext(bool isRemote) {
10 | try {
11 | return IsValid() ?
12 | new ActivityContext(
13 | ActivityTraceId.CreateFromString(TraceId),
14 | ActivitySpanId.CreateFromString(SpanId),
15 | ActivityTraceFlags.Recorded,
16 | isRemote: isRemote
17 | ) : default;
18 | }
19 | catch (Exception) {
20 | return default;
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Domain/Eventuous.Domain.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Eventuous
4 |
5 |
6 |
7 | Eventuous.ExceptionMessages.resources
8 |
9 |
10 |
11 |
12 | Tools\Ensure.cs
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Domain/Eventuous.Domain.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
3 | True
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Domain/Exceptions/DomainException.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous;
5 |
6 | public class DomainException(string message) : Exception(message);
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Domain/Exceptions/ExceptionMessages.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Reflection;
5 | using System.Resources;
6 |
7 | namespace Eventuous;
8 |
9 | static class ExceptionMessages {
10 | static readonly ResourceManager Resources = new("Eventuous.ExceptionMessages", Assembly.GetExecutingAssembly());
11 |
12 | internal static string AggregateIdEmpty(Type idType)
13 | => string.Format(Resources.GetString("AggregateIdEmpty")!, idType.Name);
14 |
15 | internal static string DuplicateTypeKey()
16 | => string.Format(Resources.GetString("DuplicateTypeKey")!, typeof(T).Name);
17 | }
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Domain/Exceptions/ExceptionMessages.restext:
--------------------------------------------------------------------------------
1 | AggregateIdEmpty=Aggregate id {0} cannot have an empty value
2 | DuplicateTypeKey=Type {0} has already been added to the map
3 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Domain/Exceptions/Exceptions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous;
5 |
6 | static class Exceptions {
7 | public class InvalidIdException(Type idType) : Exception(ExceptionMessages.AggregateIdEmpty(idType)) {
8 | public InvalidIdException(Id id)
9 | : this(id.GetType()) { }
10 | }
11 |
12 | public class InvalidIdException() : InvalidIdException(typeof(T)) where T : Id;
13 |
14 | internal class DuplicateTypeException() : ArgumentException(ExceptionMessages.DuplicateTypeKey(), typeof(T).FullName);
15 | }
16 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Domain/Id.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous;
5 |
6 | [Obsolete("Use Id instead")]
7 | public abstract record AggregateId : Id {
8 | protected AggregateId(string value) : base(value) { }
9 | }
10 |
11 | [PublicAPI]
12 | public abstract record Id {
13 | protected Id(string value) {
14 | if (string.IsNullOrWhiteSpace(value)) {
15 | throw new Exceptions.InvalidIdException(this);
16 | }
17 |
18 | Value = value;
19 | }
20 |
21 | public string Value { get; }
22 |
23 | public sealed override string ToString() => Value;
24 |
25 | public static implicit operator string(Id? id) => id?.ToString() ?? throw new Exceptions.InvalidIdException(typeof(Id));
26 |
27 | public void Deconstruct(out string value) => value = Value;
28 | }
29 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Persistence/AmendEvent.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ.All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous;
5 |
6 | ///
7 | /// Function to add additional information to the event before it's stored.
8 | ///
9 | public delegate NewStreamEvent AmendEvent(NewStreamEvent originalEvent);
10 |
11 | public delegate NewStreamEvent AmendEvent(NewStreamEvent originalEvent, T context);
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Persistence/AppendEventsResult.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous;
5 |
6 | public record AppendEventsResult(ulong GlobalPosition, long NextExpectedVersion) {
7 | public static readonly AppendEventsResult NoOp = new(0, -1);
8 | }
9 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Persistence/Eventuous.Persistence.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
3 | True
4 | True
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Persistence/StreamEvent.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Runtime.InteropServices;
5 |
6 | namespace Eventuous;
7 |
8 | [StructLayout(LayoutKind.Auto)]
9 | public record struct NewStreamEvent(Guid Id, object? Payload, Metadata Metadata);
10 |
11 | [StructLayout(LayoutKind.Auto)]
12 | public record struct StreamEvent(Guid Id, object? Payload, Metadata Metadata, string ContentType, long Position, bool FromArchive = false);
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Persistence/StreamNameFactory.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous;
5 |
6 | public static class StreamNameFactory {
7 | public static StreamName For(TId id) where TAggregate : Aggregate where TState : State, new() where TId : Id
8 | => new($"{typeof(TAggregate).Name}-{Ensure.NotEmptyString(id.Value)}");
9 |
10 | public static StreamName For(TId id) where TId : Id {
11 | var idTypeName = typeof(TId).Name;
12 |
13 | var idSpan = idTypeName.AsSpan();
14 |
15 | if (idSpan.EndsWith("Id")) {
16 | idSpan = idSpan[..^2];
17 | }
18 |
19 | return idSpan.Length > 0 ? new($"{idSpan}-{id.Value}") : new($"{idTypeName}-{id.Value}");
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Producers/AckProduce.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Producers;
5 |
6 | public delegate ValueTask AcknowledgeProduce(ProducedMessage message);
7 |
8 | public delegate ValueTask ReportFailedProduce(ProducedMessage message, string error, Exception? exception);
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Producers/Eventuous.Producers.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Diagnostics\DiagnosticName.cs
12 |
13 |
14 | Tools\TaskExtensions.cs
15 |
16 |
17 | Tools\Ensure.cs
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Serialization/Eventuous.Serialization.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Eventuous
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Serialization/IEventSerializer.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous;
5 |
6 | public interface IEventSerializer {
7 | DeserializationResult DeserializeEvent(ReadOnlySpan data, string eventType, string contentType);
8 |
9 | SerializationResult SerializeEvent(object evt);
10 | }
11 |
12 | public record SerializationResult(string EventType, string ContentType, byte[] Payload);
13 |
14 | public abstract record DeserializationResult {
15 | public record SuccessfullyDeserialized(object Payload) : DeserializationResult;
16 |
17 | public record FailedToDeserialize(DeserializationError Error) : DeserializationResult;
18 | }
19 |
20 | public enum DeserializationError {
21 | UnknownType,
22 | ContentTypeMismatch,
23 | PayloadEmpty
24 | }
25 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Serialization/IMetadataSerializer.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous;
5 |
6 | public interface IMetadataSerializer {
7 | byte[] Serialize(Metadata evt);
8 |
9 | ///
10 | /// Deserializes the metadata
11 | ///
12 | /// Serialized metadata as bytes
13 | /// Deserialized metadata object
14 | /// MetadataDeserializationException if the metadata cannot be deserialized
15 | Metadata? Deserialize(ReadOnlySpan bytes);
16 | }
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Serialization/MetadataDeserializationException.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous;
5 |
6 | public class MetadataDeserializationException(Exception inner) : Exception("Failed to deserialize metadata", inner);
7 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Shared/Eventuous.Shared.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
3 | True
4 | True
5 | True
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Shared/Exceptions/ExceptionMessages.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Reflection;
5 | using System.Resources;
6 |
7 | namespace Eventuous;
8 |
9 | static class ExceptionMessages {
10 | static readonly ResourceManager Resources = new("Eventuous.ExceptionMessages", Assembly.GetExecutingAssembly());
11 |
12 | internal static string DuplicateTypeKey() => string.Format(Resources.GetString("DuplicateTypeKey")!, typeof(T).Name);
13 | }
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Shared/Exceptions/ExceptionMessages.restext:
--------------------------------------------------------------------------------
1 | DuplicateTypeKey=Type {0} has already been added to the map
2 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Shared/Exceptions/Exceptions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous;
5 |
6 | static class Exceptions {
7 | internal class DuplicateTypeException() : ArgumentException(ExceptionMessages.DuplicateTypeKey(), typeof(T).FullName);
8 | }
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Shared/Meta/MetaTags.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous;
5 |
6 | public static class MetaTags {
7 | const string Prefix = "eventuous";
8 |
9 | public const string MessageId = $"{Prefix}.message-id";
10 | public const string CorrelationId = $"{Prefix}.correlation-id";
11 | public const string CausationId = $"{Prefix}.causation-id";
12 | }
13 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Shared/Tools/TypeExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Extensions.AspNetCore;
5 |
6 | static class TypeExtensions {
7 | public static T? GetAttribute(this Type type) where T : class => Attribute.GetCustomAttribute(type, typeof(T)) as T;
8 | }
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Channels/ChannelFullException.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Subscriptions.Channels;
5 |
6 | public class ChannelFullException() : Exception("Channel worker unable to write to the channel because it's full");
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Checkpoints/Checkpoint.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ.All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Runtime.InteropServices;
5 |
6 | namespace Eventuous.Subscriptions.Checkpoints;
7 |
8 | [PublicAPI]
9 | [StructLayout(LayoutKind.Auto)]
10 | public record struct Checkpoint(string Id, ulong? Position) {
11 | public static Checkpoint Empty(string id) => new(id, null);
12 |
13 | public readonly bool IsEmpty => Position == null;
14 | }
15 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Checkpoints/ICheckpointStore.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Subscriptions.Checkpoints;
5 |
6 | [PublicAPI]
7 | public interface ICheckpointStore {
8 | ValueTask GetLastCheckpoint(string checkpointId, CancellationToken cancellationToken);
9 |
10 | ValueTask StoreCheckpoint(Checkpoint checkpoint, bool force, CancellationToken cancellationToken);
11 | }
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Consumers/IMessageConsumer.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Subscriptions.Consumers;
5 |
6 | using Context;
7 |
8 | public interface IMessageConsumer where TContext : class, IMessageConsumeContext {
9 | ValueTask Consume(TContext context);
10 | }
11 |
12 | public interface IMessageConsumer : IMessageConsumer;
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Context/ContextExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Subscriptions.Context;
5 |
6 | public static class ContextExtensions {
7 | public static T? GetContext(this IMessageConsumeContext ctx) where T : class, IMessageConsumeContext {
8 | while (true) {
9 | if (typeof(T) == ctx.GetType()) return (T)ctx;
10 |
11 | if (ctx is WrappedConsumeContext wrapped) {
12 | ctx = wrapped.InnerContext;
13 | continue;
14 | }
15 |
16 | return null;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Context/ContextItemKeys.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Subscriptions.Context;
5 |
6 | public static class ContextItemKeys {
7 | public const string Activity = "activity";
8 | }
9 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Diagnostics/HealthReport.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Subscriptions.Diagnostics;
5 |
6 | readonly record struct HealthReport {
7 | HealthReport(bool isHealthy, Exception? lastException) {
8 | IsHealthy = isHealthy;
9 | LastException = lastException;
10 | }
11 |
12 | public static HealthReport Healthy() => new(true, null);
13 |
14 | public static HealthReport Unhealthy(Exception? exception) => new(false, exception);
15 |
16 | public bool IsHealthy { get; }
17 | public Exception? LastException { get; }
18 | }
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Diagnostics/SubscriptionGapMeasure.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Runtime.InteropServices;
5 |
6 | namespace Eventuous.Subscriptions.Diagnostics;
7 |
8 | public delegate ValueTask GetSubscriptionEndOfStream(CancellationToken cancellationToken);
9 |
10 | [PublicAPI]
11 | [StructLayout(LayoutKind.Auto)]
12 | public readonly record struct EndOfStream(string SubscriptionId, ulong Position, DateTime Timestamp) {
13 | public static readonly EndOfStream Invalid = new("error", 0, DateTime.MinValue);
14 | }
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/DropReason.cs:
--------------------------------------------------------------------------------
1 | namespace Eventuous.Subscriptions;
2 |
3 | public enum DropReason {
4 | Stopped,
5 | ServerError,
6 | SubscriptionError
7 | }
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Eventuous.Subscriptions.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
3 | True
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Filters/ConsumePipeExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Subscriptions.Filters;
5 |
6 | using Consumers;
7 |
8 | public static class ConsumePipeExtensions {
9 | public static ConsumePipe AddDefaultConsumer(this ConsumePipe consumePipe, params IEventHandler[] handlers)
10 | => consumePipe.AddFilterLast(new ConsumerFilter(new DefaultConsumer(handlers)));
11 | }
12 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Filters/ConsumerFilter.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Subscriptions.Filters;
5 |
6 | using Consumers;
7 | using Context;
8 |
9 | public class ConsumerFilter(IMessageConsumer consumer) : ConsumeFilter {
10 | protected override ValueTask Send(IMessageConsumeContext context, LinkedListNode? next) => consumer.Consume(context);
11 | }
12 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Filters/MessageFilter.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Subscriptions.Filters;
5 |
6 | using Context;
7 |
8 | public delegate bool FilterMessage(IMessageConsumeContext receivedEvent);
9 |
10 | public class MessageFilter(FilterMessage filter) : ConsumeFilter {
11 | readonly FilterMessage _filter = Ensure.NotNull(filter);
12 |
13 | protected override ValueTask Send(IMessageConsumeContext context, LinkedListNode? next) {
14 | if (next?.Value == null) return default;
15 |
16 | if (_filter(context)) return next.Value.Send(context, next.Next);
17 |
18 | context.Ignore();
19 | return default;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Filters/Partitioning/Partitioner.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Subscriptions.Filters.Partitioning;
5 |
6 | using Context;
7 |
8 | public static class Partitioner {
9 | ///
10 | /// Partition key hash calculator function
11 | ///
12 | public delegate uint GetPartitionHash(string partitionKey);
13 |
14 | ///
15 | /// Function to get a partition key from a message context
16 | ///
17 | public delegate string GetPartitionKey(IMessageConsumeContext context);
18 | }
19 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Handlers/BaseEventHandler.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Subscriptions;
5 |
6 | using Context;
7 |
8 | public abstract class BaseEventHandler : IEventHandler {
9 | protected BaseEventHandler() => DiagnosticName = GetType().Name;
10 |
11 | public string DiagnosticName { get; }
12 |
13 | public abstract ValueTask HandleEvent(IMessageConsumeContext context);
14 | }
15 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Handlers/EventHandlingStatus.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Subscriptions;
5 |
6 | [Flags]
7 | public enum EventHandlingStatus : short {
8 | Ignored = 0b_1000,
9 | Success = 0b_0001,
10 | Pending = 0b_0010,
11 | Failure = 0b_0011,
12 | Handled = 0b_0111
13 | // 0111 bitmask for Handled means that if any of the three lower bits is set, the message
14 | // hs been handled.
15 | }
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Handlers/IEventHandler.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Subscriptions;
5 |
6 | using Context;
7 |
8 | ///
9 | /// Subscription event handlers must implement this interface
10 | ///
11 | public interface IEventHandler {
12 | ///
13 | /// Event handler name that is used for diagnostics (logging, tracing, etc)
14 | ///
15 | string DiagnosticName { get; }
16 |
17 | ///
18 | /// Function that handles an event received from the subscription
19 | ///
20 | /// Message context with message payload and details
21 | ///
22 | ValueTask HandleEvent(IMessageConsumeContext context);
23 | }
24 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/IMessageSubscription.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Subscriptions;
5 |
6 | using Diagnostics;
7 |
8 | public delegate void OnSubscribed(string subscriptionId);
9 |
10 | public delegate void OnDropped(string subscriptionId, DropReason dropReason, Exception? exception);
11 |
12 | public delegate void OnUnsubscribed(string subscriptionId);
13 |
14 | public interface IMessageSubscription {
15 | string SubscriptionId { get; }
16 |
17 | ValueTask Subscribe(OnSubscribed onSubscribed, OnDropped onDropped, CancellationToken cancellationToken);
18 |
19 | ValueTask Unsubscribe(OnUnsubscribed onUnsubscribed, CancellationToken cancellationToken);
20 | }
21 |
22 | public interface IMeasuredSubscription {
23 | GetSubscriptionEndOfStream GetMeasure();
24 | }
25 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Logging/InternalLogger.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using Microsoft.Extensions.Logging;
5 |
6 | // ReSharper disable TemplateIsNotCompileTimeConstantProblem
7 |
8 | namespace Eventuous.Subscriptions.Logging;
9 |
10 | public class InternalLogger(ILogger logger, LogLevel logLevel, string subscriptionId) {
11 | #pragma warning disable CA2254
12 | public void Log(string message, params object[] args) => logger.Log(logLevel, GetMessage(message), args);
13 |
14 | public void Log(Exception? exception, string message, params object[] args) => logger.Log(logLevel, exception, GetMessage(message), args);
15 | #pragma warning restore CA2254
16 |
17 | string GetMessage(string message) => $"[{subscriptionId}] {message}";
18 | }
19 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/Properties/InternalVisibleTo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | [assembly: InternalsVisibleTo("Eventuous.Tests.Subscriptions")]
4 | [assembly: InternalsVisibleTo("Eventuous.TestHelpers")]
5 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous.Subscriptions/SubscriptionOptions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Subscriptions;
5 |
6 | [PublicAPI]
7 | public abstract record SubscriptionOptions {
8 | ///
9 | /// Subscription id is used to match event handlers with one subscription
10 | ///
11 | public string SubscriptionId { get; set; } = null!;
12 |
13 | ///
14 | /// Set to true if you want the subscription to fail and stop if anything goes wrong.
15 | ///
16 | public bool ThrowOnError { get; set; }
17 | }
18 |
19 | public abstract record SubscriptionWithCheckpointOptions : SubscriptionOptions {
20 | public int CheckpointCommitBatchSize { get; set; } = 100;
21 | public int CheckpointCommitDelayMs { get; set; } = 5000;
22 | }
23 |
--------------------------------------------------------------------------------
/src/Core/src/Eventuous/Eventuous.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | README.md
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/Core/test/Eventuous.Tests.Application/Helpers.cs:
--------------------------------------------------------------------------------
1 | using Eventuous.Sut.App;
2 | using NodaTime;
3 |
4 | namespace Eventuous.Tests.Application;
5 |
6 | public static class Helpers {
7 | public static Commands.BookRoom GetBookRoom(string bookingId = "123") {
8 | var checkIn = LocalDate.FromDateTime(DateTime.Today);
9 | var checkOut = checkIn.PlusDays(1);
10 |
11 | return new(bookingId, "234", checkIn, checkOut, 100);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Core/test/Eventuous.Tests.Persistence.Base/Fixtures/DomainFixture.cs:
--------------------------------------------------------------------------------
1 | using Bogus;
2 | using Eventuous.Sut.App;
3 |
4 | namespace Eventuous.Tests.Persistence.Base.Fixtures;
5 |
6 | public static class DomainFixture {
7 | static DomainFixture() => TypeMap.RegisterKnownEventTypes(typeof(DomainFixture).Assembly);
8 |
9 | static Faker Faker => new Faker()
10 | .RuleFor(x => x.BookingId, _ => Guid.NewGuid().ToString("N"))
11 | .RuleFor(x => x.RoomId, _ => Guid.NewGuid().ToString("N"))
12 | .RuleFor(x => x.Price, f => f.Random.Number(50, 200))
13 | .RuleFor(x => x.CheckIn, f => f.Noda().LocalDate.Soon())
14 | .RuleFor(x => x.CheckOut, (f, c) => c.CheckIn.PlusDays(f.Random.Number(1, 5)));
15 |
16 | public static Commands.ImportBooking CreateImportBooking() => Faker.Generate();
17 | }
18 |
--------------------------------------------------------------------------------
/src/Core/test/Eventuous.Tests.Subscriptions.Base/Eventuous.Tests.Subscriptions.Base.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
--------------------------------------------------------------------------------
/src/Core/test/Eventuous.Tests.Subscriptions.Base/Fixtures/TracedHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using Eventuous.Subscriptions;
3 | using Eventuous.Subscriptions.Context;
4 | using Eventuous.TestHelpers;
5 |
6 | namespace Eventuous.Tests.Subscriptions.Base;
7 |
8 | public class TracedHandler : BaseEventHandler {
9 | public List Contexts { get; } = [];
10 |
11 | static readonly ValueTask Success = new(EventHandlingStatus.Success);
12 |
13 | public override ValueTask HandleEvent(IMessageConsumeContext context) {
14 | Contexts.Add(new(Activity.Current?.TraceId, Activity.Current?.SpanId, Activity.Current?.ParentSpanId));
15 |
16 | return Success;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Core/test/Eventuous.Tests.Subscriptions.Base/SubscriptionTestBase.cs:
--------------------------------------------------------------------------------
1 | using Eventuous.Tests.Persistence.Base.Fixtures;
2 |
3 | namespace Eventuous.Tests.Subscriptions.Base;
4 |
5 | public abstract class SubscriptionTestBase(IStartableFixture fixture) {
6 | [Before(Test)]
7 | public async Task Startup() {
8 | await fixture.InitializeAsync();
9 | }
10 |
11 | [After(Test)]
12 | public async Task Shutdown() {
13 | await fixture.DisposeAsync();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Core/test/Eventuous.Tests.Subscriptions/Eventuous.Tests.Subscriptions.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 | true
5 | Exe
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/Core/test/Eventuous.Tests/AggregateWithId/OperateOnAggregateWithId.cs:
--------------------------------------------------------------------------------
1 | using Eventuous.Testing;
2 |
3 | namespace Eventuous.Tests.AggregateWithId;
4 |
5 | public class OperateOnAggregateWithId : AggregateWithIdSpec {
6 | protected override void When(TestAggregate aggregate) => aggregate.Process();
7 |
8 | const string IdValue = "test";
9 |
10 | protected override TestId? Id { get; } = new(IdValue);
11 |
12 | [Test]
13 | public void should_emit_event() => Emitted(new TestEvent());
14 |
15 | [Test]
16 | public void should_set_id() => Then().State.Id.Value.Should().Be(IdValue);
17 | }
18 |
19 | public class TestAggregate : Aggregate {
20 | public void Process() => Apply(new TestEvent());
21 | }
22 |
23 | public record TestState : State;
24 |
25 | public record TestId(string Value) : Id(Value);
26 |
27 | record TestEvent;
28 |
--------------------------------------------------------------------------------
/src/Core/test/Eventuous.Tests/Fixtures/IdGenerator.cs:
--------------------------------------------------------------------------------
1 | namespace Eventuous.Tests.Fixtures;
2 |
3 | public class IdGenerator {
4 | public static string GetId() => Guid.NewGuid().ToString("N");
5 | }
6 |
--------------------------------------------------------------------------------
/src/Core/test/Eventuous.Tests/Fixtures/NaiveFixture.cs:
--------------------------------------------------------------------------------
1 | using Bogus;
2 |
3 | namespace Eventuous.Tests.Fixtures;
4 |
5 | using Sut.App;
6 | using Testing;
7 |
8 | public class NaiveFixture {
9 | protected IEventStore EventStore { get; } = new InMemoryEventStore();
10 |
11 | static readonly Faker Faker = new Faker()
12 | .CustomInstantiator(
13 | f => {
14 | var checkin = f.Noda().LocalDate.Soon();
15 | var checkout = checkin.PlusDays(f.Random.Number(1, 5));
16 |
17 | return new(f.Random.Guid().ToString("N"), f.Random.Guid().ToString("N"), checkin, checkout, f.Random.Number(50, 200));
18 | }
19 | );
20 |
21 | protected static Commands.BookRoom CreateBookRoomCommand() => Faker.Generate();
22 | }
23 |
--------------------------------------------------------------------------------
/src/Core/test/Eventuous.Tests/StreamNameMapTests.cs:
--------------------------------------------------------------------------------
1 | using Eventuous.Sut.Domain;
2 |
3 | namespace Eventuous.Tests;
4 |
5 | using static Fixtures.IdGenerator;
6 |
7 | public class StreamNameMapTests {
8 | readonly StreamNameMap _sut = new();
9 |
10 | [Test]
11 | public async Task Should_get_stream_name_for_id() {
12 | var idString = GetId();
13 | var id = new BookingId(idString);
14 | var streamName = StreamNameFactory.For(id);
15 | await Assert.That(streamName.ToString()).IsEqualTo($"Booking-{idString}");
16 | }
17 |
18 | [Test]
19 | public async Task Should_get_default_stream_name_for_id() {
20 | var idString = GetId();
21 | var id = new BookingId(idString);
22 | var streamName = _sut.GetStreamName(id);
23 | await Assert.That(streamName.ToString()).IsEqualTo($"Booking-{idString}");
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Core/test/Eventuous.Tests/TypeRegistrationTests.cs:
--------------------------------------------------------------------------------
1 | using static Eventuous.Sut.Domain.BookingEvents;
2 |
3 | namespace Eventuous.Tests;
4 |
5 | public class TypeRegistrationTests {
6 | readonly TypeMapper _typeMapper = new();
7 |
8 | public TypeRegistrationTests() => _typeMapper.RegisterKnownEventTypes(typeof(BookingCancelled).Assembly);
9 |
10 | [Test]
11 | public async Task ShouldResolveDecoratedEvent() {
12 | await Assert.That(_typeMapper.GetTypeName()).IsEqualTo(TypeNames.BookingCancelled);
13 | await Assert.That(_typeMapper.GetType(TypeNames.BookingCancelled)).IsEqualTo(typeof(BookingCancelled));
14 | }
15 | }
--------------------------------------------------------------------------------
/src/Diagnostics/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.7'
2 |
3 | services:
4 | zipkin:
5 | image: openzipkin/zipkin
6 | container_name: eventuous-zipkin
7 | ports:
8 | - "9411:9411"
9 |
--------------------------------------------------------------------------------
/src/Diagnostics/src/Eventuous.Diagnostics.Logging/Eventuous.Diagnostics.Logging.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | DiagnosticName.cs
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/Diagnostics/src/Eventuous.Diagnostics.Logging/README.md:
--------------------------------------------------------------------------------
1 | # Eventuous.Diagnostics.Logging
2 |
3 | Eventuous has internal event sources that emit log messages.
4 | It's possible to expose those messages into the logs by using the logging event listener from this package.
5 |
6 | ## Usage
7 |
8 | Normally, you'd not need to use the logging listener directly.
9 | The `Eventuous.Extensions.DependencyInjection` package contains extensions for `IApplicationBuilder` and `IHost` to connect Eventuous diagnostic events to the logging system of .NET.
--------------------------------------------------------------------------------
/src/Diagnostics/src/Eventuous.Diagnostics.OpenTelemetry/Eventuous.Diagnostics.OpenTelemetry.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Tools\Ensure.cs
12 |
13 |
14 | DiagnosticName.cs
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/Diagnostics/src/Eventuous.Diagnostics/DiagnosticName.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021-2022 Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Diagnostics;
5 |
6 | public static class DiagnosticName {
7 | public const string BaseName = "eventuous";
8 | }
9 |
--------------------------------------------------------------------------------
/src/Diagnostics/src/Eventuous.Diagnostics/Eventuous.Diagnostics.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/Diagnostics/src/Eventuous.Diagnostics/Properties/InternalVisibleTo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | [assembly: InternalsVisibleTo("Eventuous")]
4 |
--------------------------------------------------------------------------------
/src/Diagnostics/test/Eventuous.Tests.OpenTelemetry/Fakes/MessageCounter.cs:
--------------------------------------------------------------------------------
1 | namespace Eventuous.Tests.OpenTelemetry.Fakes;
2 |
3 | public class MessageCounter {
4 | public int Count;
5 | public void Increment() => Interlocked.Increment(ref Count);
6 | }
7 |
--------------------------------------------------------------------------------
/src/Diagnostics/test/Eventuous.Tests.OpenTelemetry/Fakes/MetricValue.cs:
--------------------------------------------------------------------------------
1 | namespace Eventuous.Tests.OpenTelemetry.Fakes;
2 |
3 | public record MetricValue(string Name, string[] Keys, object[] Values, double Value);
4 |
--------------------------------------------------------------------------------
/src/Diagnostics/test/Eventuous.Tests.OpenTelemetry/Fakes/TestHandler.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 |
3 | namespace Eventuous.Tests.OpenTelemetry.Fakes;
4 |
5 | class TestHandler(MessageCounter counter, ILogger log) : BaseEventHandler {
6 | public override async ValueTask HandleEvent(IMessageConsumeContext context) {
7 | await Task.Delay(10, context.CancellationToken);
8 | counter.Increment();
9 | log.LogDebug("Processed {@Message}", context.Message);
10 |
11 | return EventHandlingStatus.Success;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/Directory.Testable.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | false
6 | CA1816
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/Directory.Untestable.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/EventStore/Eventuous.EventStore.slnf:
--------------------------------------------------------------------------------
1 | {
2 | "solution": {
3 | "path": "..\\..\\Eventuous.sln",
4 | "projects": [
5 | "src\\Core\\src\\Eventuous\\Eventuous.csproj",
6 | "src\\Core\\src\\Eventuous.Subscriptions\\Eventuous.Subscriptions.csproj",
7 | "src\\Core\\src\\Eventuous.Producers\\Eventuous.Producers.csproj",
8 | "src\\EventStore\\src\\Eventuous.EventStore\\Eventuous.EventStore.csproj",
9 | "src\\EventStore\\test\\Eventuous.Tests.EventStore\\Eventuous.Tests.EventStore.csproj",
10 | "test\\Eventuous.Tests.SutDomain\\Eventuous.Tests.SutDomain.csproj",
11 | "test\\Eventuous.Tests.SutApp\\Eventuous.Tests.SutApp.csproj"
12 | ]
13 | }
14 | }
--------------------------------------------------------------------------------
/src/EventStore/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.7'
2 |
3 | services:
4 | esdb:
5 | container_name: eventuous-esdb
6 | image: ghcr.io/eventstore/eventstore:22.10.2-alpha-arm64v8
7 | ports:
8 | - '2113:2113'
9 | - '1113:1113'
10 | environment:
11 | EVENTSTORE_INSECURE: 'true'
12 | EVENTSTORE_CLUSTER_SIZE: 1
13 | EVENTSTORE_EXT_TCP_PORT: 1113
14 | EVENTSTORE_HTTP_PORT: 2113
15 | EVENTSTORE_ENABLE_EXTERNAL_TCP: 'true'
16 | EVENTSTORE_RUN_PROJECTIONS: all
17 | EVENTSTORE_START_STANDARD_PROJECTIONS: "true"
18 | EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP: "true"
19 |
--------------------------------------------------------------------------------
/src/EventStore/src/Eventuous.EventStore/Eventuous.EventStore.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
--------------------------------------------------------------------------------
/src/EventStore/src/Eventuous.EventStore/README.md:
--------------------------------------------------------------------------------
1 | # Eventuous EventStoreDB support
2 |
3 | This package adds support for [EventStoreDB](https://eventstore.com) to applications built with Eventuous.
4 | It includes the following components:
5 |
6 | - `EsdbEventStore` - implementation of the `IEventStore` interface
7 | - Different types of subscriptions (catch-up and persistent)
8 | - Message producer
--------------------------------------------------------------------------------
/src/EventStore/src/Eventuous.EventStore/Subscriptions/ConsumePipeExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using Eventuous.Subscriptions.Filters;
5 |
6 | namespace Eventuous.EventStore.Subscriptions;
7 |
8 | ///
9 | /// Extensions for
10 | ///
11 | public static class ConsumePipeExtensions {
12 | ///
13 | /// Adds a filter to ignore EventStoreDB system events
14 | ///
15 | ///
16 | ///
17 | public static ConsumePipe AddSystemEventsFilter(this ConsumePipe pipe) => pipe.AddFilterLast(new MessageFilter(x => !x.MessageType.StartsWith("$")));
18 | }
19 |
--------------------------------------------------------------------------------
/src/EventStore/src/Eventuous.EventStore/Subscriptions/Diagnostics/AllStreamSubscriptionMeasure.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.EventStore.Subscriptions.Diagnostics;
5 |
6 | class AllStreamSubscriptionMeasure(string subscriptionId, EventStoreClient eventStoreClient)
7 | : BaseSubscriptionMeasure(subscriptionId, "$all", eventStoreClient) {
8 | protected override IAsyncEnumerable Read(CancellationToken cancellationToken)
9 | => EventStoreClient.ReadAllAsync(Direction.Backwards, Position.End, 1, cancellationToken: cancellationToken);
10 |
11 | protected override ulong GetLastPosition(ResolvedEvent resolvedEvent) => resolvedEvent.Event.Position.CommitPosition;
12 | }
13 |
--------------------------------------------------------------------------------
/src/EventStore/src/Eventuous.EventStore/Subscriptions/Diagnostics/StreamSubscriptionMeasure.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.EventStore.Subscriptions.Diagnostics;
5 |
6 | class StreamSubscriptionMeasure(string subscriptionId, StreamName streamName, EventStoreClient eventStoreClient)
7 | : BaseSubscriptionMeasure(subscriptionId, streamName, eventStoreClient) {
8 | protected override IAsyncEnumerable Read(CancellationToken cancellationToken)
9 | => EventStoreClient.ReadStreamAsync(Direction.Backwards, streamName, StreamPosition.End, 1, cancellationToken: cancellationToken);
10 |
11 | protected override ulong GetLastPosition(ResolvedEvent resolvedEvent) => resolvedEvent.Event.EventNumber;
12 | }
13 |
--------------------------------------------------------------------------------
/src/EventStore/src/Eventuous.EventStore/Subscriptions/EsdbMappings.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.EventStore.Subscriptions;
5 |
6 | static class EsdbMappings {
7 | public static DropReason AsDropReason(SubscriptionDroppedReason reason)
8 | => reason switch {
9 | SubscriptionDroppedReason.Disposed => DropReason.Stopped,
10 | SubscriptionDroppedReason.ServerError => DropReason.ServerError,
11 | SubscriptionDroppedReason.SubscriberError => DropReason.SubscriptionError,
12 | _ => throw new ArgumentOutOfRangeException(nameof(reason), reason, null)
13 | };
14 |
15 | }
--------------------------------------------------------------------------------
/src/EventStore/src/Eventuous.EventStore/Subscriptions/Options/AllPersistentSubscriptionOptions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.EventStore.Subscriptions;
5 |
6 | ///
7 | /// Options for
8 | ///
9 | public record AllPersistentSubscriptionOptions : PersistentSubscriptionOptions {
10 | ///
11 | /// Server-side event filter.
12 | /// Warning: the filter is set when the subscription is created.
13 | /// Eventuous doesn't update the filter after that even if it changes in code.
14 | ///
15 | public IEventFilter? EventFilter { get; set; }
16 | }
--------------------------------------------------------------------------------
/src/EventStore/src/Eventuous.EventStore/Subscriptions/Options/AllStreamSubscriptionOptions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.EventStore.Subscriptions;
5 |
6 | ///
7 | /// Options for
8 | ///
9 | [PublicAPI]
10 | public record AllStreamSubscriptionOptions : CatchUpSubscriptionOptions {
11 | ///
12 | /// Server-side event filter
13 | ///
14 | public IEventFilter? EventFilter { get; set; }
15 |
16 | ///
17 | /// When using the server-side , the clients still wants to persist the checkpoint
18 | /// from time to time, to avoid re-reading lots of filtered out events after the restart. Default is 10.
19 | ///
20 | public uint CheckpointInterval { get; set; } = 10;
21 | }
--------------------------------------------------------------------------------
/src/EventStore/src/Eventuous.EventStore/Subscriptions/Options/CatchUpSubscriptionOptions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using Eventuous.Subscriptions.Filters;
5 |
6 | namespace Eventuous.EventStore.Subscriptions;
7 |
8 | ///
9 | /// Base class for catch-up subscription options
10 | ///
11 | public record CatchUpSubscriptionOptions : EventStoreSubscriptionWithCheckpointOptions {
12 | ///
13 | /// Number of parallel consumers. Defaults to 1.
14 | /// Don't set this value if you use partitioned subscriptions with .
15 | ///
16 | public int ConcurrencyLimit { get; set; } = 1;
17 | }
18 |
--------------------------------------------------------------------------------
/src/EventStore/src/Eventuous.EventStore/Subscriptions/Options/EventStoreSubscriptionOptions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.EventStore.Subscriptions;
5 |
6 | ///
7 | /// Base class for EventStoreDB subscription options
8 | ///
9 | public abstract record EventStoreSubscriptionOptions : SubscriptionOptions {
10 | ///
11 | /// User credentials
12 | ///
13 | public UserCredentials? Credentials { get; [PublicAPI] set; }
14 |
15 | ///
16 | /// Resolve link events
17 | ///
18 | public bool ResolveLinkTos { get; [PublicAPI] set; }
19 | }
20 |
--------------------------------------------------------------------------------
/src/EventStore/src/Eventuous.EventStore/Subscriptions/Options/EventStoreSubscriptionWithCheckpointOptions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ.All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.EventStore.Subscriptions;
5 |
6 | ///
7 | /// Options base record for EventStoreDB checkpoint-based subscriptions
8 | ///
9 | public abstract record EventStoreSubscriptionWithCheckpointOptions : SubscriptionWithCheckpointOptions {
10 | ///
11 | /// User credentials
12 | ///
13 | public UserCredentials? Credentials { get; [PublicAPI] set; }
14 |
15 | ///
16 | /// Resolve link events
17 | ///
18 | public bool ResolveLinkTos { get; set; }
19 | }
20 |
--------------------------------------------------------------------------------
/src/EventStore/src/Eventuous.EventStore/Subscriptions/Options/StreamPersistentSubscriptionOptions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.EventStore.Subscriptions;
5 |
6 | ///
7 | /// Options for
8 | ///
9 | [PublicAPI]
10 | public record StreamPersistentSubscriptionOptions : PersistentSubscriptionOptions {
11 | ///
12 | /// Stream name to subscribe for
13 | ///
14 | public StreamName StreamName { get; set; }
15 | }
--------------------------------------------------------------------------------
/src/EventStore/src/Eventuous.EventStore/Subscriptions/Options/StreamSubscriptionOptions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.EventStore.Subscriptions;
5 |
6 | ///
7 | /// Options for
8 | ///
9 | public record StreamSubscriptionOptions : CatchUpSubscriptionOptions {
10 | ///
11 | /// WHen set to true, all events of type that starts with '$' will be ignored. Default is true.
12 | ///
13 | public bool IgnoreSystemEvents { get; set; } = true;
14 |
15 | ///
16 | /// Stream name to subscribe for
17 | ///
18 | public StreamName StreamName { get; set; }
19 | }
--------------------------------------------------------------------------------
/src/EventStore/test/Eventuous.Tests.EventStore/Fixtures/DomainFixture.cs:
--------------------------------------------------------------------------------
1 | using Bogus;
2 | using Eventuous.Sut.App;
3 | using Eventuous.Sut.Domain;
4 |
5 | namespace Eventuous.Tests.EventStore.Fixtures;
6 |
7 | public static class DomainFixture {
8 | static DomainFixture() => TypeMap.RegisterKnownEventTypes(typeof(BookingEvents.BookingImported).Assembly);
9 |
10 | static Faker Faker => new Faker()
11 | .RuleFor(x => x.BookingId, _ => Guid.NewGuid().ToString("N"))
12 | .RuleFor(x => x.RoomId, _ => Guid.NewGuid().ToString("N"))
13 | .RuleFor(x => x.Price, f => f.Random.Number(50, 200))
14 | .RuleFor(x => x.CheckIn, f => f.Noda().LocalDate.Soon())
15 | .RuleFor(x => x.CheckOut, (f, c) => c.CheckIn.PlusDays(f.Random.Number(1, 5)));
16 |
17 | public static Commands.ImportBooking CreateImportBooking() => Faker.Generate();
18 | }
19 |
--------------------------------------------------------------------------------
/src/EventStore/test/Eventuous.Tests.EventStore/Fixtures/EsdbContainer.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 | using Testcontainers.EventStoreDb;
3 |
4 | namespace Eventuous.Tests.EventStore.Fixtures;
5 |
6 | public static class EsdbContainer {
7 | public static EventStoreDbContainer Create() {
8 | var image = RuntimeInformation.ProcessArchitecture == Architecture.Arm64
9 | ? "eventstore/eventstore:24.6.0-alpha-arm64v8"
10 | : "eventstore/eventstore:24.6";
11 |
12 | return new EventStoreDbBuilder()
13 | .WithImage(image)
14 | .WithEnvironment("EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP", "true")
15 | .Build();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/EventStore/test/Eventuous.Tests.EventStore/Limiter.cs:
--------------------------------------------------------------------------------
1 | using Eventuous.Tests.EventStore;
2 | using TUnit.Core.Interfaces;
3 |
4 | [assembly: ParallelLimiter]
5 |
6 | namespace Eventuous.Tests.EventStore;
7 |
8 | public class Limiter : IParallelLimit {
9 | public int Limit => 4;
10 | }
11 |
--------------------------------------------------------------------------------
/src/EventStore/test/Eventuous.Tests.EventStore/Metrics/MetricsTests.cs:
--------------------------------------------------------------------------------
1 | using Eventuous.Tests.OpenTelemetry;
2 |
3 | namespace Eventuous.Tests.EventStore.Metrics;
4 |
5 | [ClassDataSource]
6 | [NotInParallel]
7 | public class MetricsTests(MetricsFixture fixture) : MetricsTestsBase(fixture) {
8 | [Test]
9 | [Retry(3)]
10 | public async Task ShouldMeasureSubscriptionGapCountBase_Esdb() {
11 | await ShouldMeasureSubscriptionGapCountBase();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/EventStore/test/Eventuous.Tests.EventStore/Store/StoreTests.cs:
--------------------------------------------------------------------------------
1 | using Eventuous.Tests.Persistence.Base.Store;
2 |
3 | // ReSharper disable UnusedType.Global
4 |
5 | namespace Eventuous.Tests.EventStore.Store;
6 |
7 | [InheritsTests]
8 | [ClassDataSource]
9 | public class Append(StoreFixture fixture) : StoreAppendTests(fixture);
10 |
11 | [InheritsTests]
12 | [ClassDataSource]
13 | public class Read(StoreFixture fixture) : StoreReadTests(fixture);
14 |
15 | [InheritsTests]
16 | [ClassDataSource]
17 | public class OtherMethods(StoreFixture fixture) : StoreOtherOpsTests(fixture);
18 |
--------------------------------------------------------------------------------
/src/EventStore/test/Eventuous.Tests.EventStore/Store/TieredStoreTests.cs:
--------------------------------------------------------------------------------
1 | using Eventuous.Tests.Persistence.Base.Store;
2 | using Testcontainers.EventStoreDb;
3 |
4 | namespace Eventuous.Tests.EventStore.Store;
5 |
6 | [ClassDataSource]
7 | public class TieredStoreTests(StoreFixture storeFixture) : TieredStoreTestsBase(storeFixture) {
8 | [Test]
9 | public async Task Esdb_should_load_hot_and_archive() {
10 | await Should_load_hot_and_archive();
11 | }
12 | }
--------------------------------------------------------------------------------
/src/Experimental/src/ElasticPlayground/Generator.cs:
--------------------------------------------------------------------------------
1 | using Bogus;
2 | using Eventuous.Sut.App;
3 |
4 | namespace ElasticPlayground;
5 |
6 | public class Generator{
7 | public static string RandomString() => Guid.NewGuid().ToString();
8 |
9 | static readonly Faker Faker = new Faker()
10 | .CustomInstantiator(
11 | f => {
12 | var checkin = f.Noda().LocalDate.Soon();
13 | var checkout = checkin.PlusDays(f.Random.Number(1, 5));
14 |
15 | return new(f.Random.Guid().ToString("N"), f.Random.Guid().ToString("N"), checkin, checkout, f.Random.Number(50, 200));
16 | }
17 | );
18 |
19 | public static Commands.BookRoom CreateBookRoomCommand() => Faker.Generate();
20 | }
--------------------------------------------------------------------------------
/src/Experimental/src/ElasticPlayground/MiscExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using Eventuous.Sut.App;
5 | using Eventuous.Sut.Domain;
6 |
7 | namespace ElasticPlayground;
8 |
9 | public static class MiscExtensions {
10 | public static Commands.RecordPayment ToRecordPayment(this Commands.BookRoom command, string paymentId, float divider = 1)
11 | => new(
12 | new BookingId(command.BookingId),
13 | paymentId,
14 | new Money(command.Price / divider),
15 | DateTimeOffset.Now
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/src/Experimental/src/ElasticPlayground/ResultExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace ElasticPlayground;
2 |
3 | static class ResultExtensions {
4 | public static void Dump(this Result r) where T : State, new() {
5 | Console.WriteLine(r.Success ? "Success" : "Failure");
6 |
7 | r.Match(
8 | ok => {
9 | foreach (var change in ok.Changes!) {
10 | Console.WriteLine($"{change.EventType} {change.Event}");
11 | }
12 | },
13 | error => Console.WriteLine(error.ErrorMessage)
14 | );
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Experimental/src/Eventuous.Spyglass/Eventuous.Spyglass.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/Experimental/src/Eventuous.Spyglass/RegistrationExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2021-2022 Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using Microsoft.Extensions.DependencyInjection;
5 |
6 | namespace Eventuous.Spyglass;
7 |
8 | public static class RegistrationExtensions {
9 | public static IServiceCollection AddEventuousSpyglass(this IServiceCollection services)
10 | => services.AddSingleton();
11 | }
12 |
--------------------------------------------------------------------------------
/src/Extensions/src/Eventuous.Extensions.AspNetCore/Http/ContentTypes.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ.All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Extensions.AspNetCore;
5 |
6 | public static class ContentTypes {
7 | public const string ProblemDetails = "application/problem+json";
8 | public const string Json = "application/json";
9 | }
10 |
--------------------------------------------------------------------------------
/src/Extensions/src/Eventuous.Extensions.AspNetCore/Http/ControllerAttributes.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ.All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Extensions.AspNetCore;
5 |
6 | public class ProducesResult() : ProducesResponseTypeAttribute(typeof(Result.Ok), 200) where TState : State, new();
7 |
8 | public class ProducesConflict() : ProducesResponseTypeAttribute(typeof(ProblemDetails), 409);
9 |
10 | public class ProducesNotFound() : ProducesResponseTypeAttribute(typeof(ProblemDetails), 409);
11 |
12 | public class ProducesDomainError() : ProducesResponseTypeAttribute(typeof(ValidationProblemDetails), 400);
13 |
--------------------------------------------------------------------------------
/src/Extensions/src/Eventuous.Extensions.DependencyInjection/README.md:
--------------------------------------------------------------------------------
1 | # Eventuous ASP.NET Core
2 |
3 | This package adds several DI extensions for `IServiceCollection`:
4 |
5 | - `AddCommandService` to register app services
6 | - `AddAggregateStore` to register the `AggregateStore` and a given `IEventStore` (Eventuous does not need aggregate store to be registered, only use it if you use the aggregate store in your application directly)
7 | - `AddAggregate` to register aggregate types that require dependencies
8 |
9 | Keep in mind that we don't recommend having dependencies in aggregates, so you'd normally not need to use `AddAggregate`.
10 |
--------------------------------------------------------------------------------
/src/Extensions/src/Eventuous.Extensions.Logging/Eventuous.Extensions.Logging.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/Extensions/src/Eventuous.Subscriptions.Polly/Eventuous.Subscriptions.Polly.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Tools\TaskExtensions.cs
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/Extensions/test/Eventuous.Sut.AspNetCore/Program.cs:
--------------------------------------------------------------------------------
1 | using Eventuous.Sut.AspNetCore;
2 | using Eventuous.Sut.Domain;
3 | using Eventuous.TestHelpers;
4 | using Eventuous.Testing;
5 | using Microsoft.AspNetCore.Http.Json;
6 | using BookingService = Eventuous.Sut.AspNetCore.BookingService;
7 |
8 | DefaultEventSerializer.SetDefaultSerializer(new DefaultEventSerializer(TestPrimitives.DefaultOptions));
9 |
10 | var builder = WebApplication.CreateBuilder(args);
11 | builder.Services.AddCommandService();
12 | builder.Services.AddEventStore();
13 | builder.Services.Configure(options => options.SerializerOptions.ConfigureForTests());
14 |
15 | var app = builder.Build();
16 |
17 | var config = app.Services.GetService();
18 | config?.Invoke(app);
19 |
20 | app.Run();
21 |
22 | public partial class Program;
23 |
--------------------------------------------------------------------------------
/src/Extensions/test/Eventuous.Sut.AspNetCore/TestConfig.cs:
--------------------------------------------------------------------------------
1 | namespace Eventuous.Sut.AspNetCore;
2 |
3 | public delegate void ConfigureWebApplication(WebApplication app);
4 |
--------------------------------------------------------------------------------
/src/Extensions/test/Eventuous.Sut.AspNetCore/TestData.cs:
--------------------------------------------------------------------------------
1 | namespace Eventuous.Sut.AspNetCore;
2 |
3 | public static class TestData {
4 | public const string GuestId = "test guest";
5 | }
6 |
--------------------------------------------------------------------------------
/src/Extensions/test/Eventuous.Sut.AspNetCore/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/src/Extensions/test/Eventuous.Tests.DependencyInjection/Eventuous.Tests.DependencyInjection.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 | Eventuous.Tests.AspNetCore
5 | Exe
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/Extensions/test/Eventuous.Tests.DependencyInjection/Sut/TestAggregate.cs:
--------------------------------------------------------------------------------
1 | namespace Eventuous.Tests.AspNetCore.Sut;
2 |
3 | public class TestAggregate(TestDependency dependency) : Aggregate {
4 | public TestDependency Dependency { get; } = dependency;
5 | }
6 |
7 | public class AnotherTestAggregate(TestDependency dependency) : Aggregate {
8 | public TestDependency Dependency { get; } = dependency;
9 | }
10 |
11 | public record TestState : State;
12 |
13 | public record TestId(string Value) : Id(Value);
14 |
--------------------------------------------------------------------------------
/src/Extensions/test/Eventuous.Tests.DependencyInjection/Sut/TestDependency.cs:
--------------------------------------------------------------------------------
1 | namespace Eventuous.Tests.AspNetCore.Sut;
2 |
3 | public class TestDependency;
4 |
--------------------------------------------------------------------------------
/src/Extensions/test/Eventuous.Tests.Extensions.AspNetCore/AggregateCommandsTests.MapAggregateContractToCommandExplicitlyWithoutRouteWithGenericAttr_factory=Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1[Program].verified.txt:
--------------------------------------------------------------------------------
1 | {
2 | state: {
3 | price: {
4 | amount: 100,
5 | currency: EUR
6 | },
7 | amountPaid: {
8 | amount: 0,
9 | currency: EUR
10 | },
11 | id: {
12 | value: Guid_1
13 | }
14 | },
15 | changes: [
16 | {
17 | event: {
18 | roomId: Guid_2,
19 | price: 100,
20 | checkIn: 2023-10-01,
21 | checkOut: 2023-10-02
22 | },
23 | eventType: V1.BookingImported
24 | }
25 | ],
26 | globalPosition: 0
27 | }
--------------------------------------------------------------------------------
/src/Extensions/test/Eventuous.Tests.Extensions.AspNetCore/AggregateCommandsTests.MapAggregateContractToCommandExplicitlyWithoutRoute_factory=Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1[Program].verified.txt:
--------------------------------------------------------------------------------
1 | {
2 | state: {
3 | price: {
4 | amount: 100,
5 | currency: EUR
6 | },
7 | amountPaid: {
8 | amount: 0,
9 | currency: EUR
10 | },
11 | id: {
12 | value: Guid_1
13 | }
14 | },
15 | changes: [
16 | {
17 | event: {
18 | roomId: Guid_2,
19 | price: 100,
20 | checkIn: 2023-10-01,
21 | checkOut: 2023-10-02
22 | },
23 | eventType: V1.BookingImported
24 | }
25 | ],
26 | globalPosition: 0
27 | }
--------------------------------------------------------------------------------
/src/Extensions/test/Eventuous.Tests.Extensions.AspNetCore/AggregateCommandsTests.MapAggregateContractToCommandExplicitly_factory=Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1[Program].verified.txt:
--------------------------------------------------------------------------------
1 | {
2 | state: {
3 | price: {
4 | amount: 100,
5 | currency: EUR
6 | },
7 | amountPaid: {
8 | amount: 0,
9 | currency: EUR
10 | },
11 | id: {
12 | value: Guid_1
13 | }
14 | },
15 | changes: [
16 | {
17 | event: {
18 | roomId: Guid_2,
19 | price: 100,
20 | checkIn: 2023-10-01,
21 | checkOut: 2023-10-02
22 | },
23 | eventType: V1.BookingImported
24 | }
25 | ],
26 | globalPosition: 0
27 | }
--------------------------------------------------------------------------------
/src/Extensions/test/Eventuous.Tests.Extensions.AspNetCore/AggregateCommandsTests.MapEnrichedCommand_factory=Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1[Program].verified.txt:
--------------------------------------------------------------------------------
1 | {
2 | state: {
3 | price: {
4 | amount: 100,
5 | currency: EUR
6 | },
7 | amountPaid: {
8 | amount: 0,
9 | currency: EUR
10 | },
11 | id: {
12 | value: Guid_1
13 | }
14 | },
15 | changes: [
16 | {
17 | event: {
18 | roomId: Guid_2,
19 | checkIn: 2023-10-01,
20 | checkOut: 2023-10-02,
21 | price: 100,
22 | guestId: test guest
23 | },
24 | eventType: V1.RoomBooked
25 | }
26 | ],
27 | globalPosition: 0
28 | }
--------------------------------------------------------------------------------
/src/Extensions/test/Eventuous.Tests.Extensions.AspNetCore/DiscoveredCommandsTests.CallDiscoveredCommandRoute_factory=Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1[Program].verified.txt:
--------------------------------------------------------------------------------
1 | {
2 | state: {
3 | price: {
4 | amount: 100,
5 | currency: EUR
6 | },
7 | amountPaid: {
8 | amount: 0,
9 | currency: EUR
10 | },
11 | id: {
12 | value: Guid_1
13 | }
14 | },
15 | changes: [
16 | {
17 | event: {
18 | roomId: Guid_2,
19 | checkIn: 2023-10-01,
20 | checkOut: 2023-10-02,
21 | price: 100,
22 | guestId: guest
23 | },
24 | eventType: V1.RoomBooked
25 | }
26 | ],
27 | globalPosition: 0
28 | }
--------------------------------------------------------------------------------
/src/Extensions/test/Eventuous.Tests.Extensions.AspNetCore/Fixture/Enricher.cs:
--------------------------------------------------------------------------------
1 | namespace Eventuous.Tests.Extensions.AspNetCore.Fixture;
2 |
3 | public static class Enricher {
4 | internal static SutBookingCommands.ImportBooking EnrichCommand(TestCommands.ImportBookingHttp command, HttpContext _)
5 | => new(new(command.BookingId), command.RoomId, new(command.CheckIn, command.CheckOut), new(command.Price));
6 | }
7 |
--------------------------------------------------------------------------------
/src/Extensions/test/Eventuous.Tests.Extensions.AspNetCore/Fixture/Module.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | using VerifyTests.DiffPlex;
3 |
4 | namespace Eventuous.Tests.Extensions.AspNetCore.Fixture;
5 |
6 | public static class ModuleInitializer {
7 | [ModuleInitializer]
8 | public static void Initialize() {
9 | TypeMap.RegisterKnownEventTypes(typeof(BookingEvents.RoomBooked).Assembly);
10 | VerifyDiffPlex.Initialize(OutputType.Compact);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Extensions/test/Eventuous.Tests.Extensions.AspNetCore/Fixture/TestAggregate.cs:
--------------------------------------------------------------------------------
1 | namespace Eventuous.Tests.Extensions.AspNetCore.Fixture;
2 |
3 | record BrookingState : State;
--------------------------------------------------------------------------------
/src/Extensions/test/Eventuous.Tests.Extensions.AspNetCore/Fixture/TestBaseWithLogs.cs:
--------------------------------------------------------------------------------
1 | using Eventuous.TestHelpers.TUnit;
2 |
3 | namespace Eventuous.Tests.Extensions.AspNetCore.Fixture;
4 |
5 | public abstract class TestBaseWithLogs : IDisposable {
6 | readonly TestEventListener _listener = new();
7 |
8 | public void Dispose() => _listener.Dispose();
9 | }
10 |
--------------------------------------------------------------------------------
/src/Gateway/src/Eventuous.Gateway/Eventuous.Gateway.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Tools\TaskExtensions.cs
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/Gateway/src/Eventuous.Gateway/GatewayHandlerFactory.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Gateway;
5 |
6 | [PublicAPI]
7 | public static class GatewayHandlerFactory {
8 | public static IEventHandler Create(IProducer producer, RouteAndTransform routeAndTransform, bool awaitProduce) where T : class
9 | => new GatewayHandler(new GatewayProducer(producer), routeAndTransform, awaitProduce);
10 | }
11 |
--------------------------------------------------------------------------------
/src/Gateway/src/Eventuous.Gateway/GatewayMessage.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace Eventuous.Gateway;
5 |
6 | public record GatewayMessage(StreamName TargetStream, object Message, Metadata? Metadata, TProduceOptions ProduceOptions);
7 |
--------------------------------------------------------------------------------
/src/Gateway/src/Eventuous.Gateway/IGatewayTransform.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using Eventuous.Subscriptions.Context;
5 |
6 | namespace Eventuous.Gateway;
7 |
8 | ///
9 | /// Interface for routing and transformation of messages with produce options.
10 | ///
11 | public interface IGatewayTransform {
12 | ValueTask[]> RouteAndTransform(IMessageConsumeContext context);
13 | }
14 |
--------------------------------------------------------------------------------
/src/Gateway/test/Eventuous.Tests.Gateway/Eventuous.Tests.Gateway.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 | Exe
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/GooglePubSub/src/Eventuous.GooglePubSub.CloudRun/CloudRunPubSubSubscriptionOptions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using Eventuous.Subscriptions;
5 |
6 | namespace Eventuous.GooglePubSub.CloudRun;
7 |
8 | ///
9 | /// Cloud Run Pub/Sub subscription options
10 | ///
11 | public record CloudRunPubSubSubscriptionOptions : SubscriptionOptions {
12 | ///
13 | /// Pub/Sub topic ID, it will only be used for informational purposes
14 | ///
15 | public string TopicId { get; set; } = "unknown";
16 |
17 | ///
18 | /// Message attribute keys for system values like content type and event type
19 | ///
20 | public PubSubAttributes Attributes { get; set; } = new();
21 | }
22 |
--------------------------------------------------------------------------------
/src/GooglePubSub/src/Eventuous.GooglePubSub.CloudRun/EndpointMappingExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using Eventuous.GooglePubSub.CloudRun;
5 |
6 | // ReSharper disable CheckNamespace
7 |
8 | namespace Microsoft.AspNetCore.Builder;
9 |
10 | public static class EndpointMappingExtensions {
11 | public static WebApplication MapCloudRunPubSubSubscription(this WebApplication app, string path = "/") {
12 | CloudRunPubSubSubscription.MapSubscription(app, path);
13 |
14 | return app;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/GooglePubSub/src/Eventuous.GooglePubSub.CloudRun/Eventuous.GooglePubSub.CloudRun.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | PubSubAttributes.cs
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/GooglePubSub/src/Eventuous.GooglePubSub/Producers/PubSubProduceOptions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (C) Eventuous HQ OÜ. All rights reserved
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using Google.Protobuf.Collections;
5 |
6 | namespace Eventuous.GooglePubSub.Producers;
7 |
8 | ///
9 | /// Google PubSub produce options, supplied per message or batch
10 | ///
11 | [PublicAPI]
12 | public class PubSubProduceOptions {
13 | ///
14 | /// Function, which can be used to add custom message attributes
15 | ///
16 | public Func