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
27 changes: 27 additions & 0 deletions docs/events/projections/async-daemon.md
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,33 @@ using multi-tenancy through a database per tenant. On these spans will be these
There is also a counter metric called `marten.daemon.skipping` or `marten.[database name].daemon.skipping`
that just emits and update every time that Marten has to "skip" stale events.

## Extended Progression Tracking

When you opt into extended progression tracking, Marten adds six monitoring
columns (`heartbeat`, `agent_status`, `pause_reason`, `running_on_node`,
`warning_behind_threshold`, `critical_behind_threshold`) to `mt_event_progression`
and the async daemon writes them from runtime state. The shard-state selector
reads them back into `ShardState` so monitoring tooling such as CritterWatch can
display per-shard health.

```cs
opts.Events.EnableExtendedProgressionTracking = true;
```

Marten 9.7 also implements the storage-agnostic
[`IEventStoreInstrumentation`](https://github.com/JasperFx/jasperfx/blob/main/src/JasperFx.Events/IEventStoreInstrumentation.cs)
abstraction from JasperFx.Events 2.9.0 — `Wolverine.CritterWatch.Marten` and
similar satellite packages flip the same toggle via the interface without
referencing Marten's concrete `EventGraph`:

```cs
((IEventStoreInstrumentation)opts.Events).ExtendedProgressionEnabled = true;
```

Both names refer to the same underlying field. New code is encouraged to prefer
the interface property; `EnableExtendedProgressionTracking` continues to work
without deprecation warnings.

## Advanced Skipping Tracking <Badge type="tip" text="8.6" />

::: info
Expand Down
75 changes: 75 additions & 0 deletions src/CoreTests/Events/EventGraph_IEventStoreInstrumentation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using JasperFx.Events;
using Marten.Events;
using Shouldly;
using Xunit;

namespace CoreTests.Events;

// #4686 — EventGraph implements JasperFx.Events.IEventStoreInstrumentation (shipped in
// JasperFx 2.9.0, jasperfx#424). Both the legacy EnableExtendedProgressionTracking property
// and the storage-agnostic ExtendedProgressionEnabled name on IEventStoreInstrumentation must
// alias the same underlying field, so Wolverine.CritterWatch.Marten can flip the toggle via
// the abstraction without breaking existing code that sets EnableExtendedProgressionTracking
// directly.
public class EventGraph_IEventStoreInstrumentation
{
private static EventGraph BuildEventGraph()
{
// EventGraph requires a StoreOptions to wire up its registry, but a default
// StoreOptions is sufficient here -- no connection or schema interaction.
return new EventGraph(new Marten.StoreOptions());
}

[Fact]
public void implements_event_store_instrumentation()
{
BuildEventGraph().ShouldBeAssignableTo<IEventStoreInstrumentation>();
}

[Fact]
public void default_is_disabled()
{
var events = BuildEventGraph();

events.EnableExtendedProgressionTracking.ShouldBeFalse();
events.ExtendedProgressionEnabled.ShouldBeFalse();
((IEventStoreInstrumentation)events).ExtendedProgressionEnabled.ShouldBeFalse();
}

[Fact]
public void enabling_via_legacy_name_flows_to_interface_property()
{
var events = BuildEventGraph();
var instrumentation = (IEventStoreInstrumentation)events;

events.EnableExtendedProgressionTracking = true;

events.ExtendedProgressionEnabled.ShouldBeTrue();
instrumentation.ExtendedProgressionEnabled.ShouldBeTrue();
}

[Fact]
public void enabling_via_interface_flows_to_legacy_name()
{
var events = BuildEventGraph();
var instrumentation = (IEventStoreInstrumentation)events;

instrumentation.ExtendedProgressionEnabled = true;

events.EnableExtendedProgressionTracking.ShouldBeTrue();
events.ExtendedProgressionEnabled.ShouldBeTrue();
}

[Fact]
public void disabling_via_either_surface_unwinds_the_other()
{
var events = BuildEventGraph();
var instrumentation = (IEventStoreInstrumentation)events;

events.EnableExtendedProgressionTracking = true;
instrumentation.ExtendedProgressionEnabled = false;

events.EnableExtendedProgressionTracking.ShouldBeFalse();
events.ExtendedProgressionEnabled.ShouldBeFalse();
}
}
29 changes: 25 additions & 4 deletions src/Marten/Events/EventGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ namespace Marten.Events;
Justification = "Class-level: uses Type.MakeGenericType / MethodInfo.MakeGenericMethod / Activator.CreateInstance / FastExpressionCompiler — runtime code generation. AOT consumers pre-generate codegen artifacts (codegen write) and supply source-generator-backed serializer impls per the AOT publishing guide.")]
public partial class EventGraph: EventRegistry, IEventStoreOptions, IReadOnlyEventStoreOptions,
IDisposable, IAsyncDisposable,
IAggregationSourceFactory<IQuerySession>, IDescribeMyself
IAggregationSourceFactory<IQuerySession>, IDescribeMyself,
IEventStoreInstrumentation
{
private readonly Cache<Type, string> _aggregateNameByType =
new(type => type.IsGenericType ? type.ShortNameInCode() : type.Name.ToTableAlias());
Expand Down Expand Up @@ -232,10 +233,30 @@ public override IEvent BuildEvent(object eventData)
public bool EnableEventSkippingInProjectionsOrSubscriptions { get; set; }

/// <summary>
/// When enabled, adds heartbeat, agent_status, pause_reason, and running_on_node
/// columns to the event progression table for CritterWatch monitoring
/// When enabled, adds heartbeat, agent_status, pause_reason, running_on_node, and
/// warning/critical-behind-threshold columns to the event progression table for
/// CritterWatch monitoring.
/// <para>
/// This is the long-standing Marten-side toggle; #4686 added the storage-agnostic
/// <see cref="IEventStoreInstrumentation.ExtendedProgressionEnabled"/> as a sibling so
/// store-agnostic monitoring tooling (e.g. <c>Wolverine.CritterWatch.Marten</c>) can flip
/// the switch via the JasperFx.Events abstraction without referencing Marten's concrete
/// option type. Both names refer to the same underlying field; new code is encouraged to
/// prefer <c>ExtendedProgressionEnabled</c> on the interface.
/// </para>
/// </summary>
public bool EnableExtendedProgressionTracking { get; set; }
public bool EnableExtendedProgressionTracking
{
get => ExtendedProgressionEnabled;
set => ExtendedProgressionEnabled = value;
}

/// <summary>
/// <see cref="IEventStoreInstrumentation.ExtendedProgressionEnabled"/> -- the primary
/// (storage-agnostic) toggle that controls extended progression tracking. Aliased by the
/// legacy <see cref="EnableExtendedProgressionTracking"/> property.
/// </summary>
public bool ExtendedProgressionEnabled { get; set; }
public bool UseArchivedStreamPartitioning { get; set; }
public bool UseListenNotifyForEventAppends { get; set; }

Expand Down
Loading