Skip to content

Commit 36f915e

Browse files
committed
Add llms.txt for AI indexing and Claude Code plugin
llms.txt: - Follows llmstxt.org specification for AI assistant documentation - Links to all doc pages as raw GitHub URLs for direct AI consumption - Enables Context7 and other AI indexing services to find accurate, up-to-date API documentation Claude Code plugin (claude-plugin/): - plugin.json with metadata for marketplace publishing - skills/configure — generate RedisConfiguration and DI setup from natural language (serializer/compressor selection guide included) - skills/scaffold — production-ready code patterns: cache-aside, consumer groups, geo search, VectorSet RAG, hash field TTL, Pub/Sub - skills/diagnose — troubleshooting tree for timeouts, connection failures, serialization errors, pool exhaustion, Pub/Sub issues README.md: - Added "AI-Ready" callout with links to llms.txt and plugin Closes #629 Closes #630
1 parent d4cd6ca commit 36f915e

File tree

6 files changed

+448
-0
lines changed

6 files changed

+448
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
![Tests](https://img.shields.io/badge/tests-970%2B%20passing-brightgreen)
99
![.NET](https://img.shields.io/badge/.NET-8%20%7C%209%20%7C%2010-blue)
1010

11+
> **AI-Ready:** This library provides an [`llms.txt`](llms.txt) file for AI coding assistants and a [Claude Code plugin](claude-plugin/) for configuration, scaffolding, and troubleshooting.
12+
1113
## Features
1214

1315
- Store and retrieve complex .NET objects with automatic serialization

claude-plugin/plugin.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "stackexchange-redis-extensions",
3+
"version": "1.0.0",
4+
"description": "Configure, scaffold, and troubleshoot StackExchange.Redis.Extensions — the high-level .NET Redis client with serialization, pooling, Streams, Geo, VectorSet, compression, and more.",
5+
"author": "imperugo",
6+
"homepage": "https://github.com/imperugo/StackExchange.Redis.Extensions",
7+
"skills": [
8+
"skills/configure",
9+
"skills/scaffold",
10+
"skills/diagnose"
11+
]
12+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
---
2+
name: redis-configure
3+
description: Generate StackExchange.Redis.Extensions configuration and DI registration from natural language requirements
4+
---
5+
6+
# Redis Configure
7+
8+
Generate complete `RedisConfiguration` and ASP.NET Core DI setup for StackExchange.Redis.Extensions based on the user's requirements.
9+
10+
## When to use
11+
12+
When the user asks to:
13+
- Set up Redis in their .NET project
14+
- Configure connection pooling, Sentinel, TLS, Azure Managed Identity
15+
- Choose a serializer or compressor
16+
- Set up multiple Redis instances
17+
18+
## How to respond
19+
20+
1. Ask clarifying questions if needed (single vs. multi-instance, cloud vs. local, auth method)
21+
2. Generate the complete configuration
22+
23+
## Configuration Reference
24+
25+
### NuGet packages required
26+
- `StackExchange.Redis.Extensions.Core` — always required
27+
- `StackExchange.Redis.Extensions.AspNetCore` — for DI registration
28+
- One serializer: `System.Text.Json` (recommended), `Newtonsoft`, `MemoryPack`, `MsgPack`, `Protobuf`
29+
- Optional compressor: `Compression.LZ4` (fastest), `Compression.ZstdSharp` (best ratio), `Compression.GZip` (no deps)
30+
31+
### appsettings.json structure
32+
```json
33+
{
34+
"Redis": {
35+
"Password": "",
36+
"AllowAdmin": true,
37+
"Ssl": false,
38+
"ConnectTimeout": 5000,
39+
"SyncTimeout": 5000,
40+
"Database": 0,
41+
"Hosts": [{ "Host": "localhost", "Port": 6379 }],
42+
"PoolSize": 5,
43+
"IsDefault": true
44+
}
45+
}
46+
```
47+
48+
### Program.cs registration
49+
```csharp
50+
var redisConfig = builder.Configuration.GetSection("Redis").Get<RedisConfiguration>();
51+
builder.Services.AddStackExchangeRedisExtensions<SystemTextJsonSerializer>(redisConfig);
52+
// Optional compression:
53+
builder.Services.AddRedisCompression<LZ4Compressor>();
54+
```
55+
56+
### Azure Managed Identity
57+
```csharp
58+
redisConfig.ConfigurationOptionsAsyncHandler = async opts =>
59+
{
60+
await opts.ConfigureForAzureWithTokenCredentialAsync(new DefaultAzureCredential());
61+
return opts;
62+
};
63+
```
64+
65+
### Sentinel configuration
66+
```csharp
67+
var config = new RedisConfiguration
68+
{
69+
ServiceName = "mymaster",
70+
Hosts = new[] {
71+
new RedisHost { Host = "sentinel1", Port = 26379 },
72+
new RedisHost { Host = "sentinel2", Port = 26379 },
73+
},
74+
IsDefault = true,
75+
};
76+
```
77+
78+
### Multiple instances
79+
```csharp
80+
var configs = new[]
81+
{
82+
new RedisConfiguration { Name = "Cache", IsDefault = true, /* ... */ },
83+
new RedisConfiguration { Name = "Session", /* ... */ },
84+
};
85+
builder.Services.AddStackExchangeRedisExtensions<SystemTextJsonSerializer>(configs);
86+
87+
// Resolve: inject IRedisClientFactory, call GetRedisClient("Session")
88+
```
89+
90+
### Key properties
91+
| Property | Default | Description |
92+
|----------|---------|-------------|
93+
| PoolSize | 5 | Connection pool size |
94+
| ConnectionSelectionStrategy | LeastLoaded | LeastLoaded or RoundRobin |
95+
| SyncTimeout | 5000 | Sync timeout (ms) |
96+
| ConnectTimeout | 5000 | Connect timeout (ms) |
97+
| KeyPrefix | "" | Prefix for all keys and channels |
98+
| KeepAlive | -1 | Heartbeat interval (seconds) |
99+
| ClientName | null | Connection client name |
100+
| MaxValueLength | 0 | Max serialized value size (0 = unlimited) |
101+
102+
### Serializer selection guide
103+
| Scenario | Recommended |
104+
|----------|-------------|
105+
| General purpose | System.Text.Json |
106+
| Legacy JSON.NET compatibility | Newtonsoft |
107+
| Maximum performance (binary) | MemoryPack (net7.0+) |
108+
| Cross-language compatibility | Protobuf or MsgPack |
109+
110+
### Compressor selection guide
111+
| Scenario | Recommended |
112+
|----------|-------------|
113+
| Lowest latency (caching) | LZ4 |
114+
| Best compression ratio | ZstdSharp or Brotli |
115+
| No external dependencies | GZip |
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
---
2+
name: redis-diagnose
3+
description: Troubleshoot common StackExchange.Redis.Extensions issues — timeouts, connection failures, serialization problems, pool exhaustion
4+
---
5+
6+
# Redis Diagnose
7+
8+
Diagnose and fix common issues with StackExchange.Redis.Extensions.
9+
10+
## When to use
11+
12+
When the user reports:
13+
- Timeout exceptions
14+
- Connection failures
15+
- Serialization errors
16+
- Pool exhaustion
17+
- Pub/Sub messages not being received
18+
- Performance issues
19+
20+
## Diagnostic Tree
21+
22+
### RedisTimeoutException
23+
**Symptoms:** `StackExchange.Redis.RedisTimeoutException`
24+
25+
**Check in order:**
26+
1. **SyncTimeout too low** — default is 5000ms, increase for slow networks
27+
```csharp
28+
config.SyncTimeout = 10000; // 10 seconds
29+
```
30+
2. **Pool size too small** — default 5, increase for high-throughput
31+
```csharp
32+
config.PoolSize = 10;
33+
```
34+
3. **Connection strategy** — switch to LeastLoaded if using RoundRobin
35+
```csharp
36+
config.ConnectionSelectionStrategy = ConnectionSelectionStrategy.LeastLoaded;
37+
```
38+
4. **Large values** — enable compression to reduce payload size
39+
```csharp
40+
services.AddRedisCompression<LZ4Compressor>();
41+
```
42+
5. **ThreadPool starvation** — check with `ThreadPool.GetAvailableThreads()`, increase min threads
43+
44+
### RedisConnectionException
45+
**Symptoms:** `SocketClosed`, `ConnectionFailed`
46+
47+
**Check:**
48+
1. **Redis server reachable?**`redis-cli -h <host> -p <port> ping`
49+
2. **Firewall/NSG rules** — port 6379 (or 6380 for TLS) open?
50+
3. **TLS misconfiguration** — if using Ssl=true, check certificate callbacks
51+
4. **Sentinel misconfiguration** — ServiceName must match Redis master name exactly
52+
5. **Azure Cache for Redis** — ensure Managed Identity is configured if not using password
53+
54+
### Serialization Errors
55+
**Symptoms:** `JsonException`, `InvalidOperationException`, corrupt data
56+
57+
**Check:**
58+
1. **Type mismatch** — GetAsync<T> must use same T as AddAsync<T>
59+
2. **String values are JSON-encoded** — "hello" is stored as "\"hello\"", this is by design
60+
3. **Compression migration** — enabling compression makes old (uncompressed) data unreadable
61+
- Error: `InvalidOperationException: Failed to decompress data from Redis`
62+
- Fix: flush the database or read old data without compression first
63+
4. **Value type quirk**`GetAsync<int>()` returns 0 (not null) for missing keys. Use `GetAsync<int?>()` instead.
64+
65+
### Pub/Sub Not Receiving Messages
66+
**Check:**
67+
1. **KeyPrefix** — channels are automatically prefixed. Don't add prefix manually.
68+
2. **Serializer mismatch** — publisher and subscriber must use the same serializer
69+
3. **Handler exceptions** — check logs for EventId 4001 errors. Handlers that throw don't crash but the message is lost.
70+
4. **Different connection pools** — ensure pub and sub use the same IRedisDatabase instance
71+
72+
### Pool Exhaustion / All Connections Down
73+
**Symptoms:** All operations fail, logs show EventId 1003
74+
75+
**Check:**
76+
1. **Pool health**`redis.ConnectionPoolManager.GetConnectionInformation()`
77+
2. **Redis server overloaded** — check `INFO clients` on Redis
78+
3. **Network partition** — the pool skips disconnected connections automatically and logs warnings
79+
4. **Dispose pattern** — ensure IRedisConnectionPoolManager is not disposed prematurely
80+
81+
### Performance Issues
82+
**Check:**
83+
1. **Enable logging** — set log level to Debug to see connection selection
84+
```json
85+
{ "Logging": { "LogLevel": { "StackExchange.Redis.Extensions.Core": "Debug" } } }
86+
```
87+
2. **Check outstanding commands** — pool info shows outstanding count per connection
88+
3. **Use compression** for large objects — LZ4 adds ~1ms latency but reduces network 5-10x
89+
4. **Use AddAllAsync** for bulk writes instead of loop of AddAsync
90+
5. **Use GetAllAsync** with HashSet<string> for bulk reads
91+
92+
## Logging Reference
93+
94+
| EventId | Level | Meaning |
95+
|---------|-------|---------|
96+
| 1001 | Info | Pool initialized successfully |
97+
| 1003 | Warning | All connections disconnected — degraded mode |
98+
| 1006 | Error | Pool initialization failed |
99+
| 2001 | Error | Connection failed |
100+
| 2002 | Warning | Connection restored |
101+
| 4001 | Error | Pub/Sub handler threw exception |
102+
103+
Enable with:
104+
```json
105+
{ "Logging": { "LogLevel": { "StackExchange.Redis.Extensions.Core": "Information" } } }
106+
```

0 commit comments

Comments
 (0)