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 @@ -446,15 +446,15 @@ var cachedRemoteProxy = Proxy<int, string>.Create(id => remoteProxy.Execute(id))
---

## Patterns Table
PatternKit currently tracks 95 production-readiness patterns. Each catalog pattern is represented in tests, documentation, real-world examples, IoC integration, and the BenchmarkDotNet coverage matrix.
PatternKit currently tracks 96 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 | 16 | Activity Tracker, Anti-Corruption Layer, Audit Log, CQRS, Data Mapper, Domain Event, Event Sourcing, Feature Toggle, Identity Map, Materialized View, Repository, Service Layer, Specification, Table Data Gateway, Transaction Script, Unit of Work |
| 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 |
| Enterprise Integration | 36 | Aggregator, Canonical Data Model, Channel Adapter, Channel Purger, Claim Check, Competing Consumers, Content-Based Router, Control Bus, Dead Letter Channel, Durable Subscriber, Dynamic Router, Event Notification, Event-Carried State Transfer, Event-Driven Consumer, Invalid Message Channel, Mailbox, Message Bus, Message Channel, Message Envelope, Message Filter, Message Store, Message Translator, Messaging Bridge, Messaging Gateway, Pipes and Filters, Polling Consumer, Publish-Subscribe, Recipient List, Request-Reply, Resequencer, Routing Slip, Saga / Process Manager, Scatter-Gather, Service Activator, Splitter, Wire Tap |
| Enterprise Integration | 37 | Aggregator, Canonical Data Model, Channel Adapter, Channel Purger, Claim Check, Competing Consumers, Content-Based Router, Control Bus, Dead Letter Channel, Durable Subscriber, Dynamic Router, Event Notification, Event-Carried State Transfer, Event-Driven Consumer, Invalid Message Channel, Mailbox, Message Bus, Message Channel, Message Envelope, Message Filter, Message History, Message Store, Message Translator, Messaging Bridge, Messaging Gateway, Pipes and Filters, Polling Consumer, Publish-Subscribe, Recipient List, Request-Reply, Resequencer, Routing Slip, Saga / Process Manager, Scatter-Gather, Service Activator, Splitter, Wire Tap |
| Messaging Reliability | 3 | Idempotent Receiver, Inbox, Outbox |
| Structural | 7 | Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy |

Expand Down Expand Up @@ -522,6 +522,8 @@ BenchmarkDotNet guidance is documented in [docs/guides/benchmarks.md](docs/guide
| Message Bus | Execution | 503.8 ns | 3,192 B | 587.7 ns | 3,232 B | Fluent was faster and allocated slightly less for publishing order events to topic subscribers. |
| Messaging Bridge | Construction | 184.0 ns | 1,328 B | 185.5 ns | 1,328 B | Same allocation; fluent and generated bridge construction were effectively equivalent. |
| Messaging Bridge | Execution | 666.8 ns | 3,912 B | 670.8 ns | 3,912 B | Same allocation; fluent was slightly faster for partner order imports. |
| Message History | Construction | 6.843 ns | 56 B | 6.075 ns | 56 B | Same allocation; generated was slightly faster for history recorder construction. |
| Message History | Execution | 275.298 ns | 1,400 B | 285.765 ns | 1,400 B | Same allocation; fluent was slightly faster for order history recording. |
| Decorator | Construction | 34.293 ns | 264 B | 17.669 ns | 168 B | Generated decorator composition was faster and allocated less. |
| Decorator | Execution | 60.765 ns | 384 B | 35.551 ns | 304 B | Generated decorator execution was faster and allocated less for decorated storage reads. |
| Domain Event | Construction | 199.5 ns | 1.34 KB | 157.6 ns | 1.04 KB | Generated reduced construction time and allocation in this microbenchmark. |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using BenchmarkDotNet.Attributes;
using PatternKit.Examples.Messaging;
using PatternKit.Messaging.Diagnostics;

namespace PatternKit.Benchmarks.Messaging;

[BenchmarkCategory("EnterpriseIntegration", "Messaging", "MessageHistory")]
public class MessageHistoryBenchmarks
{
private static readonly HistoryOrder Order = new("O-100", 125m, "web");

[Benchmark(Baseline = true, Description = "Fluent: create message history")]
[BenchmarkCategory("Fluent", "Construction")]
public MessageHistory<HistoryOrder> Fluent_CreateMessageHistory()
=> OrderMessageHistories.CreateReceived();

[Benchmark(Description = "Generated: create message history")]
[BenchmarkCategory("Generated", "Construction")]
public MessageHistory<HistoryOrder> Generated_CreateMessageHistory()
=> GeneratedOrderReceivedHistory.Create()
.Details(static message => message.Payload.Channel)
.Build();

[Benchmark(Description = "Fluent: record order message history")]
[BenchmarkCategory("Fluent", "Execution")]
public OrderMessageHistorySummary Fluent_RecordOrderHistory()
=> OrderMessageHistoryExampleRunner.RunFluent(Order);

[Benchmark(Description = "Generated: record order message history")]
[BenchmarkCategory("Generated", "Execution")]
public OrderMessageHistorySummary Generated_RecordOrderHistory()
=> OrderMessageHistoryExampleRunner.RunGeneratedStatic(Order);
}
11 changes: 11 additions & 0 deletions docs/examples/order-message-history.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Order Message History

This example models an order moving through a checkout API and fulfillment router.

- `MessageHistory<HistoryOrder>` appends handling steps to the message envelope.
- The fluent path builds the same recorders by hand.
- The generated path uses `[GenerateMessageHistory]` for stable component factories.
- Correlation metadata remains on the message while history entries accumulate.
- `AddOrderMessageHistoryDemo()` imports the generated path through `IServiceCollection`.

The example is implemented in `src/PatternKit.Examples/Messaging/OrderMessageHistoryExample.cs` and validated by TinyBDD tests in `test/PatternKit.Examples.Tests/Messaging/OrderMessageHistoryExampleTests.cs`.
3 changes: 3 additions & 0 deletions docs/examples/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@
- name: Partner Order Messaging Bridge
href: partner-order-messaging-bridge.md

- name: Order Message History
href: order-message-history.md

- name: Order Wire Tap
href: order-wire-tap.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 @@ -84,6 +84,7 @@ PatternKit includes a Roslyn incremental generator package (`PatternKit.Generato
| [**Message Channel**](message-channel.md) | Typed channel factories for in-process message queues | `[GenerateMessageChannel]` |
| [**Message Bus**](message-bus.md) | Topic bus topology factories over message channels | `[GenerateMessageBus]` |
| [**Messaging Bridge**](messaging-bridge.md) | Channel-to-bus bridge factories for topology boundaries | `[GenerateMessagingBridge]` |
| [**Message History**](message-history.md) | Message handling history factories for auditable envelopes | `[GenerateMessageHistory]` |
| [**Channel Purger**](channel-purger.md) | Channel maintenance purger factories for in-process message queues | `[GenerateChannelPurger]` |
| [**Invalid Message Channel**](invalid-message-channel.md) | Invalid-message channel builder factories for validation boundaries | `[GenerateInvalidMessageChannel]` |
| [**Polling Consumer**](polling-consumer.md) | Pull-based message consumer factories | `[GeneratePollingConsumer]` |
Expand Down
27 changes: 27 additions & 0 deletions docs/generators/message-history.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Message History Generator

`[GenerateMessageHistory]` emits a typed message history factory.

```csharp
[GenerateMessageHistory(
typeof(HistoryOrder),
"checkout-api",
FactoryName = "Create",
Action = "received")]
public static partial class GeneratedOrderReceivedHistory;
```

The generated factory returns a `MessageHistory<TPayload>.Builder`, so application code can still add runtime-only details or a deterministic test clock:

```csharp
var history = GeneratedOrderReceivedHistory.Create()
.Details(message => message.Payload.Channel)
.Build();
```

Diagnostics:

| ID | Meaning |
| --- | --- |
| `PKMH001` | The host type must be `partial`. |
| `PKMH002` | Factory, component, action, and header names 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 @@ -109,6 +109,9 @@
- name: Messaging Bridge
href: messaging-bridge.md

- name: Message History
href: message-history.md

- name: Channel Purger
href: channel-purger.md

Expand Down
16 changes: 10 additions & 6 deletions docs/guides/benchmark-results.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ The latest measured timings below were captured on Windows 11, Intel Core i9-149
| Message Bus | Execution | 503.8 ns | 3,192 B | 587.7 ns | 3,232 B | Fluent was faster and allocated slightly less for publishing order events to topic subscribers. |
| Messaging Bridge | Construction | 184.0 ns | 1,328 B | 185.5 ns | 1,328 B | Same allocation; fluent and generated bridge construction were effectively equivalent. |
| Messaging Bridge | Execution | 666.8 ns | 3,912 B | 670.8 ns | 3,912 B | Same allocation; fluent was slightly faster for partner order imports. |
| Message History | Construction | 6.843 ns | 56 B | 6.075 ns | 56 B | Same allocation; generated was slightly faster for history recorder construction. |
| Message History | Execution | 275.298 ns | 1,400 B | 285.765 ns | 1,400 B | Same allocation; fluent was slightly faster for order history recording. |
| Decorator | Construction | 34.293 ns | 264 B | 17.669 ns | 168 B | Generated decorator composition was faster and allocated less. |
| Decorator | Execution | 60.765 ns | 384 B | 35.551 ns | 304 B | Generated decorator execution was faster and allocated less for decorated storage reads. |
| Domain Event | Construction | 199.5 ns | 1.34 KB | 157.6 ns | 1.04 KB | Generated reduced construction time and allocation in this microbenchmark. |
Expand Down Expand Up @@ -208,19 +210,19 @@ The latest measured timings below were captured on Windows 11, Intel Core i9-149

## Coverage Matrix Summary

The coverage matrix currently publishes 95 catalog patterns and 380 pattern route results. Each pattern has four BenchmarkDotNet routes: fluent construction, fluent execution, source-generated construction, and source-generated execution.
The coverage matrix currently publishes 96 catalog patterns and 384 pattern route results. Each pattern has four BenchmarkDotNet routes: fluent construction, fluent execution, source-generated construction, and source-generated execution.

| Category | Patterns | Published route results |
| --- | ---: | ---: |
| Application Architecture | 16 | 64 |
| Behavioral | 11 | 44 |
| Cloud Architecture | 17 | 68 |
| Creational | 5 | 20 |
| Enterprise Integration | 36 | 144 |
| Enterprise Integration | 37 | 148 |
| Messaging Reliability | 3 | 12 |
| Structural | 7 | 28 |

The generator matrix currently publishes 91 generator source route results.
The generator matrix currently publishes 92 generator source route results.

## Pattern Matrix Results

Expand Down Expand Up @@ -289,6 +291,7 @@ The generator matrix currently publishes 91 generator source route results.
| Enterprise Integration | Dynamic Router | Covered | Covered | Covered | Covered |
| Enterprise Integration | Message Bus | Covered | Covered | Covered | Covered |
| Enterprise Integration | Messaging Bridge | Covered | Covered | Covered | Covered |
| Enterprise Integration | Message History | Covered | Covered | Covered | Covered |
| Enterprise Integration | Event Notification | Covered | Covered | Covered | Covered |
| Enterprise Integration | Event-Carried State Transfer | Covered | Covered | Covered | Covered |
| Enterprise Integration | Event-Driven Consumer | Covered | Covered | Covered | Covered |
Expand Down Expand Up @@ -380,9 +383,10 @@ The generator matrix currently publishes 91 generator source route results.
| MessageBusGenerator | `src/PatternKit.Generators/Messaging/MessageBusGenerator.cs` | Covered |
| MessagingBridgeGenerator | `src/PatternKit.Generators/Messaging/MessagingBridgeGenerator.cs` | Covered |
| MessageChannelGenerator | `src/PatternKit.Generators/Messaging/MessageChannelGenerator.cs` | Covered |
| MessageEnvelopeGenerator | `src/PatternKit.Generators/Messaging/MessageEnvelopeGenerator.cs` | Covered |
| MessageFilterGenerator | `src/PatternKit.Generators/Messaging/MessageFilterGenerator.cs` | Covered |
| MessageStoreGenerator | `src/PatternKit.Generators/Messaging/MessageStoreGenerator.cs` | Covered |
| MessageEnvelopeGenerator | `src/PatternKit.Generators/Messaging/MessageEnvelopeGenerator.cs` | Covered |
| MessageFilterGenerator | `src/PatternKit.Generators/Messaging/MessageFilterGenerator.cs` | Covered |
| MessageHistoryGenerator | `src/PatternKit.Generators/Messaging/MessageHistoryGenerator.cs` | Covered |
| MessageStoreGenerator | `src/PatternKit.Generators/Messaging/MessageStoreGenerator.cs` | Covered |
| MessageTranslatorGenerator | `src/PatternKit.Generators/Messaging/MessageTranslatorGenerator.cs` | Covered |
| MessagingGatewayGenerator | `src/PatternKit.Generators/Messaging/MessagingGatewayGenerator.cs` | Covered |
| PipesAndFiltersPipelineGenerator | `src/PatternKit.Generators/Messaging/PipesAndFiltersPipelineGenerator.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 @@ -84,6 +84,8 @@ The following numbers were captured on Windows 11, Intel Core i9-14900K, .NET SD
| Dynamic Router | Execution | 406.7 ns | 2.83 KB | 415.2 ns | 2.83 KB | Same allocation; fluent was slightly faster for fulfillment route-table dispatch. |
| Messaging Bridge | Construction | 184.0 ns | 1,328 B | 185.5 ns | 1,328 B | Same allocation; fluent and generated bridge construction were effectively equivalent. |
| Messaging Bridge | Execution | 666.8 ns | 3,912 B | 670.8 ns | 3,912 B | Same allocation; fluent was slightly faster for partner order imports. |
| Message History | Construction | 6.843 ns | 56 B | 6.075 ns | 56 B | Same allocation; generated was slightly faster for history recorder construction. |
| Message History | Execution | 275.298 ns | 1,400 B | 285.765 ns | 1,400 B | Same allocation; fluent was slightly faster for order history recording. |
| Decorator | Construction | 34.293 ns | 264 B | 17.669 ns | 168 B | Generated decorator composition was faster and allocated less. |
| Decorator | Execution | 60.765 ns | 384 B | 35.551 ns | 304 B | Generated decorator execution was faster and allocated less for decorated storage reads. |
| Domain Event | Construction | 199.5 ns | 1.34 KB | 157.6 ns | 1.04 KB | Generated reduced construction time and allocation 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 @@ -63,6 +63,7 @@ The source of truth is `PatternKitPatternCatalog` in `src/PatternKit.Examples/Pr
| Enterprise Integration | Dynamic Router | `DynamicRouter<TPayload, TResult>` | Dynamic Router generator |
| Enterprise Integration | Message Bus | `MessageBus<TPayload>` | Message Bus generator |
| Enterprise Integration | Messaging Bridge | `MessagingBridge<TInbound,TOutbound>` | Messaging Bridge generator |
| Enterprise Integration | Message History | `MessageHistory<TPayload>` | Message History generator |
| Enterprise Integration | Message Filter | `MessageFilter<TPayload>` | Message Filter generator |
| Enterprise Integration | Message Store | `MessageStore<TPayload>` | Message Store generator |
| Enterprise Integration | Wire Tap | `WireTap<TPayload>` | Wire Tap generator |
Expand Down
18 changes: 18 additions & 0 deletions docs/patterns/messaging/message-history.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Message History

Message History records the components and operations that handled a message while preserving the original payload and metadata. Use it when production support, audit trails, or cross-system troubleshooting need to answer where a message has been.

PatternKit stores immutable `MessageHistoryEntry` values in a message header. Each recorder appends one hop:

```csharp
var received = MessageHistory<HistoryOrder>
.Create("checkout-api")
.Action("received")
.Details(message => message.Payload.Channel)
.Build();

var result = received.Record(message);
var history = MessageHistory<HistoryOrder>.Read(result);
```

Use Message History for observability that must travel with the message envelope. Use Wire Tap when the observation should be copied out-of-band, and use Audit Log when the record is a domain or compliance event rather than transport metadata.
2 changes: 2 additions & 0 deletions docs/patterns/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@
href: messaging/message-bus.md
- name: Messaging Bridge
href: messaging/messaging-bridge.md
- name: Message History
href: messaging/message-history.md
- name: Channel Adapter
href: messaging/channel-adapter.md
- name: Messaging Gateway
Expand Down
Loading
Loading