Skip to content

RESEARCH

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

Research: Phase 2 — Core Usage Pages API Verification

Date: 2026-04-08 Source version: DotNetWorkQueue 0.9.30 Source repo: /mnt/f/git/DotNetWorkQueue/Source/DotNetWorkQueue/ Samples repo: /mnt/f/git/DotNetWorkQueue.Samples/Source/Samples/


Summary of Key Findings

  1. ConsumerQueueNotifications is a required parameter on all Start() overloads — the wiki was missing it.
  2. The old DotNetWorkQueue.Logging.LogLevel / notifications.Log.Log() API is completely gone. Logging is now Microsoft.Extensions.Logging.ILogger accessed via IWorkerNotification.Log, used with standard MEL extension methods (LogInformation, LogError, etc.).
  3. AbortWorkerThreadsWhenStopping does NOT exist anywhere in IWorkerConfiguration or any current source file.
  4. WaitForTheadPoolToFinish (single 't' typo) does NOT exist. The correct spelling is WaitForThreadPoolToFinish (double 't') on ITaskSchedulerConfiguration.
  5. AddWorkGroup(string name, int concurrencyLevel) takes exactly two parameters, not three. Any third parameter documented in the wiki does not exist.
  6. Dynamic LINQ (LinqExpressionToRun) is guarded by #if net48 — it is dead code in net8.0/net10.0 builds.
  7. Target frameworks are net10.0 and net8.0 only — no net48, no netstandard2.0.
  8. CreateConsumer() takes a single QueueConnection parameter; there is no overload accepting notifications.
  9. The method consumer API is CreateConsumerMethodQueueScheduler() / CreateMethodConsumer() — not CreateConsumerLinq*.
  10. The scheduler sample still uses Schyntax expressions (sec(0,5,10,...)) — this is stale and should be replaced with Cronos cron syntax in Phase 4.

Per-Page Findings


1. Consumer.md

Question: What is the correct consumer creation and Start() signature?

Source: IConsumerQueue.cs, QueueContainer.cs

Creation:

// QueueContainer.cs line 80
public IConsumerQueue CreateConsumer(QueueConnection queueConnection)
  • Single parameter: QueueConnection (queue name + connection string).
  • No ConsumerQueueNotifications at creation time — notifications go to Start().

Start signature:

// IConsumerQueue.cs line 37
void Start<T>(Action<IReceivedMessage<T>, IWorkerNotification> workerAction, ConsumerQueueNotifications notifications)
    where T : class;
  • ConsumerQueueNotifications is the second parameter of Start<T>(), not optional.
  • Wiki was missing this parameter entirely — this is the Critical finding.

ConsumerQueueNotifications constructor (Queue/ConsumerQueueNotifications.cs):

public ConsumerQueueNotifications(
    Action<ErrorNotification> onError = null,
    Action<ErrorReceiveNotification> onReceiveMessageError = null,
    Action<ErrorNotification> onMessageMovedToErrorQueue = null,
    Action<PoisonMessageNotification> onPoisonMessage = null,
    Action<RollBackNotification> onMessageRollBack = null,
    Action<MessageCompleteNotification> onMessageCompleted = null)

All parameters are optional (default null). Namespace: DotNetWorkQueue.Queue. Notification types are in namespace DotNetWorkQueue.Notifications.

Logging API (inside worker action):

  • IWorkerNotification.Log is Microsoft.Extensions.Logging.ILogger
  • Call: arg2.Log.LogInformation(...), arg2.Log.LogError(...), etc.
  • The old notifications.Log.Log(DotNetWorkQueue.Logging.LogLevel.Debug, () => ...) pattern is gone.

Working sample: SQLServerConsumer/Program.cs lines 57–80

using (var queue = queueContainer.CreateConsumer(queueConnection))
{
    queue.Configuration.Worker.WorkerCount = 4;
    queue.Configuration.HeartBeat.UpdateTime = "sec(*%10)";
    queue.Configuration.HeartBeat.MonitorTime = TimeSpan.FromSeconds(15);
    queue.Configuration.HeartBeat.Time = TimeSpan.FromSeconds(35);
    queue.Configuration.TransportConfiguration.RetryDelayBehavior.Add(
        typeof(InvalidDataException),
        new List<TimeSpan> { TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(6), TimeSpan.FromSeconds(9) });
    queue.Configuration.MessageExpiration.Enabled = true;
    queue.Configuration.MessageExpiration.MonitorTime = TimeSpan.FromSeconds(20);
    queue.Start<SimpleMessage>(MessageProcessing.HandleMessages, CreateNotifications.Create(log));
}

Required using statements:

using DotNetWorkQueue;
using DotNetWorkQueue.Configuration;
using DotNetWorkQueue.Queue;           // ConsumerQueueNotifications
using DotNetWorkQueue.Notifications;   // ErrorNotification, etc.
using Microsoft.Extensions.Logging;    // ILogger extension methods

2. ConsumerAsync.md

Question: What is the correct async consumer creation and Start() signature?

Source: IConsumerQueueAsync.cs, QueueContainer.cs

Creation:

// QueueContainer.cs line 111
public IConsumerQueueAsync CreateConsumerAsync(QueueConnection queueConnection)

Start signature:

// IConsumerQueueAsync.cs line 37
void Start<T>(Func<IReceivedMessage<T>, IWorkerNotification, Task> workerAction, ConsumerQueueNotifications notifications)
    where T : class;
  • Worker action is Func<..., Task> (async), not Action<...>.
  • ConsumerQueueNotifications is the second parameter.

Note on "async consumer" naming: The sample project named SQLServerConsumerAsync actually uses CreateConsumerQueueScheduler() + a SchedulerContainer, not CreateConsumerAsync(). The IConsumerQueueAsync is the lower-level interface; the scheduler-based approach is the more common pattern shown in samples. The wiki page should clarify this distinction.

Working sample: SQLServerConsumerAsync/Program.cs — uses CreateConsumerQueueScheduler() with task factory, not CreateConsumerAsync() directly. The direct CreateConsumerAsync() pattern is not demonstrated in the samples repo; only the scheduler-based async consumer has a sample.


3. ConsumerLinq.md → ConsumerMethod.md

Question: What is the current method consumer API?

Source: IConsumerMethodQueue.cs, QueueContainer.cs

Creation:

// QueueContainer.cs line 95
public IConsumerMethodQueue CreateMethodConsumer(QueueConnection queueConnection, Action<IContainer> registerServiceInternal)
  • Takes two parameters: QueueConnection and Action<IContainer> registerServiceInternal (for registering the message handler class).
  • Returns IConsumerMethodQueue.

Start signature:

// IConsumerMethodQueue.cs line 35
void Start(ConsumerQueueNotifications notifications);
  • No generic type parameter (the method expression carries the type information).
  • ConsumerQueueNotifications is required.

Scheduler variant:

// QueueContainer.cs line 147
public IConsumerMethodQueueScheduler CreateConsumerMethodQueueScheduler(QueueConnection queueConnection)

// QueueContainer.cs line 180
public IConsumerMethodQueueScheduler CreateConsumerMethodQueueScheduler(QueueConnection queueConnection, ITaskFactory factory)

// QueueContainer.cs line 195
public IConsumerMethodQueueScheduler CreateConsumerMethodQueueScheduler(QueueConnection queueConnection, ITaskFactory factory, IWorkGroup workGroup)

IConsumerMethodQueueScheduler.Start:

// IConsumerMethodQueueScheduler.cs line 35
void Start(ConsumerQueueNotifications notifications);

Working sample: SQLServerConsumerLinq/Program.cs uses CreateConsumerMethodQueueScheduler(queueConnection, factory).

using (var queue = queueContainer.CreateConsumerMethodQueueScheduler(queueConnection, factory))
{
    queue.Configuration.Worker.WorkerCount = 1;
    // ... configure ...
    queue.Start(CreateNotifications.Create(log));
}

Dynamic LINQ removal: In SampleShared/RunProducer.cs, the RunDynamic() and RunDynamicAsync() methods that use LinqExpressionToRun are wrapped in #if net48. They do not compile or exist in net8.0/net10.0 builds. The wiki must not reference LinqExpressionToRun as a current feature.


4. ConsumerLinqAsync.md → ConsumerMethodAsync.md

Question: What is the current async method consumer API?

Source: IConsumerMethodQueueScheduler.cs, QueueContainer.cs

This is the same as ConsumerMethod.md — there is no separate "async" method consumer. The scheduler-based IConsumerMethodQueueScheduler is the async/scheduler variant.

Start signature:

void Start(ConsumerQueueNotifications notifications);

Creation path:

// Three overloads exist (same as above, see ConsumerMethod section):
CreateConsumerMethodQueueScheduler(QueueConnection)
CreateConsumerMethodQueueScheduler(QueueConnection, ITaskFactory)
CreateConsumerMethodQueueScheduler(QueueConnection, ITaskFactory, IWorkGroup)

The SQLServerConsumerLinq sample demonstrates this pattern. No separate ConsumerLinqAsync sample project exists — the scheduler-based method consumer is both the "method" and the "async" variant.


5. ProducerLinq.md → ProducerMethod.md

Question: What does IProducerMethodQueue look like? Does it still accept lambda expressions? What happened to LinqExpressionToRun?

Source: IProducerMethodQueue.cs, QueueContainer.cs

Creation:

// QueueContainer.cs line 356
public IProducerMethodQueue CreateMethodProducer(QueueConnection queueConnection)

IProducerMethodQueue interface (all Send/SendAsync overloads accept lambda expressions):

// Send a single expression
IQueueOutputMessage Send(
    Expression<Action<IReceivedMessage<MessageExpression>, IWorkerNotification>> method,
    IAdditionalMessageData data = null,
    bool rawExpression = false);

// Send a list of expressions (no per-message data)
IQueueOutputMessages Send(
    List<Expression<Action<IReceivedMessage<MessageExpression>, IWorkerNotification>>> methods,
    bool rawExpression = false);

// Send a list with per-message data
IQueueOutputMessages Send(
    List<QueueMessage<Expression<Action<IReceivedMessage<MessageExpression>, IWorkerNotification>>, IAdditionalMessageData>> methods,
    bool rawExpression = false);

// Async variants of all three
Task<IQueueOutputMessage> SendAsync(...)
Task<IQueueOutputMessages> SendAsync(...)
Task<IQueueOutputMessages> SendAsync(...)

Lambda expression format (static — works on net8.0/net10.0):

queue.Send((message, workerNotification) => new TestClass().RunMe(
    workerNotification,
    "a string",
    2,
    new SomeInput(DateTime.UtcNow.ToString())));

LinqExpressionToRun (dynamic string-based): Guarded by #if net48 in RunProducer.cs. Does NOT exist in net8.0/net10.0 builds. The wiki must not document it as current.

rawExpression parameter: When true, the expression is not serialized (only works with in-process/memory transport). Default is false.

Working sample: SQLServerProducerLinq/Program.cs line 65:

using (var queue = queueContainer.CreateMethodProducer(queueConnection))
{
    // ...
}

And SampleShared/RunProducer.cs RunStatic() and RunStaticAsync() methods.


6. Home.md

Question: What are the current target frameworks?

Source: DotNetWorkQueue.csproj line 4

<TargetFrameworks>net10.0;net8.0;</TargetFrameworks>

Version: 0.9.30 Description from csproj: "Work queue for dot net 8.0 and 10.0."

Key NuGet dependencies (from csproj):

  • Microsoft.Extensions.Caching.Memory
  • OpenTelemetry
  • Polly.Core
  • SimpleInjector
  • Cronos + CronExpressionDescriptor (cron scheduling)
  • DotNetWorkQueue.Aq.ExpressionJsonSerializer (lambda serialization)
  • Newtonsoft.Json

What to remove from Home.md:

  • All references to net48, netstandard2.0, .NET Framework 4.8, .NET Standard 2.0
  • Any mention of dynamic LINQ as a current feature

7. _Sidebar.md

Required changes:

  • ProducerLinqProducerMethod
  • ConsumerLinqConsumerMethod
  • ConsumerLinqAsyncConsumerMethodAsync
  • Fix any typos noted in MANIFEST.md ("Additonal", "Posion")
  • No new pages needed from Phase 2 scope alone

8. WorkerConfiguration.md

Question: Does AbortWorkerThreadsWhenStopping exist?

Source: IWorkerConfiguration.cs

Current IWorkerConfiguration properties (complete list):

int WorkerCount { get; set; }
TimeSpan TimeToWaitForWorkersToCancel { get; set; }
TimeSpan TimeToWaitForWorkersToStop { get; set; }
bool SingleWorkerWhenNoWorkFound { get; set; }

AbortWorkerThreadsWhenStopping does NOT exist. No property by that name appears anywhere in IWorkerConfiguration.cs or WorkerConfiguration.cs. The wiki page documents a property that was removed from the library.

Concrete class: Configuration/WorkerConfiguration.cs implements IWorkerConfiguration.

Configuration access path (from samples):

queue.Configuration.Worker.WorkerCount = 4;
queue.Configuration.Worker.TimeToWaitForWorkersToCancel = TimeSpan.FromSeconds(30);
queue.Configuration.Worker.TimeToWaitForWorkersToStop = TimeSpan.FromSeconds(5);
queue.Configuration.Worker.SingleWorkerWhenNoWorkFound = true;

9. TaskSchedulerConfiguration.md

Question: What properties exist on ITaskSchedulerConfiguration? Is the typo fixed?

Source: ITaskSchedulerConfiguration.cs

Current ITaskSchedulerConfiguration properties (complete list):

int MaximumThreads { get; set; }
TimeSpan WaitForThreadPoolToFinish { get; set; }

WaitForTheadPoolToFinish (one 't') does NOT exist. The correct spelling is WaitForThreadPoolToFinish (double 't'). The wiki has a typo that prevents compilation.

Configuration access path (from samples):

factory.Scheduler.Configuration.MaximumThreads = 8;

WaitForThreadPoolToFinish is used internally in TaskScheduler.cs during Dispose():

WaitForDelegate.Wait(() => CurrentTaskCount > 0, _configuration.WaitForThreadPoolToFinish);

Also implements: IReadonly, ISetReadonly — configuration becomes read-only after Start() is called.

ITaskSchedulerConfiguration concrete class: Configuration/TaskSchedulerConfiguration.cs


10. ConsumerAsyncWorkGroup.md

Question: What is the AddWorkGroup method signature? Does the third parameter exist?

Source: ITaskScheduler.cs (interface), TaskScheduling/TaskScheduler.cs (implementation)

Interface definition:

// ITaskScheduler.cs line 49
IWorkGroup AddWorkGroup(string name, int concurrencyLevel);

Implementation:

// TaskScheduler.cs line 309
public override IWorkGroup AddWorkGroup(string name, int concurrencyLevel)
{
    var group = new WorkGroup(name, concurrencyLevel);
    // ...
    return groupWithItem.GroupInfo;
}

AddWorkGroup takes exactly two parameters: name (string) and concurrencyLevel (int). There is no third parameter. The wiki's claim of a third parameter is incorrect.

IWorkGroup properties:

string Name { get; }
int ConcurrencyLevel { get; }

Usage pattern:

var workGroup = factory.Scheduler.AddWorkGroup("myGroup", 4);
// Then pass to CreateConsumerMethodQueueScheduler:
queueContainer.CreateConsumerMethodQueueScheduler(queueConnection, factory, workGroup);
// or:
queueContainer.CreateConsumerQueueScheduler(queueConnection, factory, workGroup);

WorkGroupWithItem (internal): Created automatically inside AddWorkGroup. It wraps IWorkGroup with runtime state (CurrentWorkItems, MaxWorkItems, MetricCounter). This is an internal implementation detail, not part of the public API.


11. Producer.md

Question: Verify the current producer API is correct.

Source: IProducerQueue.cs, QueueContainer.cs

Creation:

public IProducerQueue<TMessage> CreateProducer<TMessage>(QueueConnection queueConnection)
    where TMessage : class

IProducerQueue send methods:

IQueueOutputMessage Send(TMessage message, IAdditionalMessageData data = null);
IQueueOutputMessages Send(List<TMessage> messages);
IQueueOutputMessages Send(List<QueueMessage<TMessage, IAdditionalMessageData>> messages);
Task<IQueueOutputMessage> SendAsync(TMessage message, IAdditionalMessageData data = null);
Task<IQueueOutputMessages> SendAsync(List<TMessage> messages);
Task<IQueueOutputMessages> SendAsync(List<QueueMessage<TMessage, IAdditionalMessageData>> messages);

Working sample: SQLServerProducer/Program.cs line 74:

using (var queue = queueContainer.CreateProducer<SimpleMessage>(queueConnection))
{
    var result = queue.Send(message, additionalData);
}

Audit conclusion: Producer.md is confirmed correct. No changes needed to API signatures.


12. ProducerConfiguration.md

Question: What configuration sections exist for producers?

Source: Configuration/QueueProducerConfiguration.cs, Configuration/QueueConfigurationSend.cs

QueueProducerConfiguration extends QueueConfigurationSend.

Properties on QueueProducerConfiguration / QueueConfigurationSend:

// From QueueConfigurationSend:
TransportConfigurationSend TransportConfiguration { get; }
IPolicies Policies { get; }
IHeaders HeaderNames { get; }
IConfiguration AdditionalConfiguration { get; }
BaseTimeConfiguration TimeConfiguration { get; }

Key transport-level configuration (accessed via TransportConfiguration):

  • RetryDelayBehavior — maps exception types to retry delay sequences

Typical configuration pattern (from samples):

// Producer configuration is mostly done at queue creation time (QueueCreationContainer)
// The producer itself has minimal runtime configuration
using (var queue = queueContainer.CreateProducer<SimpleMessage>(queueConnection))
{
    // queue.Configuration.TransportConfiguration...
    // queue.Configuration.Policies...
}

Note: Most producer options (delayed processing, heartbeat, history, etc.) are set at queue creation time via QueueCreationContainer, not on the producer runtime configuration. The wiki page should make this distinction clear.


13. ConsumerConfiguration.md

Question: What configuration sections exist for consumers? Is MessageError present?

Source: Configuration/QueueConsumerConfiguration.cs

QueueConsumerConfiguration extends QueueConfigurationReceive.

Properties:

IWorkerConfiguration Worker { get; }
IHeartBeatConfiguration HeartBeat { get; }
IMessageExpirationConfiguration MessageExpiration { get; }
IMessageErrorConfiguration MessageError { get; }
List<string> Routes { get; }
Dictionary<string, object> AdditionalSettings { get; }
MaintenanceMode MaintenanceMode { get; set; }  // added property, not in wiki

Plus from QueueConfigurationReceive (base):

TransportConfigurationReceive TransportConfiguration { get; }
IHeaders HeaderNames { get; }
IConfiguration AdditionalConfiguration { get; }
BaseTimeConfiguration TimeConfiguration { get; }

IMessageErrorConfiguration (from Configuration/MessageErrorConfiguration.cs):

bool Enabled { get; set; }          // default: true
TimeSpan MessageAge { get; set; }   // default: 30 days
TimeSpan MonitorTime { get; set; }  // default: 1 day

Purpose: Automatically removes error-status messages older than MessageAge. Checked every MonitorTime.

MaintenanceMode (new property):

  • MaintenanceMode.Consumer (default) — consumer runs maintenance monitors (heartbeat reset, expiration cleanup, error cleanup)
  • MaintenanceMode.External — consumer does NOT run maintenance monitors; per-message heartbeat updates are unaffected

Audit conclusion: MessageError configuration IS present in source and should be documented in the wiki.


14. ConsumerAsyncConfiguration.md

Question: What configuration sections exist for async consumers? MessageError? MessageHistory?

Source: Same as ConsumerConfiguration.md — async consumers use the same QueueConsumerConfiguration.

All consumers — sync, async, method, method-scheduler — share QueueConsumerConfiguration via IConsumerBaseQueue.Configuration. The configuration structure is identical regardless of which Create* method was used.

MessageHistory configuration: There is a Configuration/HistoryTransportOptions.cs and an IHistoryTransportOptions interface, but these are transport-specific (set at queue creation time). There is no MessageHistory section on the runtime consumer configuration. The wiki should note that message history is enabled at queue creation (via createQueue.Options.EnableHistory = true), not at consumer runtime.


15. Usage.md

Question: What queue variants exist now?

From QueueContainer public methods (complete list):

Method Returns Notes
CreateConsumer(QueueConnection) IConsumerQueue Sync consumer
CreateConsumerAsync(QueueConnection) IConsumerQueueAsync Async consumer (user manages tasks)
CreateConsumerQueueScheduler(QueueConnection) IConsumerQueueScheduler Scheduler-based async (auto task factory)
CreateConsumerQueueScheduler(QueueConnection, ITaskFactory) IConsumerQueueScheduler Scheduler-based async (external factory)
CreateConsumerQueueScheduler(QueueConnection, ITaskFactory, IWorkGroup) IConsumerQueueScheduler Scheduler-based with work group
CreateMethodConsumer(QueueConnection, Action<IContainer>) IConsumerMethodQueue Method consumer (lambda expressions)
CreateConsumerMethodQueueScheduler(QueueConnection) IConsumerMethodQueueScheduler Method + scheduler (auto factory)
CreateConsumerMethodQueueScheduler(QueueConnection, ITaskFactory) IConsumerMethodQueueScheduler Method + scheduler (external factory)
CreateConsumerMethodQueueScheduler(QueueConnection, ITaskFactory, IWorkGroup) IConsumerMethodQueueScheduler Method + scheduler + work group
CreateProducer<TMessage>(QueueConnection) IProducerQueue<TMessage> Typed message producer
CreateMethodProducer(QueueConnection) IProducerMethodQueue Lambda expression producer
CreateMethodJobProducer(QueueConnection) IProducerMethodJobQueue Job scheduler producer
CreateJobSchedulerLastKnownEvent(QueueConnection) IJobSchedulerLastKnownEvent Job scheduler state query
CreateTimeSync(string connection) IGetTimeFactory Server time synchronization
CreateAdminApi() IAdminApi Admin API (queue counts, etc.)
CreateAdminFunctions(QueueConnection) IAdminFunctions Per-queue admin functions
CreateAdminContainer(QueueConnection) IContainer Raw IoC container for dashboard

Logging API: Before vs. After

Old pattern (broken, must not appear in any Phase 2 page):

// This does not compile against 0.9.30
notifications.Log.Log(DotNetWorkQueue.Logging.LogLevel.Debug, () => "message");

Current pattern (from SampleShared/MessageProcessing.cs):

// arg2 is IWorkerNotification; arg2.Log is Microsoft.Extensions.Logging.ILogger
arg2.Log.LogInformation($"Processing message {arg1.MessageId.Id.Value}");
arg2.Log.LogError($"Something failed");
arg2.Log.LogWarning($"Warning message");

The DotNetWorkQueue.Logging namespace still exists (as a directory in source) but contains only a Decorator subdirectory — it does not export LogLevel or any logging API that user code should reference. All user-facing logging goes through Microsoft.Extensions.Logging.ILogger.


ConsumerQueueNotifications Notification Types

All notification action types are in DotNetWorkQueue.Notifications:

Parameter Type Fires When
onError Action<ErrorNotification> Unhandled exception during processing
onReceiveMessageError Action<ErrorReceiveNotification> Queue unable to obtain messages from transport
onMessageMovedToErrorQueue Action<ErrorNotification> Message moved to error queue (or deleted)
onPoisonMessage Action<PoisonMessageNotification> Poison message encountered
onMessageRollBack Action<RollBackNotification> Message being rolled back
onMessageCompleted Action<MessageCompleteNotification> Message completed without error

ABaseNotification base class properties (all notification types share these):

IMessageId MessageId { get; }
ICorrelationId CorrelationId { get; }
IReadOnlyDictionary<string, object> Headers { get; }
THeader GetHeader<THeader>(IMessageContextData<THeader> property)

Working sample of notification creation (SampleShared/CreateNotifications.cs):

public static ConsumerQueueNotifications Create(ILogger logger)
{
    return new ConsumerQueueNotifications(
        onError:                   (n) => logger.LogError($"Error: {n.Error}"),
        onReceiveMessageError:     (n) => logger.LogError($"Receive error: {n.Error}"),
        onMessageMovedToErrorQueue:(n) => logger.LogError($"Moved to error queue: {n.MessageId}"),
        onPoisonMessage:           (n) => logger.LogError($"Poison message: {n.MessageId}"),
        onMessageRollBack:         (n) => logger.LogWarning($"Rollback: {n.MessageId}"),
        onMessageCompleted:        (n) => logger.LogInformation($"Completed: {n.MessageId}"));
}

Uncertainty Flags

  1. IConsumerQueueAsync direct usage sample: The SQLServerConsumerAsync sample uses CreateConsumerQueueScheduler(), not CreateConsumerAsync(). There is no sample in the repo demonstrating direct use of IConsumerQueueAsync. The wiki page for ConsumerAsync.md may need to clarify the distinction or note that the scheduler approach is preferred.

  2. CreateMethodConsumer second parameter: QueueContainer.CreateMethodConsumer() requires Action<IContainer> registerServiceInternal. The samples do not demonstrate this path directly (they use CreateConsumerMethodQueueScheduler() instead). The wiki needs to clarify what registerServiceInternal is for (registering the class that will handle the method expressions).

  3. Scheduler sample still uses Schyntax: SQLServerScheduler/Program.cs uses "sec(0,5,10,15,20,25,30,35,40,45,50,55)" — this is the old Schyntax format. The JobScheduler section in Phase 4 must verify whether the live AddUpdateJob API still accepts Schyntax or has migrated to Cronos. The main project csproj includes both Cronos and CronExpressionDescriptor packages, suggesting cron is the current format.

  4. MessageHistory on async consumer: The wiki implies MessageHistory is a consumer configuration section, but the source shows it is a queue creation option (createQueue.Options.EnableHistory), not a runtime consumer configuration property. Phase 2 should correct this framing. The IHistoryTransportOptions interface is transport-specific.

  5. MaintenanceMode property on QueueConsumerConfiguration: This appears to be a newer addition not in the original wiki. Phase 2 pages should decide whether to document it.


Source File Index

File Purpose
QueueContainer.cs All Create* factory methods
IConsumerQueue.cs Start<T>(action, notifications)
IConsumerQueueAsync.cs Start<T>(asyncAction, notifications)
IConsumerMethodQueue.cs Start(notifications) — no generic
IConsumerMethodQueueScheduler.cs Start(notifications) — scheduler variant
IConsumerQueueScheduler.cs Start<T>(action, notifications) — scheduler for typed messages
IConsumerBaseQueue.cs QueueConsumerConfiguration Configuration { get; }
IProducerQueue.cs Send() / SendAsync() for typed messages
IProducerMethodQueue.cs Send() / SendAsync() for lambda expressions
IWorkerConfiguration.cs 4 properties; no AbortWorkerThreadsWhenStopping
ITaskSchedulerConfiguration.cs MaximumThreads, WaitForThreadPoolToFinish
ITaskScheduler.cs AddWorkGroup(name, concurrencyLevel) — 2 params
TaskScheduling/TaskScheduler.cs AddWorkGroup implementation
TaskScheduling/WorkGroup.cs IWorkGroup impl: Name, ConcurrencyLevel
Configuration/QueueConsumerConfiguration.cs Consumer config: Worker, HeartBeat, MessageExpiration, MessageError, Routes, MaintenanceMode
Configuration/QueueProducerConfiguration.cs Producer config: TransportConfiguration, Policies, HeaderNames
Configuration/MessageErrorConfiguration.cs Enabled, MessageAge (30d), MonitorTime (1d)
Queue/ConsumerQueueNotifications.cs All-optional constructor, 6 notification callbacks
Notifications/BaseNotification.cs ABaseNotification base class
IWorkerNotification.cs ILogger Log (MEL), IMetrics Metrics, ActivitySource Tracer
IAdminApi.cs AddQueueConnection(), Count()
SchedulerContainer.cs CreateTaskScheduler(), CreateTaskFactory()
DotNetWorkQueue.csproj net10.0;net8.0 target frameworks, version 0.9.30

Samples File Index

File Demonstrates
SQLServerConsumer/Program.cs Sync consumer, full configuration, Start<T>() with notifications
SQLServerConsumerAsync/Program.cs Scheduler-based async consumer (typed messages)
SQLServerConsumerLinq/Program.cs CreateConsumerMethodQueueScheduler() with external factory
SQLServerProducer/Program.cs Typed producer, queue creation, CreateAdminApi()
SQLServerProducerLinq/Program.cs CreateMethodProducer()
SQLServerScheduler/Program.cs Job scheduler (uses stale Schyntax — see uncertainty flag 3)
SampleShared/CreateNotifications.cs ConsumerQueueNotifications construction pattern
SampleShared/MessageProcessing.cs IWorkerNotification.Log.LogInformation() usage
SampleShared/RunProducer.cs RunStatic() lambda expression send; RunDynamic() guarded by #if net48

Clone this wiki locally