Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions .github/workflows/on-push-do-ci-build-pg15-jsonnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@ jobs:
run: ./build.sh test-patching
shell: bash

- name: test-value-types
if: ${{ success() || failure() }}
run: ./build.sh test-value-types
shell: bash
# - name: test-value-types
# if: ${{ success() || failure() }}
# run: ./build.sh test-value-types
# shell: bash

- name: test-code-gen
if: ${{ success() || failure() }}
Expand All @@ -129,7 +129,7 @@ jobs:
run: ./build.sh test-noda-time
shell: bash

- name: test-aspnet-core
if: ${{ success() || failure() }}
run: ./build.sh test-aspnet-core
shell: bash
#- name: test-aspnet-core
# if: ${{ success() || failure() }}
# run: ./build.sh test-aspnet-core
# shell: bash
4 changes: 2 additions & 2 deletions docs/configuration/hostbuilder.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ public interface IConfigureMarten
void Configure(IServiceProvider services, StoreOptions options);
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten/MartenServiceCollectionExtensions.cs#L880-L891' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_iconfiguremarten' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten/MartenServiceCollectionExtensions.cs#L881-L892' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_iconfiguremarten' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

You could alternatively implement a custom `IConfigureMarten` (or `IConfigureMarten<T> where T : IDocumentStore` if you're working with multiple databases class like so:
Expand Down Expand Up @@ -321,7 +321,7 @@ public interface IAsyncConfigureMarten
ValueTask Configure(StoreOptions options, CancellationToken cancellationToken);
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten/MartenServiceCollectionExtensions.cs#L893-L905' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_iasyncconfiguremarten' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten/MartenServiceCollectionExtensions.cs#L894-L906' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_iasyncconfiguremarten' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

As an example from the tests, here's a custom version that uses the Feature Management service:
Expand Down
2 changes: 1 addition & 1 deletion docs/configuration/storeoptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public static DocumentStore For(Action<StoreOptions> configure)
return new DocumentStore(options);
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten/DocumentStore.cs#L498-L508' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_documentstore.for' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/Marten/DocumentStore.cs#L503-L513' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_documentstore.for' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

The major parts of `StoreOptions` are shown in the class diagram below:
Expand Down
12 changes: 6 additions & 6 deletions docs/events/projections/async-daemon.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ You can see the usage below from one of the Marten tests where we use that metho
daemon has caught up:

<!-- snippet: sample_using_WaitForNonStaleProjectionDataAsync -->
<a id='snippet-sample_using_WaitForNonStaleProjectionDataAsync'></a>
<a id='snippet-sample_using_waitfornonstaleprojectiondataasync'></a>
```cs
[Fact]
public async Task run_simultaneously()
Expand All @@ -241,7 +241,7 @@ public async Task run_simultaneously()
await CheckExpectedResults();
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/EventProjections/event_projections_end_to_end.cs#L28-L49' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_WaitForNonStaleProjectionDataAsync' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/EventProjections/event_projections_end_to_end.cs#L28-L49' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_waitfornonstaleprojectiondataasync' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

The basic idea in your tests is to:
Expand Down Expand Up @@ -289,7 +289,7 @@ public async Task run_simultaneously()
The following code shows the diagnostics support for the async daemon as it is today:

<!-- snippet: sample_DaemonDiagnostics -->
<a id='snippet-sample_DaemonDiagnostics'></a>
<a id='snippet-sample_daemondiagnostics'></a>
```cs
public static async Task ShowDaemonDiagnostics(IDocumentStore store)
{
Expand All @@ -308,7 +308,7 @@ public static async Task ShowDaemonDiagnostics(IDocumentStore store)
Console.WriteLine($"The daemon high water sequence mark is {daemonHighWaterMark}");
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/CommandLineRunner/AsyncDaemonBootstrappingSamples.cs#L109-L128' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_DaemonDiagnostics' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/CommandLineRunner/AsyncDaemonBootstrappingSamples.cs#L109-L128' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_daemondiagnostics' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

## Command Line Support
Expand Down Expand Up @@ -429,7 +429,7 @@ from systems using Marten.
If your system is configured to export metrics and Open Telemetry data from Marten like this:

<!-- snippet: sample_enabling_open_telemetry_exporting_from_Marten -->
<a id='snippet-sample_enabling_open_telemetry_exporting_from_Marten'></a>
<a id='snippet-sample_enabling_open_telemetry_exporting_from_marten'></a>
```cs
// This is passed in by Project Aspire. The exporter usage is a little
// different for other tools like Prometheus or SigNoz
Expand All @@ -448,7 +448,7 @@ builder.Services.AddOpenTelemetry()
metrics.AddMeter("Marten");
});
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/samples/AspireHeadlessTripService/Program.cs#L21-L40' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_enabling_open_telemetry_exporting_from_Marten' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/samples/AspireHeadlessTripService/Program.cs#L21-L40' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_enabling_open_telemetry_exporting_from_marten' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

*And* you are running the async daemon in your system, you should see potentially activities for each running projection
Expand Down
23 changes: 21 additions & 2 deletions docs/events/projections/composite.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ opts.Projections.CompositeProjectionFor("TeleHealth", projection =>
projection.Add<BoardSummaryProjection>(2);
});
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/Composites/multi_stage_projections.cs#L181-L194' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_defining_a_composite_projection' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/Composites/multi_stage_projections.cs#L182-L195' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_defining_a_composite_projection' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

First, let's just look at the simple `ProviderShiftProjection`:
Expand Down Expand Up @@ -167,6 +167,11 @@ public class AppointmentDetailsProjection : MultiStreamProjection<AppointmentDet
Identity<Updated<Appointment>>(x => x.Entity.Id);
Identity<IEvent<ProviderAssigned>>(x => x.StreamId);
Identity<IEvent<AppointmentRouted>>(x => x.StreamId);

// This is a synthetic event published from upstream projections to identify
// which projected Appointment documents were deleted as part of the current event range
// so we can keep this richer model mirroring the simpler Appointment projection
Identity<ProjectionDeleted<Appointment, Guid>>(x => x.Identity);
}

public override async Task EnrichEventsAsync(SliceGroup<AppointmentDetails, Guid> group, IQuerySession querySession, CancellationToken cancellation)
Expand Down Expand Up @@ -243,19 +248,33 @@ public class AppointmentDetailsProjection : MultiStreamProjection<AppointmentDet
snapshot.BoardName = board.Entity.Name;
snapshot.BoardId = board.Entity.Id;
break;

// The matching projection for Appointment was deleted
// so we'll delete this enriched projection as well
// ProjectionDeleted<TDoc> is a synthetic event that Marten
// itself publishes from the upstream projections and available
// to downstream projections
case ProjectionDeleted<Appointment>:
return null;
}

return snapshot;
}

}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/TeleHealth/AppointmentDetailsProjection.cs#L14-L115' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_appointmentdetailsprojection' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/TeleHealth/AppointmentDetailsProjection.cs#L14-L128' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_appointmentdetailsprojection' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

::: tip
The new `Updated<T>` synthetic event that we're using to communicate updates between projections can also be used within
`Apply()`, `Create`, or `ShouldDelete` methods as well.

There is also a corresponding `ProjectionDeleted<TDoc, TId>` synthetic event that will communicate updates between projections
and can also be used with `Apply()`, `Create`, or `ShouldDelete` methods.

The `ProjectionDeleted<TDoc,TId>` also implements some simpler interfaces `ProjectionDeleted<TDoc>` and `DeletedIdentity<TId>` that are available
just as conveniences to avoid the proliferation of ugly generics in your code.
:::

And also the definition for the downstream `BoardSummary` view:
Expand Down
12 changes: 10 additions & 2 deletions docs/events/projections/enrichment.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ await group
.ForEntityId(x => x.BoardId)
.AddReferences();
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/TeleHealth/AppointmentDetailsProjection.cs#L44-L61' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_forevent_addreferences' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/TeleHealth/AppointmentDetailsProjection.cs#L49-L66' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_forevent_addreferences' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

What this does is data lookup for all the unique `Provider` and `Board` documents that match
Expand Down Expand Up @@ -395,10 +395,18 @@ public override AppointmentDetails Evolve(AppointmentDetails snapshot, Guid id,
snapshot.BoardName = board.Entity.Name;
snapshot.BoardId = board.Entity.Id;
break;

// The matching projection for Appointment was deleted
// so we'll delete this enriched projection as well
// ProjectionDeleted<TDoc> is a synthetic event that Marten
// itself publishes from the upstream projections and available
// to downstream projections
case ProjectionDeleted<Appointment>:
return null;
}

return snapshot;
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/TeleHealth/AppointmentDetailsProjection.cs#L65-L112' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_appointmentdetails_evolve' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/TeleHealth/AppointmentDetailsProjection.cs#L70-L125' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_appointmentdetails_evolve' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
5 changes: 4 additions & 1 deletion docs/events/projections/explicit.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,16 @@ public class AppointmentProjection: SingleStreamProjection<Appointment, Guid>
snapshot.Status = AppointmentStatus.Completed;
snapshot.Completed = e.Timestamp;
break;

case AppointmentCancelled:
return null;
}

return snapshot;
}
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/TeleHealth/Appointments.cs#L40-L93' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_appointmentprojection' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/TeleHealth/Appointments.cs#L42-L98' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_appointmentprojection' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

If your "evolve" step will require some data lookups or need to utilize any kind of asynchronous service, use
Expand Down
42 changes: 42 additions & 0 deletions docs/events/projections/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,48 @@ var store = DocumentStore.For(_ =>

At this point, you would be able to query against `QuestParty` as just another document type.

## Logging in Projections <Badge type="tip" text="8.19" />

*If* you are running Marten within a .NET application that bootstraps an `IHost` and registering Marten through
`AddMarten()`, all the projections registered in your Marten application will have an instance property for the
`ILogger` like this:

<!-- snippet: sample_using_Logger_in_projections -->
<a id='snippet-sample_using_logger_in_projections'></a>
```cs
// If you have to be all special and want to group the logging
// your own way, just override this method:
public override void AttachLogger(ILoggerFactory loggerFactory)
{
Logger = loggerFactory.CreateLogger<MyLoggingMarkerType>();
}

public void Project(
IEvent<AppointmentStarted> @event,
IDocumentOperations ops)
{
// Outside of AddMarten() usage, this would be a NullLogger
// Inside of an app bootstrapped as an IHost with standard .NET
// logging registered and Marten bootstrapped through AddMarten(),
// Logger would be an ILogger<T> *by default* where T is the concrete
// type of the actual projection
Logger?.LogDebug("Hey, I'm inserting a row for appointment started");

var sql = "insert into appointment_duration "
+ "(id, start) values (?, ?)";
ops.QueueSqlCommand(sql,
@event.Id,
@event.Timestamp);
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/TeleHealth/AppointmentDurationProjection.cs#L29-L56' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_logger_in_projections' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

::: warning
If you are registering a projection into your DI container, you are responsible for injecting and configuring
the correct `ILogger`.
:::

## Rebuilding Projections

Projections need to be rebuilt when the code that defines them changes in a way that requires events to be reapplied in order to maintain correct state. Using an `IDaemon` this is easy to execute on-demand:
Expand Down
2 changes: 1 addition & 1 deletion docs/events/projections/read-aggregates.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ var summaries = await theSession
.QueryForNonStaleData<BoardSummary>(10.Seconds())
.ToListAsync();
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/Composites/multi_stage_projections.cs#L234-L244' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_querying_for_non_stale_projection_data' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/Composites/multi_stage_projections.cs#L235-L245' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_querying_for_non_stale_projection_data' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

To be clear though, if you need the latest version of a single stream projection, we recommend always
Expand Down
5 changes: 4 additions & 1 deletion docs/events/projections/single-stream-projections.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,13 +215,16 @@ public class AppointmentProjection: SingleStreamProjection<Appointment, Guid>
snapshot.Status = AppointmentStatus.Completed;
snapshot.Completed = e.Timestamp;
break;

case AppointmentCancelled:
return null;
}

return snapshot;
}
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/TeleHealth/Appointments.cs#L40-L93' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_appointmentprojection' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DaemonTests/TeleHealth/Appointments.cs#L42-L98' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_appointmentprojection' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

And a more complicated sample from our tests that just shows how you can create a reentrant workflow that includes
Expand Down
Loading
Loading