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
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -473,11 +473,11 @@ var cachedRemoteProxy = Proxy<int, string>.Create(id => remoteProxy.Execute(id))
---

## Patterns Table
PatternKit currently tracks 106 production-readiness patterns. Each catalog pattern is represented in tests, documentation, real-world examples, IoC integration, and the BenchmarkDotNet coverage matrix.
PatternKit currently tracks 107 production-readiness patterns. Each catalog pattern is represented in tests, documentation, real-world examples, IoC integration, and the BenchmarkDotNet coverage matrix.

| Category | Count | Patterns |
| --- | ---: | --- |
| Application Architecture | 21 | Activity Tracker, Aggregate Root, Anti-Corruption Layer, Audit Log, Bounded Context, Context Map, CQRS, Data Mapper, Domain Event, Domain Service, Event Sourcing, Feature Toggle, Identity Map, Materialized View, Repository, Service Layer, Specification, Table Data Gateway, Transaction Script, Unit of Work, Value Object |
| Application Architecture | 22 | Activity Tracker, Aggregate Root, Anti-Corruption Layer, Audit Log, Bounded Context, Context Map, CQRS, Data Mapper, Domain Event, Domain Service, Event Sourcing, Feature Toggle, Identity Map, Materialized View, Repository, Service Layer, Specification, Table Data Gateway, Timeout Manager, Transaction Script, Unit of Work, Value Object |
| Behavioral | 11 | Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor |
| Cloud Architecture | 17 | Ambassador, Backends for Frontends, Bulkhead, Cache-Aside, Circuit Breaker, External Configuration Store, Gateway Aggregation, Gateway Routing, Health Endpoint Monitoring, Leader Election, Priority Queue, Queue-Based Load Leveling, Rate Limiting, Retry, Scheduler Agent Supervisor, Sidecar, Strangler Fig |
| Creational | 5 | Abstract Factory, Builder, Factory Method, Prototype, Singleton |
Expand All @@ -497,6 +497,8 @@ BenchmarkDotNet guidance is documented in [docs/guides/benchmarks.md](docs/guide
| Adapter | Execution | 59.084 ns | 416 B | 20.479 ns | 80 B | Generated adapter execution was faster and allocated less for shipment adaptation. |
| Activity Tracker | Construction | 13.09 ns | 152 B | 12.98 ns | 152 B | Same allocation; generated was slightly faster in this microbenchmark. |
| Activity Tracker | Execution | 446.88 ns | 1,656 B | 452.36 ns | 1,656 B | Same allocation; fluent was slightly faster for dashboard loading gates. |
| Timeout Manager | Construction | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Timeout Manager | Execution | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Aggregate Root | Construction | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Aggregate Root | Execution | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Aggregator | Construction | 14.562 ns | 168 B | 15.235 ns | 168 B | Same allocation; fluent was slightly faster in this microbenchmark. |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using BenchmarkDotNet.Attributes;
using PatternKit.Application.Timeouts;
using PatternKit.Examples.TimeoutManagerDemo;

namespace PatternKit.Benchmarks.Application;

[BenchmarkCategory("ApplicationArchitecture", "TimeoutManager")]
public class TimeoutManagerBenchmarks
{
private static readonly OrderReservationRequest Request = new(
Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"),
"REQ-100",
TimeSpan.FromMinutes(15));

private static readonly DateTimeOffset ExpiresAt = DateTimeOffset.UtcNow.AddMinutes(20);

[Benchmark(Baseline = true, Description = "Fluent: create timeout manager")]
[BenchmarkCategory("Fluent", "Construction")]
public TimeoutManager<Guid> Fluent_CreateTimeoutManager()
=> OrderReservationTimeoutManagers.CreateFluent();

[Benchmark(Description = "Generated: create timeout manager")]
[BenchmarkCategory("Generated", "Construction")]
public TimeoutManager<Guid> Generated_CreateTimeoutManager()
=> GeneratedOrderReservationTimeoutManager.CreateGenerated();

[Benchmark(Description = "Fluent: expire order reservation timeout")]
[BenchmarkCategory("Fluent", "Execution")]
public OrderReservationTimeoutSummary Fluent_ExpireOrderReservation()
=> OrderReservationTimeoutDemoRunner.RunFluent(Request, ExpiresAt);

[Benchmark(Description = "Generated: expire order reservation timeout")]
[BenchmarkCategory("Generated", "Execution")]
public OrderReservationTimeoutSummary Generated_ExpireOrderReservation()
=> OrderReservationTimeoutDemoRunner.RunGeneratedStatic(Request, ExpiresAt);
}
23 changes: 23 additions & 0 deletions docs/examples/order-reservation-timeout-manager.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Order Reservation Timeout Manager

This example models an order reservation hold that expires if the customer does not complete checkout before the deadline.

The fluent path builds the manager directly:

```csharp
var manager = OrderReservationTimeoutManagers.CreateFluent();
```

The generated path uses a source-generated factory:

```csharp
var manager = GeneratedOrderReservationTimeoutManager.CreateGenerated();
```

The example is importable through standard dependency injection:

```csharp
services.AddOrderReservationTimeoutDemo();
```

`OrderReservationTimeoutDemoRunner` schedules a reservation timeout and expires due holds. Production applications can pair the expired order identifiers with a message channel, outbox, saga, or service layer operation to release inventory and notify customers.
3 changes: 3 additions & 0 deletions docs/examples/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
- name: Dashboard Activity Tracker
href: dashboard-activity-tracker.md

- name: Order Reservation Timeout Manager
href: order-reservation-timeout-manager.md

- name: Auth & Logging with `ActionChain<HttpRequest>`
href: auth-logging-chain.md

Expand Down
1 change: 1 addition & 0 deletions docs/generators/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ PatternKit includes a Roslyn incremental generator package (`PatternKit.Generato
| [**Repository**](repository.md) | In-memory repository factories from key selectors | `[GenerateRepository]` |
| [**Anti-Corruption Layer**](anti-corruption-layer.md) | External-to-domain translation boundaries with validation | `[GenerateAntiCorruptionLayer]` |
| [**Activity Tracker**](activity-tracker.md) | Active-work tracker gates for loading and readiness workflows | `[GenerateActivityTracker]` |
| [**Timeout Manager**](timeout-manager.md) | Deadline registry for expiring pending workflow work | `[GenerateTimeoutManager]` |
| [**Audit Log**](audit-log.md) | Append-only audit log factories from key selectors | `[GenerateAuditLog]` |
| [**Unit of Work**](unit-of-work.md) | Ordered commit and rollback units | `[GenerateUnitOfWork]` |
| [**Data Mapper**](data-mapper.md) | Domain/data model mapper factories | `[GenerateDataMapper]` |
Expand Down
23 changes: 23 additions & 0 deletions docs/generators/timeout-manager.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Timeout Manager Generator

The Timeout Manager generator creates a strongly typed factory for `TimeoutManager<TKey>` from a partial host type.

```csharp
using PatternKit.Generators.Timeouts;

[GenerateTimeoutManager(typeof(Guid), FactoryMethodName = "CreateGenerated", ManagerName = "order-reservation-timeouts")]
public static partial class GeneratedOrderReservationTimeoutManager;
```

Generated output:

```csharp
TimeoutManager<Guid> manager = GeneratedOrderReservationTimeoutManager.CreateGenerated();
```

The generated path removes repeated factory boilerplate while keeping the runtime manager explicit and importable through normal `IServiceCollection` registration.

## Diagnostics

- `PKTM001`: the host type must be partial.
- `PKTM002`: `FactoryMethodName` and `ManagerName` must be non-empty.
3 changes: 3 additions & 0 deletions docs/generators/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,9 @@
- name: Table Data Gateway
href: table-data-gateway.md

- name: Timeout Manager
href: timeout-manager.md

- name: Strategy
href: strategy.md

Expand Down
10 changes: 7 additions & 3 deletions docs/guides/benchmark-results.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ The latest measured timings below were captured on Windows 11, Intel Core i9-149
| Adapter | Execution | 59.084 ns | 416 B | 20.479 ns | 80 B | Generated adapter execution was faster and allocated less for shipment adaptation. |
| Activity Tracker | Construction | 13.09 ns | 152 B | 12.98 ns | 152 B | Same allocation; generated was slightly faster in this microbenchmark. |
| Activity Tracker | Execution | 446.88 ns | 1,656 B | 452.36 ns | 1,656 B | Same allocation; fluent was slightly faster for dashboard loading gates. |
| Timeout Manager | Construction | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Timeout Manager | Execution | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Aggregate Root | Construction | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Aggregate Root | Execution | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Aggregator | Construction | 14.562 ns | 168 B | 15.235 ns | 168 B | Same allocation; fluent was slightly faster in this microbenchmark. |
Expand Down Expand Up @@ -230,19 +232,19 @@ The latest measured timings below were captured on Windows 11, Intel Core i9-149

## Coverage Matrix Summary

The coverage matrix currently publishes 106 catalog patterns and 424 pattern route results. Each pattern has four BenchmarkDotNet routes: fluent construction, fluent execution, source-generated construction, and source-generated execution. The reusable hosting integration matrix publishes 9 reusable hosting integration route results for package-level `IServiceCollection` registrations.
The coverage matrix currently publishes 107 catalog patterns and 428 pattern route results. Each pattern has four BenchmarkDotNet routes: fluent construction, fluent execution, source-generated construction, and source-generated execution. The reusable hosting integration matrix publishes 9 reusable hosting integration route results for package-level `IServiceCollection` registrations.

| Category | Patterns | Published route results |
| --- | ---: | ---: |
| Application Architecture | 21 | 84 |
| Application Architecture | 22 | 88 |
| Behavioral | 11 | 44 |
| Cloud Architecture | 17 | 68 |
| Creational | 5 | 20 |
| Enterprise Integration | 41 | 164 |
| Messaging Reliability | 3 | 12 |
| Structural | 7 | 28 |

The generator matrix currently publishes 101 generator source route results.
The generator matrix currently publishes 102 generator source route results.

## Hosting Integration Matrix Results

Expand All @@ -263,6 +265,7 @@ The generator matrix currently publishes 101 generator source route results.
| Category | Pattern | Fluent construction | Fluent execution | Generated construction | Generated execution |
| --- | --- | --- | --- | --- | --- |
| Application Architecture | Activity Tracker | Covered | Covered | Covered | Covered |
| Application Architecture | Timeout Manager | Covered | Covered | Covered | Covered |
| Application Architecture | Aggregate Root | Covered | Covered | Covered | Covered |
| Application Architecture | Anti-Corruption Layer | Covered | Covered | Covered | Covered |
| Application Architecture | Audit Log | Covered | Covered | Covered | Covered |
Expand Down Expand Up @@ -373,6 +376,7 @@ The generator matrix currently publishes 101 generator source route results.
| Generator | Source | Matrix result |
| --- | --- | --- |
| ActivityTrackerGenerator | `src/PatternKit.Generators/ActivityTracking/ActivityTrackerGenerator.cs` | Covered |
| TimeoutManagerGenerator | `src/PatternKit.Generators/Timeouts/TimeoutManagerGenerator.cs` | Covered |
| AggregateCommandHandlerGenerator | `src/PatternKit.Generators/Aggregates/AggregateCommandHandlerGenerator.cs` | Covered |
| AdapterGenerator | `src/PatternKit.Generators/Adapter/AdapterGenerator.cs` | Covered |
| AmbassadorGenerator | `src/PatternKit.Generators/Ambassador/AmbassadorGenerator.cs` | Covered |
Expand Down
2 changes: 2 additions & 0 deletions docs/guides/benchmarks.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ The following numbers were captured on Windows 11, Intel Core i9-14900K, .NET SD
| Adapter | Execution | 59.084 ns | 416 B | 20.479 ns | 80 B | Generated adapter execution was faster and allocated less for shipment adaptation. |
| Activity Tracker | Construction | 13.09 ns | 152 B | 12.98 ns | 152 B | Same allocation; generated was slightly faster in this microbenchmark. |
| Activity Tracker | Execution | 446.88 ns | 1,656 B | 452.36 ns | 1,656 B | Same allocation; fluent was slightly faster for dashboard loading gates. |
| Timeout Manager | Construction | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Timeout Manager | Execution | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Aggregate Root | Construction | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Aggregate Root | Execution | Pending | Pending | Pending | Pending | Covered by the BenchmarkDotNet matrix; publish measured values after the next benchmark refresh. |
| Aggregator | Construction | 14.562 ns | 168 B | 15.235 ns | 168 B | Same allocation; fluent was slightly faster in this microbenchmark. |
Expand Down
1 change: 1 addition & 0 deletions docs/guides/pattern-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ The source of truth is `PatternKitPatternCatalog` in `src/PatternKit.Examples/Pr
| Application Architecture | Materialized View | `IMaterializedView<TState,TEvent>` and `MaterializedView<TState,TEvent>` | Materialized View generator |
| Application Architecture | Anti-Corruption Layer | `AntiCorruptionLayer<TExternal, TDomain>` | Anti-Corruption Layer generator |
| Application Architecture | Activity Tracker | `ActivityTracker` | Activity Tracker generator |
| Application Architecture | Timeout Manager | `TimeoutManager<TKey>` | Timeout Manager generator |

## Research Baselines

Expand Down
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ if (parser.Execute("123", out var value))

## 📚 Available Patterns

PatternKit covers 106 production-readiness patterns with fluent APIs, source-generated routes where applicable, IoC integration examples, TinyBDD coverage, and BenchmarkDotNet coverage-matrix validation:
PatternKit covers 107 production-readiness patterns with fluent APIs, source-generated routes where applicable, IoC integration examples, TinyBDD coverage, and BenchmarkDotNet coverage-matrix validation:

| Category | Count | Patterns |
| --- | ---: | --- |
| Application Architecture | 21 | Activity Tracker, Aggregate Root, Anti-Corruption Layer, Audit Log, Bounded Context, Context Map, CQRS, Data Mapper, Domain Event, Domain Service, Event Sourcing, Feature Toggle, Identity Map, Materialized View, Repository, Service Layer, Specification, Table Data Gateway, Transaction Script, Unit of Work, Value Object |
| Application Architecture | 22 | Activity Tracker, Aggregate Root, Anti-Corruption Layer, Audit Log, Bounded Context, Context Map, CQRS, Data Mapper, Domain Event, Domain Service, Event Sourcing, Feature Toggle, Identity Map, Materialized View, Repository, Service Layer, Specification, Table Data Gateway, Timeout Manager, Transaction Script, Unit of Work, Value Object |
| Behavioral | 11 | Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor |
| Cloud Architecture | 17 | Ambassador, Backends for Frontends, Bulkhead, Cache-Aside, Circuit Breaker, External Configuration Store, Gateway Aggregation, Gateway Routing, Health Endpoint Monitoring, Leader Election, Priority Queue, Queue-Based Load Leveling, Rate Limiting, Retry, Scheduler Agent Supervisor, Sidecar, Strangler Fig |
| Creational | 5 | Abstract Factory, Builder, Factory Method, Prototype, Singleton |
Expand Down
28 changes: 28 additions & 0 deletions docs/patterns/application/timeout-manager.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Timeout Manager

Timeout Manager tracks deadlines for workflow work that should expire unless it is completed or canceled first. Use it when a saga, reservation, approval, shipment hold, or background operation needs a clear time boundary without coupling the domain workflow to a specific scheduler.

`TimeoutManager<TKey>` provides the fluent runtime path:

```csharp
var manager = TimeoutManager<Guid>
.Create("order-reservation-timeouts")
.Build();

manager.ScheduleAfter(orderId, TimeSpan.FromMinutes(15), requestId);
var expired = manager.ExpireDue(DateTimeOffset.UtcNow.AddMinutes(20));
```

The manager is in-memory and intentionally small. Application code can persist the returned `TimeoutRecord<TKey>` values in its own store or use the manager inside a hosted service that loads pending deadlines, calls `ExpireDue`, and dispatches expiration work through existing PatternKit messaging or workflow patterns.

## Use When

- Work can enter and leave a pending state at arbitrary times.
- The only decision needed by downstream code is whether deadlines are still pending or due.
- Expiration should be explicit and testable instead of hidden in timers.

## Compare With

- Use Saga / Process Manager when the workflow owns multiple correlated messages and state transitions.
- Use Scheduler Agent Supervisor when the system owns recurring scheduled work.
- Use Activity Tracker when the concern is active/inactive gating rather than time-based expiration.
2 changes: 2 additions & 0 deletions docs/patterns/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,8 @@
href: application/context-map.md
- name: Table Data Gateway
href: application/table-data-gateway.md
- name: Timeout Manager
href: application/timeout-manager.md
- name: Event Sourcing
href: application/event-sourcing.md
- name: Feature Toggle
Expand Down
Loading
Loading