Skip to content

03 PLAN

Brian Lehnen edited this page Apr 8, 2026 · 1 revision

phase: 03-transports plan: "3" wave: 2 dependencies: ["1"] must_haves:

  • RedisTransport.md consumer code replaces Log.Log(DotNetWorkQueue.Logging.LogLevel...) with ILogger pattern
  • RedisTransport.md links to ConsumerMethod (not ConsumerLinq)
  • RedisTransport.md includes one-liner link to MessageHistory
  • RedisTransport.md links to samples repo
  • RedisOptions.md uses correct property path DelayedProcessingConfiguration.MonitorTime
  • RedisOptions.md documents ClearErrorMessagesBatchLimit and all other properties
  • RedisOptions.md documents SntpTimeConfiguration nested properties
  • RedisPoisonMessages.md consumer code uses QueueConnection and ConsumerQueueNotifications files_touched:
  • RedisTransport.md
  • RedisOptions.md
  • RedisPoisonMessages.md tdd: false

Plan 3 -- Redis Transport Family

Wave 2 -- Transport pages. Depends on Plan 1 (Transports overview). Can run in parallel with Plans 2, 4-7.


Task 1: Fix RedisTransport.md broken logging API and add cross-references

Update `RedisTransport.md` with these changes:
  1. Consumer HandleMessages method (line 62-64): Replace the broken logging API call. Change:

    private void HandleMessages(IReceivedMessage<SimpleMessage> m, IWorkerNotification n)
    {
        n.Log.Log(DotNetWorkQueue.Logging.LogLevel.Debug, () => $"Processing Message {m.Body.Message}");
    }

    to:

    private void HandleMessages(IReceivedMessage<SimpleMessage> message, IWorkerNotification notifications)
    {
        notifications.Log.LogDebug($"Processing Message {message.Body.Message}");
    }
  2. Feature list (lines 8-15): The list is correct but add "History tracking" to match source capabilities. All Redis features are always-on except History (opt-in). Updated list:

    • Priority
    • Status
    • HeartBeat
    • Delayed Processing
    • Status Table
    • Route
    • Message Expiration
    • History tracking (opt-in)
  3. Cross-references: Add after the consumer code sample:

    For more consumer patterns, see [ConsumerMethod](https://github.com/blehnen/DotNetWorkQueue/wiki/ConsumerMethod) and [ConsumerAsync](https://github.com/blehnen/DotNetWorkQueue/wiki/ConsumerAsync).
    
    If history tracking is enabled, see [MessageHistory](https://github.com/blehnen/DotNetWorkQueue/wiki/MessageHistory) for retention and query options.
  4. Samples link: Add at the bottom:

    ###### Full samples
    
    See the [Redis samples](https://github.com/blehnen/DotNetWorkQueue.Samples/tree/main/Source/Samples/Redis) in the DotNetWorkQueue.Samples repository.

Do NOT change: Producer code, queue name/connection string examples.

grep -i "DotNetWorkQueue.Logging.LogLevel|Log.Log(|ConsumerLinq" /mnt/f/git/dotnetworkqueue.wiki/RedisTransport.md; echo "exit: $?" grep returns no matches (exit code 1). RedisTransport.md uses notifications.Log.LogDebug(...) pattern. Links to ConsumerMethod, MessageHistory, and samples repo are present.

Task 2: Rewrite RedisOptions.md with correct property paths and full documentation

Replace the content of `RedisOptions.md` with complete documentation of `RedisQueueTransportOptions` and `RedisBaseTransportOptions`. The current page is mostly correct but needs the nested property path fixed and missing properties documented.

New content for RedisOptions.md:

#### Redis Options

**NuGet package:** `DotNetWorkQueue.Transport.Redis`

**Options class:** `RedisQueueTransportOptions`

**Namespace:** `DotNetWorkQueue.Transport.Redis.Basic`

##### Always-on features

Unlike the relational transports, Redis features are always enabled. There is no queue creation step required -- queues are created on demand.

| Feature | Value | Notes |
|---------|-------|-------|
| `EnablePriority` | always `true` | |
| `EnableStatus` | always `true` | |
| `EnableHeartBeat` | always `true` | |
| `EnableDelayedProcessing` | always `true` | |
| `EnableStatusTable` | always `true` | |
| `EnableRoute` | always `true` | |
| `EnableMessageExpiration` | always `true` | |
| `EnableHistory` | `false` (settable) | Opt-in history tracking |

When `EnableHistory` is set to `true`, the `HistoryOptions` property (type `HistoryTransportOptions`) controls retention. See [MessageHistory](https://github.com/blehnen/DotNetWorkQueue/wiki/MessageHistory) for the full list of history options.

##### Batch processing limits

These control how many items are processed per LUA script execution on the Redis server.

| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `ClearExpiredMessagesBatchLimit` | `int` | `50` | Expired messages removed per batch |
| `ClearErrorMessagesBatchLimit` | `int` | `50` | Error messages removed per batch |
| `MoveDelayedMessagesBatchLimit` | `int` | `50` | Delayed messages promoted per batch |
| `ResetHeartBeatBatchLimit` | `int` | `50` | Dead messages recovered per batch |

```csharp
queue.Configuration.Options().ClearExpiredMessagesBatchLimit = 10;
queue.Configuration.Options().ClearErrorMessagesBatchLimit = 10;
queue.Configuration.Options().MoveDelayedMessagesBatchLimit = 10;
queue.Configuration.Options().ResetHeartBeatBatchLimit = 10;
Delayed processing monitor

Controls how frequently the transport checks for delayed messages that are ready to process. Lower values reduce latency; higher values reduce Redis load.

queue.Configuration.Options().DelayedProcessingConfiguration.MonitorTime = TimeSpan.FromSeconds(1);

The default is TimeSpan.FromSeconds(1).

Time source

The Redis transport supports multiple ways to obtain the current time. All time-dependent operations (delayed processing, expiration, heartbeat) use the configured time source.

TimeServer value Description
TimeLocations.LocalMachine (default) Uses the local system clock. Only safe if all machines have synchronized clocks.
TimeLocations.RedisServer Uses the Redis server clock. In a cluster, all nodes should be time-synced.
TimeLocations.SntpServer Uses an NTP server. Slowest but safest when clock sync is not guaranteed.
TimeLocations.Custom User-supplied time provider.
queue.Configuration.Options().TimeServer = TimeLocations.SntpServer;
SNTP configuration

When TimeServer is set to SntpServer, these properties configure the NTP client:

Property Type Default
Server string "pool.ntp.org"
Port int 123
TimeOut TimeSpan 8 seconds
queue.Configuration.Options().SntpTimeConfiguration.Server = "time.google.com";
queue.Configuration.Options().SntpTimeConfiguration.Port = 123;
Message ID generation

Controls how message IDs are generated.

MessageIdLocation value Description
MessageIdLocations.RedisIncr (default) Uses Redis INCR for sequential IDs
MessageIdLocations.Uuid Uses client-generated UUIDs
MessageIdLocations.Custom User-supplied ID generator
queue.Configuration.Options().MessageIdLocation = MessageIdLocations.Uuid;

See also: RedisPoisonMessages for custom poison message handling.


Key changes from current:
- `DelayedProcessingMonitorTime` reference corrected to `DelayedProcessingConfiguration.MonitorTime`
- `ClearErrorMessagesBatchLimit` now documented
- `SntpTimeConfiguration` nested properties documented
- `MessageIdLocation` property added
- Always-on features table added
- `EnableHistory` and `HistoryOptions` documented
- Structured with clear sections and property tables
</action>
<verify>grep -c "DelayedProcessingConfiguration\.MonitorTime\|ClearErrorMessagesBatchLimit\|SntpTimeConfiguration\|MessageIdLocation\|EnableHistory" /mnt/f/git/dotnetworkqueue.wiki/RedisOptions.md</verify>
<done>grep returns 5 or more matches. RedisOptions.md documents the correct property path, all batch limits, SNTP config, MessageIdLocation, and EnableHistory.</done>
</task>

---

## Task 3: Update `RedisPoisonMessages.md` consumer code to use current API

<task id="3" files="RedisPoisonMessages.md" tdd="false">
<action>
Update `RedisPoisonMessages.md` with these changes:

1. **IoC injection code sample (lines 88-100):** The consumer creation call on line 93 uses the old 2-argument `CreateConsumer(queueName, connectionString)` pattern. Update to use `QueueConnection`:
   Change:
   ```csharp
   var queueName = "example";
   var connectionString = "127.0.0.1";
   using (var queueContainer = new QueueContainer<RedisQueueInit>(registerService => 
         registerService.Register<IReceivePoisonMessage, MoveMessageToFileSystem>(LifeStyles.Singleton)))
   {
       using (var queue = queueContainer.CreateConsumer(queueName, connectionString))
       {
           queue.Start<SimpleMessage>(HandleMessages);
   ```
   to:
   ```csharp
   var queueName = "example";
   var connectionString = "127.0.0.1";
   var queueConnection = new QueueConnection(queueName, connectionString);
   using (var queueContainer = new QueueContainer<RedisQueueInit>(registerService => 
         registerService.Register<IReceivePoisonMessage, MoveMessageToFileSystem>(LifeStyles.Singleton)))
   {
       using (var queue = queueContainer.CreateConsumer(queueConnection))
       {
           var notifications = new ConsumerQueueNotifications(
               (n) => Console.WriteLine($"Error: {n.Error}"),
               (n) => Console.WriteLine($"Receive error: {n.Error}"),
               (n) => Console.WriteLine($"Moved to error queue: {n.MessageId}"),
               (n) => Console.WriteLine($"Poison message: {n.MessageId}"),
               (n) => Console.WriteLine($"Rollback: {n.MessageId}"),
               (n) => Console.WriteLine($"Completed: {n.MessageId}"));
           queue.Start<SimpleMessage>(HandleMessages, notifications);
   ```

2. **Typos:** Fix "messges" to "messages", "implemenations" to "implementations", "belive" to "believe", "posion" to "poison" in the prose text.

**Do NOT change:** The `MoveMessageToFileSystem` class implementation, the `IReceivePoisonMessage` interface, or the file system handling code. These remain valid.
</action>
<verify>grep -c "QueueConnection\|ConsumerQueueNotifications" /mnt/f/git/dotnetworkqueue.wiki/RedisPoisonMessages.md</verify>
<done>grep returns 2 or more matches. RedisPoisonMessages.md uses QueueConnection constructor and includes ConsumerQueueNotifications. Typos are fixed.</done>
</task>

Clone this wiki locally