Skip to content

Commit 976cb5a

Browse files
authored
Merge pull request #41 from tgiachi/develop
docs: phase 3 - provider README depth and Related cross-links
2 parents 568d995 + b44333b commit 976cb5a

11 files changed

Lines changed: 495 additions & 71 deletions

File tree

src/SquidStd.Aws.Abstractions/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ client at that endpoint instead of the regional AWS endpoint.
3333
|------------------|-----------------------------------------------------------------------------------|
3434
| `AwsConfigEntry` | Region, optional credentials and an optional endpoint override (e.g. LocalStack). |
3535

36+
## Related
37+
38+
- Article: [AWS abstractions](https://tgiachi.github.io/squid-std/articles/aws-abstractions.html)
39+
- [`SquidStd.Secrets.Aws`](https://tgiachi.github.io/squid-std/articles/secrets-aws.html) - AWS Secrets Manager provider using this config
40+
- [`SquidStd.Messaging.Sqs`](https://tgiachi.github.io/squid-std/articles/messaging-sqs.html) - SQS messaging provider using this config
41+
- [`SquidStd.Storage.S3`](https://tgiachi.github.io/squid-std/articles/storage-s3.html) - S3 storage provider using this config
42+
3643
## License
3744

3845
MIT - part of [SquidStd](https://github.com/tgiachi/squid-std).

src/SquidStd.Caching/README.md

Lines changed: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
<h1 align="center">SquidStd.Caching</h1>
22

3-
In-memory backend for SquidStd.Caching. Provides an `IMemoryCache`-backed `ICacheProvider` with
4-
absolute TTL and eviction, wired to the shared typed `ICacheService` facade - registered with a
5-
single `AddInMemoryCache()` call. Ideal for single-process apps, tests, and local dev.
3+
In-memory backend for SquidStd.Caching. Provides an `IMemoryCache`-backed `ICacheProvider` with absolute
4+
TTL and eviction, wired to the shared typed `ICacheService` facade - registered with a single
5+
`AddInMemoryCache()` call.
6+
7+
The contract lives in `SquidStd.Caching.Abstractions`, so code written against `ICacheService` moves
8+
unchanged to a distributed cache: use this in-memory provider for single-process apps, tests, and local
9+
dev, then swap in `SquidStd.Caching.Redis` for production. Values are serialized as JSON in both cases,
10+
so cached shapes behave the same across providers.
611

712
## Install
813

@@ -12,29 +17,87 @@ dotnet add package SquidStd.Caching
1217

1318
## Usage
1419

20+
Register through the bootstrap - the provider is an `ISquidStdService`, so `StartAsync` / `StopAsync`
21+
manage its lifecycle for you:
22+
1523
```csharp
16-
using DryIoc;
1724
using SquidStd.Caching.Abstractions.Interfaces;
1825
using SquidStd.Caching.Extensions;
26+
using SquidStd.Services.Core.Extensions;
27+
using SquidStd.Services.Core.Services.Bootstrap;
28+
29+
var bootstrap = SquidStdBootstrap.Create(o => o.ConfigName = "myapp");
30+
bootstrap.ConfigureServices(c => c.RegisterCoreServices().AddInMemoryCache());
31+
await bootstrap.StartAsync();
32+
```
33+
34+
### Get / set with TTL
35+
36+
```csharp
37+
var cache = bootstrap.Resolve<ICacheService>();
38+
39+
await cache.SetAsync("greeting", "hello", TimeSpan.FromMinutes(5));
40+
var value = await cache.GetAsync<string>("greeting"); // "hello", or default on a miss
41+
42+
var exists = await cache.ExistsAsync("greeting"); // true
43+
var removed = await cache.RemoveAsync("greeting"); // true if the key existed
44+
```
45+
46+
Omitting the TTL on `SetAsync` falls back to `CacheOptions.DefaultTtl` (no expiry when that is `null`).
1947

20-
var container = new Container();
21-
container.AddInMemoryCache("memory://localhost?defaultTtlSeconds=300&keyPrefix=app:");
48+
### Cache-aside with `GetOrSetAsync`
2249

23-
var cache = container.Resolve<ICacheService>();
24-
await cache.SetAsync("user:1", new { Name = "squid" });
25-
var user = await cache.GetAsync<object>("user:1");
50+
`GetOrSetAsync` returns the cached value, or runs the factory, stores the result, and returns it on a
51+
miss - the standard cache-aside pattern in one call:
52+
53+
```csharp
54+
public sealed record UserProfile(string Id, string Name);
55+
56+
var profile = await cache.GetOrSetAsync(
57+
$"user:{id}",
58+
async ct => await LoadProfileFromDatabaseAsync(id, ct),
59+
TimeSpan.FromMinutes(10)
60+
);
2661
```
2762

63+
## Configuration
64+
65+
`AddInMemoryCache` takes an optional `CacheOptions`. Options are code-only - this package registers no
66+
YAML config section.
67+
68+
```csharp
69+
c.AddInMemoryCache(new CacheOptions
70+
{
71+
DefaultTtl = TimeSpan.FromMinutes(5),
72+
KeyPrefix = "app:"
73+
});
74+
```
75+
76+
| Property | Default | Purpose |
77+
|--------------|----------------|------------------------------------------------------------------|
78+
| `DefaultTtl` | `null` | TTL applied when a set call passes none; `null` means no expiry. |
79+
| `KeyPrefix` | `string.Empty` | Prefix prepended to every key. |
80+
81+
A connection-string overload is also available:
82+
`AddInMemoryCache("memory://local?defaultTtlSeconds=300&keyPrefix=app:")`.
83+
84+
`CacheMetricsProvider` is registered as `ICacheMetrics` / `IMetricProvider` and exposes aggregate hit,
85+
miss, set, and remove counters plus the hit ratio to the metrics collection system.
86+
2887
## Key types
2988

30-
| Type | Purpose |
31-
|-------------------------------|-----------------------------------------|
32-
| `CacheRegistrationExtensions` | `AddInMemoryCache(...)` registration. |
33-
| `InMemoryCacheProvider` | `IMemoryCache`-backed `ICacheProvider`. |
89+
| Type | Purpose |
90+
|-------------------------------|------------------------------------------------------------|
91+
| `CacheRegistrationExtensions` | `AddInMemoryCache(...)` registration. |
92+
| `InMemoryCacheProvider` | `IMemoryCache`-backed `ICacheProvider`. |
93+
| `ICacheService` | Typed facade from `SquidStd.Caching.Abstractions`: get/set/TTL, `GetOrSetAsync`, exists/remove. |
94+
| `CacheOptions` | Default TTL and key prefix configuration. |
3495

3596
## Related
3697

98+
- Article: [Caching](https://tgiachi.github.io/squid-std/articles/caching.html)
3799
- Tutorial: [Caching](https://tgiachi.github.io/squid-std/tutorials/caching.html)
100+
- Production backend: [SquidStd.Caching.Redis](https://tgiachi.github.io/squid-std/articles/caching-redis.html)
38101

39102
## License
40103

src/SquidStd.Messaging.RabbitMq/README.md

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
<h1 align="center">SquidStd.Messaging.RabbitMq</h1>
22

3-
RabbitMQ transport for SquidStd.Messaging. Implements `IQueueProvider` on top of the RabbitMQ client,
4-
so the same `IMessageQueue` API publishes to and consumes from a real broker. Registered with a single
3+
RabbitMQ transport for SquidStd.Messaging. Implements `IQueueProvider` and `ITopicProvider` on top of the
4+
RabbitMQ client, so the same `IMessageQueue` / `IMessageTopic` API that runs in-memory during tests
5+
publishes to and consumes from a real broker in production - registered with a single
56
`AddRabbitMqMessaging(...)` call.
67

8+
The provider declares durable **quorum queues** and publishes persistent messages, so queued work survives
9+
broker restarts. Each queue gets a companion dead-letter queue (`<queue>.dlq` by default), wired via
10+
`x-delivery-limit` so the broker itself moves a message there after `MaxDeliveryAttempts` failed
11+
deliveries. Connections are created with automatic recovery enabled, and consumers apply the configured
12+
prefetch via basic QoS. Topics map to fan-out exchanges with an exclusive, auto-delete queue per
13+
subscriber - topic delivery is live fan-out, not durable.
14+
715
## Install
816

917
```bash
@@ -12,29 +20,84 @@ dotnet add package SquidStd.Messaging.RabbitMq
1220

1321
## Usage
1422

23+
Register through the bootstrap - the providers are `ISquidStdService`s, so `bootstrap.StartAsync()` opens
24+
the broker connection and `StopAsync` closes it:
25+
1526
```csharp
16-
using DryIoc;
1727
using SquidStd.Messaging.Abstractions.Interfaces;
28+
using SquidStd.Messaging.RabbitMq.Data.Config;
1829
using SquidStd.Messaging.RabbitMq.Extensions;
30+
using SquidStd.Services.Core.Extensions;
31+
using SquidStd.Services.Core.Services.Bootstrap;
32+
33+
var bootstrap = SquidStdBootstrap.Create(o => o.ConfigName = "myapp");
34+
35+
bootstrap.ConfigureServices(c => c.RegisterCoreServices().AddRabbitMqMessaging(new RabbitMqOptions
36+
{
37+
HostName = "rabbit.internal",
38+
UserName = "app",
39+
Password = "secret"
40+
}));
41+
42+
await bootstrap.StartAsync();
43+
```
44+
45+
Publishing and consuming are identical to the in-memory provider - the contracts come from
46+
`SquidStd.Messaging.Abstractions`:
1947

20-
var container = new Container();
21-
container.AddRabbitMqMessaging("rabbitmq://guest:guest@localhost:5672/");
48+
```csharp
49+
var queue = bootstrap.Resolve<IMessageQueue>();
50+
51+
using (queue.Subscribe("orders", new OrderListener())) // IQueueMessageListenerAsync<OrderPlaced>
52+
{
53+
await queue.PublishAsync("orders", new OrderPlaced("order-1"));
54+
}
2255

23-
var queue = container.Resolve<IMessageQueue>();
24-
await queue.PublishAsync("orders", new { Id = 1 });
56+
var topic = bootstrap.Resolve<IMessageTopic>();
57+
using var sub = topic.Subscribe<OrderPlaced>("order-events", (order, _) =>
58+
{
59+
Console.WriteLine($"topic saw {order.Id}");
60+
return Task.CompletedTask;
61+
});
2562
```
2663

64+
## Configuration
65+
66+
`AddRabbitMqMessaging(RabbitMqOptions options, MessagingOptions? messagingOptions = null)` takes the
67+
connection settings plus the shared messaging options (delivery attempts, dead-letter suffix). Options are
68+
code-only - this package registers no YAML config section.
69+
70+
| `RabbitMqOptions` property | Default | Purpose |
71+
|----------------------------|---------------|-----------------------------------------------------|
72+
| `HostName` | `"localhost"` | Broker host. |
73+
| `Port` | `5672` | Broker port. |
74+
| `VirtualHost` | `"/"` | Virtual host. |
75+
| `UserName` | `"guest"` | User name. |
76+
| `Password` | `"guest"` | Password. |
77+
| `Uri` | `null` | AMQP URI; when set it overrides the fields above. |
78+
| `PrefetchCount` | `10` | Consumer prefetch (basic QoS) per subscriber. |
79+
80+
A connection-string overload is also available:
81+
`AddRabbitMqMessaging("rabbitmq://app:secret@rabbit.internal:5672/myvhost?prefetch=20&maxDeliveryAttempts=5")`.
82+
83+
`MessagingMetricsProvider` is registered as `IMessagingMetrics` / `IMetricProvider`; the provider reports
84+
published, delivered, and failed counts plus subscriber counts per queue.
85+
2786
## Key types
2887

29-
| Type | Purpose |
30-
|-------------------------------------------|-------------------------------------------|
31-
| `RabbitMqMessagingRegistrationExtensions` | `AddRabbitMqMessaging(...)` registration. |
32-
| `RabbitMqQueueProvider` | RabbitMQ-backed `IQueueProvider`. |
33-
| `RabbitMqOptions` | Connection + prefetch configuration. |
88+
| Type | Purpose |
89+
|-------------------------------------------|----------------------------------------------------------|
90+
| `RabbitMqMessagingRegistrationExtensions` | `AddRabbitMqMessaging(...)` registration. |
91+
| `RabbitMqQueueProvider` | Quorum-queue `IQueueProvider` with broker-side DLQ. |
92+
| `RabbitMqTopicProvider` | Fan-out exchange `ITopicProvider`. |
93+
| `RabbitMqOptions` | Connection + prefetch configuration. |
3494

3595
## Related
3696

97+
- Article: [Messaging with RabbitMQ](https://tgiachi.github.io/squid-std/articles/messaging-rabbitmq.html)
98+
- Article: [Messaging](https://tgiachi.github.io/squid-std/articles/messaging.html)
3799
- Tutorial: [Messaging](https://tgiachi.github.io/squid-std/tutorials/messaging.html)
100+
- Siblings: [SquidStd.Messaging (in-memory)](https://tgiachi.github.io/squid-std/articles/messaging.html), [SquidStd.Messaging.Sqs](https://tgiachi.github.io/squid-std/articles/messaging-sqs.html)
38101

39102
## License
40103

src/SquidStd.Messaging/README.md

Lines changed: 99 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
<h1 align="center">SquidStd.Messaging</h1>
22

3-
In-memory transport for SquidStd.Messaging. Provides a channel-backed `IQueueProvider` with per-queue
4-
buffering, round-robin delivery to subscribers, retry/dead-letter handling, and metrics - registered
5-
with a single `AddInMemoryMessaging()` call. Ideal for single-process apps, tests, and local dev.
3+
In-memory transport for SquidStd.Messaging. Provides channel-backed `IQueueProvider` and `ITopicProvider`
4+
implementations behind the shared `IMessageQueue` / `IMessageTopic` facades: per-queue buffering,
5+
round-robin (competing-consumers) delivery, retry and dead-letter handling, topic fan-out, and metrics -
6+
all registered with a single `AddInMemoryMessaging()` call.
7+
8+
Queues deliver each message to exactly one subscriber; topics fan every message out to all subscribers.
9+
The contracts live in `SquidStd.Messaging.Abstractions`, so code written against `IMessageQueue` and
10+
`IMessageTopic` moves unchanged to a real broker: use this in-memory provider for single-process apps,
11+
tests, and local dev, then swap in `SquidStd.Messaging.RabbitMq` or `SquidStd.Messaging.Sqs` for
12+
production.
613

714
## Install
815

@@ -12,28 +19,108 @@ dotnet add package SquidStd.Messaging
1219

1320
## Usage
1421

22+
Register through the bootstrap - the providers are `ISquidStdService`s, so `StartAsync` / `StopAsync`
23+
manage their lifecycle for you:
24+
1525
```csharp
16-
using DryIoc;
1726
using SquidStd.Messaging.Abstractions.Interfaces;
1827
using SquidStd.Messaging.Extensions;
28+
using SquidStd.Services.Core.Extensions;
29+
using SquidStd.Services.Core.Services.Bootstrap;
30+
31+
var bootstrap = SquidStdBootstrap.Create(o => o.ConfigName = "myapp");
32+
bootstrap.ConfigureServices(c => c.RegisterCoreServices().AddInMemoryMessaging());
33+
await bootstrap.StartAsync();
34+
```
35+
36+
### Queues (competing consumers)
37+
38+
Each queue message goes to exactly one subscriber. Implement a listener and subscribe it; dispose the
39+
subscription to unsubscribe.
40+
41+
```csharp
42+
public sealed record OrderPlaced(string Id);
43+
44+
public sealed class OrderListener : IQueueMessageListenerAsync<OrderPlaced>
45+
{
46+
public Task HandleAsync(OrderPlaced message, CancellationToken cancellationToken)
47+
{
48+
Console.WriteLine($"queue handled {message.Id}");
49+
return Task.CompletedTask;
50+
}
51+
}
52+
53+
var queue = bootstrap.Resolve<IMessageQueue>();
54+
55+
using (queue.Subscribe("orders", new OrderListener()))
56+
{
57+
await queue.PublishAsync("orders", new OrderPlaced("order-1"));
58+
}
59+
```
1960

20-
var container = new Container();
21-
container.AddInMemoryMessaging();
61+
A synchronous `IQueueMessageListener<TMessage>` overload of `Subscribe` is also available.
2262

23-
var queue = container.Resolve<IMessageQueue>();
24-
await queue.PublishAsync("orders", new { Id = 1 });
63+
### Topics (fan-out)
64+
65+
Every subscriber receives every message published to the topic.
66+
67+
```csharp
68+
var topic = bootstrap.Resolve<IMessageTopic>();
69+
70+
using (topic.Subscribe<OrderPlaced>("order-events", (order, _) =>
71+
{
72+
Console.WriteLine($"topic saw {order.Id}");
73+
return Task.CompletedTask;
74+
}))
75+
{
76+
await topic.PublishAsync("order-events", new OrderPlaced("order-2"));
77+
}
78+
```
79+
80+
## Configuration
81+
82+
`AddInMemoryMessaging` takes an optional `MessagingOptions`. Options are code-only - this package
83+
registers no YAML config section.
84+
85+
```csharp
86+
c.AddInMemoryMessaging(new MessagingOptions
87+
{
88+
MaxDeliveryAttempts = 5,
89+
DeadLetterQueueSuffix = ".dead",
90+
RetryDelay = TimeSpan.FromMilliseconds(250)
91+
});
2592
```
2693

94+
| Property | Default | Purpose |
95+
|-------------------------|---------|-------------------------------------------------------------|
96+
| `MaxDeliveryAttempts` | `3` | Delivery attempts before a message is dead-lettered. |
97+
| `DeadLetterQueueSuffix` | `".dlq"`| Suffix appended to a queue name to form its dead-letter queue. |
98+
| `RetryDelay` | `Zero` | Delay before a failed message is re-enqueued. |
99+
100+
A connection-string overload is also available:
101+
`AddInMemoryMessaging("memory://local?maxDeliveryAttempts=5&retryDelayMs=250&deadLetterSuffix=.dead")`.
102+
103+
When a listener throws, the message is re-enqueued (after `RetryDelay`) until `MaxDeliveryAttempts` is
104+
reached, then moved to `<queue><DeadLetterQueueSuffix>` - subscribe to that queue to inspect failures.
105+
`MessagingMetricsProvider` is registered as `IMessagingMetrics` / `IMetricProvider` and tracks published,
106+
delivered, retried, failed, and dead-lettered counts per queue.
107+
27108
## Key types
28109

29-
| Type | Purpose |
30-
|-----------------------------------|-------------------------------------------|
31-
| `MessagingRegistrationExtensions` | `AddInMemoryMessaging(...)` registration. |
32-
| `InMemoryQueueProvider` | Channel-based in-memory `IQueueProvider`. |
110+
| Type | Purpose |
111+
|-----------------------------------|------------------------------------------------------------|
112+
| `MessagingRegistrationExtensions` | `AddInMemoryMessaging(...)` registration. |
113+
| `InMemoryQueueProvider` | Channel-based in-memory `IQueueProvider` with retry/DLQ. |
114+
| `InMemoryTopicProvider` | In-memory `ITopicProvider` (fan-out). |
115+
| `IMessageQueue` / `IMessageTopic` | Typed facades from `SquidStd.Messaging.Abstractions`. |
116+
| `MessagingOptions` | Retry, dead-letter, and delivery-attempt configuration. |
33117

34118
## Related
35119

120+
- Article: [Messaging](https://tgiachi.github.io/squid-std/articles/messaging.html)
121+
- Article: [Messaging abstractions](https://tgiachi.github.io/squid-std/articles/messaging-abstractions.html)
36122
- Tutorial: [Messaging](https://tgiachi.github.io/squid-std/tutorials/messaging.html)
123+
- Production transports: [SquidStd.Messaging.RabbitMq](https://tgiachi.github.io/squid-std/articles/messaging-rabbitmq.html), [SquidStd.Messaging.Sqs](https://tgiachi.github.io/squid-std/articles/messaging-sqs.html)
37124

38125
## License
39126

src/SquidStd.Persistence.Abstractions/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ dotnet add package SquidStd.Persistence.Abstractions
2323
| `JournalEntityOperationType` | `Upsert` / `Remove` journal operation discriminator. |
2424
| `SnapshotSaveStartedEvent` / `SnapshotSaveCompletedEvent` | Snapshot lifecycle events (`IEvent`). |
2525

26+
## Related
27+
28+
- Article: [Persistence abstractions](https://tgiachi.github.io/squid-std/articles/persistence-abstractions.html)
29+
- Tutorial: [Persistence](https://tgiachi.github.io/squid-std/tutorials/persistence.html)
30+
- [`SquidStd.Persistence`](https://tgiachi.github.io/squid-std/articles/persistence.html) - the binary persistence engine implementing these contracts
31+
- [`SquidStd.Persistence.MessagePack`](https://tgiachi.github.io/squid-std/articles/persistence-messagepack.html) - MessagePack entity descriptors for the engine
32+
2633
## License
2734

2835
MIT - part of [SquidStd](https://github.com/tgiachi/squid-std).

0 commit comments

Comments
 (0)