diff --git a/TaskFlow.Extensions.Microsoft.DependencyInjection/IDefaultTaskFlowFactory.cs b/TaskFlow.Extensions.Microsoft.DependencyInjection/IDefaultTaskFlowFactory.cs
index 470fd2e..738f24f 100644
--- a/TaskFlow.Extensions.Microsoft.DependencyInjection/IDefaultTaskFlowFactory.cs
+++ b/TaskFlow.Extensions.Microsoft.DependencyInjection/IDefaultTaskFlowFactory.cs
@@ -1,7 +1,143 @@
namespace System.Threading.Tasks.Flow
{
+ ///
+ /// Defines a factory contract for creating default instances with specified options.
+ ///
+ ///
+ ///
+ /// The interface provides a simple factory abstraction for creating
+ /// task flow instances with specific configuration options. This interface serves as the fallback factory
+ /// when no named factory is available, ensuring that task flows can always be created with at least
+ /// default behavior.
+ ///
+ ///
+ /// Key characteristics of the default factory:
+ ///
+ ///
+ /// Option-based creation - Takes explicit options rather than resolving them from names
+ /// Fallback behavior - Used when no specific named factory is registered
+ /// Simple interface - Single method focused on core task flow creation
+ /// Dependency injection ready - Designed for registration in DI containers
+ ///
+ ///
+ /// The default implementation typically creates standard instances, but
+ /// custom implementations can provide different task flow types or behaviors while maintaining
+ /// compatibility with the dependency injection system.
+ ///
+ ///
+ /// This interface is particularly useful for:
+ ///
+ ///
+ /// Providing consistent default behavior across the application
+ /// Enabling easy replacement of the default task flow implementation
+ /// Supporting unit testing with mock implementations
+ /// Allowing customization of default creation logic
+ ///
+ ///
+ ///
+ /// Custom default factory implementation:
+ ///
+ /// public class CustomDefaultTaskFlowFactory : IDefaultTaskFlowFactory
+ /// {
+ /// private readonly ILogger<CustomDefaultTaskFlowFactory> _logger;
+ ///
+ /// public CustomDefaultTaskFlowFactory(ILogger<CustomDefaultTaskFlowFactory> logger)
+ /// {
+ /// _logger = logger;
+ /// }
+ ///
+ /// public ITaskFlow Create(TaskFlowOptions options)
+ /// {
+ /// _logger.LogInformation("Creating TaskFlow with options: {Options}", options);
+ ///
+ /// // Create a custom task flow or wrap the standard one
+ /// var taskFlow = new TaskFlow(options);
+ /// return new LoggingTaskFlowWrapper(taskFlow, _logger);
+ /// }
+ /// }
+ ///
+ /// // Register the custom factory
+ /// services.AddSingleton<IDefaultTaskFlowFactory, CustomDefaultTaskFlowFactory>();
+ ///
+ /// Usage in task flow factory:
+ ///
+ /// public class TaskFlowFactory : ITaskFlowFactory
+ /// {
+ /// private readonly IDefaultTaskFlowFactory _defaultFactory;
+ ///
+ /// public TaskFlowFactory(IDefaultTaskFlowFactory defaultFactory)
+ /// {
+ /// _defaultFactory = defaultFactory;
+ /// }
+ ///
+ /// public ITaskFlow CreateTaskFlow(string? name = null)
+ /// {
+ /// var options = ResolveOptions(name);
+ ///
+ /// // Use default factory for creation
+ /// return _defaultFactory.Create(options);
+ /// }
+ /// }
+ ///
+ ///
public interface IDefaultTaskFlowFactory
{
+ ///
+ /// Creates a new instance with the specified configuration options.
+ ///
+ /// The configuration options to use for creating the task flow instance.
+ /// A new instance configured with the specified options.
+ /// Thrown when is null.
+ ///
+ ///
+ /// This method creates a task flow instance using the provided options directly, without any
+ /// name-based resolution or additional configuration. The implementation should respect all
+ /// settings specified in the options parameter.
+ ///
+ ///
+ /// The created task flow should:
+ ///
+ ///
+ /// Honor all configuration settings from the options parameter
+ /// Be fully functional and ready for task enqueueing
+ /// Support proper disposal for resource cleanup
+ /// Maintain thread safety as required by the task flow contract
+ ///
+ ///
+ /// Implementations may choose to:
+ ///
+ ///
+ /// Create standard instances
+ /// Apply additional wrappers or decorators
+ /// Provide custom task flow implementations
+ /// Add logging, monitoring, or other cross-cutting concerns
+ ///
+ ///
+ /// The factory should not modify the provided options object, as it may be shared
+ /// across multiple factory calls or contain immutable settings.
+ ///
+ ///
+ ///
+ ///
+ /// public ITaskFlow Create(TaskFlowOptions options)
+ /// {
+ /// // Validate options
+ /// if (options == null)
+ /// throw new ArgumentNullException(nameof(options));
+ ///
+ /// // Create the core task flow
+ /// var taskFlow = new TaskFlow(options);
+ ///
+ /// // Optionally add wrappers or decorators
+ /// if (options.EnableLogging)
+ /// {
+ /// taskFlow = new LoggingTaskFlowWrapper(taskFlow);
+ /// }
+ ///
+ /// return taskFlow;
+ /// }
+ ///
+ ///
ITaskFlow Create(TaskFlowOptions options);
}
}
\ No newline at end of file
diff --git a/TaskFlow.Extensions.Microsoft.DependencyInjection/INamedConfigureTaskFlowChain.cs b/TaskFlow.Extensions.Microsoft.DependencyInjection/INamedConfigureTaskFlowChain.cs
index 8c4d8d4..e7cb851 100644
--- a/TaskFlow.Extensions.Microsoft.DependencyInjection/INamedConfigureTaskFlowChain.cs
+++ b/TaskFlow.Extensions.Microsoft.DependencyInjection/INamedConfigureTaskFlowChain.cs
@@ -1,9 +1,239 @@
namespace System.Threading.Tasks.Flow
{
+ ///
+ /// Defines a named configuration contract for applying scheduler chain modifications to named task flow instances.
+ ///
+ ///
+ ///
+ /// The interface enables the configuration of scheduler wrapper chains
+ /// for named task flow instances. This allows the application of cross-cutting concerns like error handling,
+ /// timeouts, throttling, and other TaskFlow extensions to specific named instances.
+ ///
+ ///
+ /// Scheduler chains provide:
+ ///
+ ///
+ /// Cross-cutting concerns - Apply common functionality without modifying core logic
+ /// Named customization - Different chains for different named instances
+ /// Composition - Chain multiple schedulers together for complex behaviors
+ /// Dependency injection integration - Access other services for chain configuration
+ ///
+ ///
+ /// The chain configuration system integrates with:
+ ///
+ ///
+ /// - Chains are applied after factory creation
+ /// - Options are used before chain application
+ /// TaskFlow extension methods - Chains can use any scheduler extension methods
+ ///
+ ///
+ /// Execution order:
+ ///
+ ///
+ /// Named or default factory creates the base task flow
+ /// Named chain configuration is applied to wrap the scheduler
+ /// The wrapped scheduler is used for all task operations
+ ///
+ ///
+ /// Common chain use cases:
+ ///
+ ///
+ /// Adding timeout protection to API call task flows
+ /// Applying error handling and logging to background processing
+ /// Adding throttling to prevent resource exhaustion
+ /// Implementing retry logic for unreliable operations
+ /// Adding monitoring and metrics collection
+ ///
+ ///
+ ///
+ /// Creating a named chain configuration:
+ ///
+ /// public class ApiTaskFlowChain : INamedConfigureTaskFlowChain
+ /// {
+ /// private readonly ILogger<ApiTaskFlowChain> _logger;
+ /// private readonly IMetrics _metrics;
+ ///
+ /// public ApiTaskFlowChain(ILogger<ApiTaskFlowChain> logger, IMetrics metrics)
+ /// {
+ /// _logger = logger;
+ /// _metrics = metrics;
+ /// }
+ ///
+ /// public string Name => "api";
+ ///
+ /// public ITaskScheduler ConfigureChain(ITaskScheduler taskScheduler)
+ /// {
+ /// return taskScheduler
+ /// .WithOperationName("ApiOperation")
+ /// .WithTimeout(TimeSpan.FromSeconds(30))
+ /// .OnError<HttpRequestException>((sched, ex, name) =>
+ /// _logger.LogWarning(ex, "HTTP error in {Operation}", name?.OperationName))
+ /// .OnError<TimeoutException>((sched, ex, name) =>
+ /// _metrics.IncrementCounter("api.timeout", new { operation = name?.OperationName }));
+ /// }
+ /// }
+ ///
+ /// Registering named chains:
+ ///
+ /// // Register using implementation
+ /// services.AddSingleton<INamedConfigureTaskFlowChain, ApiTaskFlowChain>();
+ ///
+ /// // Register using delegate
+ /// services.AddTaskFlow("background",
+ /// configureSchedulerChain: (scheduler, provider) => {
+ /// var logger = provider.GetRequiredService<ILogger>();
+ /// return scheduler
+ /// .WithOperationName("BackgroundWork")
+ /// .OnError(ex => logger.LogError(ex, "Background processing error"));
+ /// });
+ ///
+ /// Complex chain configuration:
+ ///
+ /// public ITaskScheduler ConfigureChain(ITaskScheduler taskScheduler)
+ /// {
+ /// var baseScheduler = taskScheduler
+ /// .WithOperationName($"{Name}Operation")
+ /// .WithTimeout(TimeSpan.FromMinutes(5));
+ ///
+ /// // Add environment-specific behavior
+ /// if (_environment.IsProduction())
+ /// {
+ /// baseScheduler = baseScheduler
+ /// .WithDebounce(TimeSpan.FromSeconds(1))
+ /// .OnError<Exception>(ex => _telemetry.TrackException(ex));
+ /// }
+ /// else
+ /// {
+ /// baseScheduler = baseScheduler
+ /// .OnError<Exception>(ex => _console.WriteLine($"Error: {ex}"));
+ /// }
+ ///
+ /// return baseScheduler;
+ /// }
+ ///
+ ///
public interface INamedConfigureTaskFlowChain
{
+ ///
+ /// Gets the name that identifies this scheduler chain configuration.
+ ///
+ ///
+ /// A string that uniquely identifies this chain configuration within the dependency injection container.
+ /// This name is used to resolve which chain should be applied when creating named task flow instances.
+ ///
+ ///
+ ///
+ /// The name serves as the key for chain resolution in the dependency injection system.
+ /// When is called with a specific name,
+ /// the factory system searches for a registered with a
+ /// matching property.
+ ///
+ ///
+ /// Name coordination considerations:
+ ///
+ ///
+ /// Consistency - Should match names used in factories and options for coordinated configuration
+ /// Case sensitivity - Names are typically case-sensitive
+ /// Uniqueness - Each chain configuration should have a unique name within the container
+ /// Stability - The name should remain constant throughout the configuration's lifetime
+ ///
+ ///
+ /// The chain is applied after the base task flow is created (either by a named factory or the default factory)
+ /// but before the task flow is returned to the calling code. This allows the chain to wrap the scheduler
+ /// with additional functionality.
+ ///
+ ///
+ ///
+ ///
+ /// public class DatabaseChain : INamedConfigureTaskFlowChain
+ /// {
+ /// // This chain will be applied when CreateTaskFlow("database") is called
+ /// public string Name => "database";
+ ///
+ /// public ITaskScheduler ConfigureChain(ITaskScheduler taskScheduler)
+ /// {
+ /// return taskScheduler
+ /// .WithOperationName("DatabaseOperation")
+ /// .WithTimeout(TimeSpan.FromSeconds(30))
+ /// .OnError<SqlException>(ex => _logger.LogError(ex, "Database error"));
+ /// }
+ /// }
+ ///
+ ///
string Name { get; }
+ ///
+ /// Configures and returns a scheduler chain by wrapping the provided task scheduler with additional functionality.
+ ///
+ /// The base task scheduler to wrap with additional functionality.
+ /// An that wraps the original scheduler with the configured chain.
+ /// Thrown when is null.
+ ///
+ ///
+ /// This method applies scheduler wrapper chains to add cross-cutting concerns and additional functionality
+ /// to the base task scheduler. The method can chain multiple scheduler extensions together to create
+ /// complex behaviors while maintaining the core scheduler interface.
+ ///
+ ///
+ /// Chain configuration guidelines:
+ ///
+ ///
+ /// Composition - Use TaskFlow extension methods to build the chain
+ /// Order matters - The order of chained extensions affects behavior
+ /// Preserve interface - Always return an ITaskScheduler implementation
+ /// Resource management - Ensure proper disposal is supported throughout the chain
+ ///
+ ///
+ /// Available extension methods for chaining include:
+ ///
+ ///
+ /// - Add operation naming
+ /// - Add timeout protection
+ /// - Add debouncing
+ /// - Add error handling
+ /// - Add cancellation scopes
+ /// - Add cancel-previous behavior
+ ///
+ ///
+ /// The method can access dependency injection services to configure the chain based on runtime conditions,
+ /// configuration settings, or other application state.
+ ///
+ ///
+ /// Chain execution order is determined by the order of method calls, with each extension wrapping
+ /// the previous one. The outermost wrapper receives calls first, and the original scheduler
+ /// receives calls last.
+ ///
+ ///
+ ///
+ ///
+ /// public ITaskScheduler ConfigureChain(ITaskScheduler taskScheduler)
+ /// {
+ /// if (taskScheduler == null)
+ /// throw new ArgumentNullException(nameof(taskScheduler));
+ ///
+ /// // Build a comprehensive chain for this named instance
+ /// var chain = taskScheduler
+ /// .WithOperationName(Name) // Add operation naming
+ /// .WithTimeout(TimeSpan.FromMinutes(2)); // Add timeout protection
+ ///
+ /// // Add environment-specific extensions
+ /// if (_configuration.GetValue<bool>("EnableThrottling"))
+ /// {
+ /// var interval = _configuration.GetValue<TimeSpan>("ThrottleInterval");
+ /// chain = chain.WithDebounce(interval);
+ /// }
+ ///
+ /// // Add error handling
+ /// chain = chain
+ /// .OnError<TimeoutException>((sched, ex, name) =>
+ /// _metrics.IncrementCounter("timeout", new { operation = name?.OperationName }))
+ /// .OnError<Exception>(ex =>
+ /// _logger.LogError(ex, "Error in {Name} operation", Name));
+ ///
+ /// return chain;
+ /// }
+ ///
+ ///
ITaskScheduler ConfigureChain(ITaskScheduler taskScheduler);
}
}
\ No newline at end of file
diff --git a/TaskFlow.Extensions.Microsoft.DependencyInjection/INamedConfigureTaskFlowOptions.cs b/TaskFlow.Extensions.Microsoft.DependencyInjection/INamedConfigureTaskFlowOptions.cs
index 07bdbee..8499f12 100644
--- a/TaskFlow.Extensions.Microsoft.DependencyInjection/INamedConfigureTaskFlowOptions.cs
+++ b/TaskFlow.Extensions.Microsoft.DependencyInjection/INamedConfigureTaskFlowOptions.cs
@@ -1,9 +1,109 @@
namespace System.Threading.Tasks.Flow
{
+ ///
+ /// Defines a named configuration contract for providing specific to named task flow instances.
+ ///
+ ///
+ ///
+ /// The interface enables named configuration of task flow options
+ /// within the dependency injection system. This allows different task flow instances to have different
+ /// configuration settings based on their intended purpose or usage context.
+ ///
+ ///
+ /// Named options configuration provides:
+ ///
+ ///
+ /// Configuration separation - Different options for different named instances
+ /// Runtime configuration - Options can be computed or resolved at runtime
+ /// Dependency injection integration - Can access other services for configuration
+ /// Environment-specific settings - Different options for different environments
+ ///
+ ///
+ /// The options configuration system works in conjunction with:
+ ///
+ ///
+ /// - For custom task flow creation
+ /// - For scheduler chain configuration
+ /// - As the fallback when no named factory exists
+ ///
+ ///
+ /// Configuration precedence:
+ ///
+ ///
+ /// Named options are resolved and applied first
+ /// If no named options exist, default options are used
+ /// Options are passed to either named factories or the default factory
+ /// Scheduler chains are applied to the resulting task flow
+ ///
+ ///
public interface INamedConfigureTaskFlowOptions
{
+ ///
+ /// Gets the name that identifies this options configuration.
+ ///
+ ///
+ /// A string that uniquely identifies this options configuration within the dependency injection container.
+ /// This name is used to resolve which options should be used when creating named task flow instances.
+ ///
+ ///
+ ///
+ /// The name serves as the key for options resolution in the dependency injection system.
+ /// When is called with a specific name,
+ /// the factory system searches for a registered with a
+ /// matching property.
+ ///
+ ///
+ /// Name matching considerations:
+ ///
+ ///
+ /// Case sensitivity - Names are typically case-sensitive
+ /// Uniqueness - Each options configuration should have a unique name within the container
+ /// Stability - The name should remain constant throughout the configuration's lifetime
+ /// Coordination - Should match names used in factories and scheduler chains for consistency
+ ///
+ ///
+ /// If multiple options configurations are registered with the same name, the behavior depends on the
+ /// dependency injection container implementation, but typically the last registered configuration
+ /// will be used.
+ ///
+ ///
string Name { get; }
+ ///
+ /// Creates and configures a instance for this named configuration.
+ ///
+ /// A instance configured according to this configuration's requirements.
+ ///
+ ///
+ /// This method is responsible for creating and configuring the options that will be used to
+ /// create task flow instances with the associated name. The method can access dependency injection
+ /// services, configuration sources, or any other resources needed to determine the appropriate
+ /// configuration.
+ ///
+ ///
+ /// Configuration guidelines:
+ ///
+ ///
+ /// Consistency - Should return consistent options for the same conditions
+ /// Validation - Should ensure returned options are valid and usable
+ /// Performance - Should be efficient as it may be called multiple times
+ /// Thread safety - Should be safe for concurrent access
+ ///
+ ///
+ /// The method can:
+ ///
+ ///
+ /// Read from configuration files or environment variables
+ /// Access other dependency injection services
+ /// Compute options based on runtime conditions
+ /// Provide different options for different environments
+ /// Apply business logic to determine appropriate settings
+ ///
+ ///
+ /// The returned options should be a new instance rather than a shared static instance to
+ /// avoid potential modification issues, unless the options are truly immutable.
+ ///
+ ///
TaskFlowOptions Configure();
}
}
\ No newline at end of file
diff --git a/TaskFlow.Extensions.Microsoft.DependencyInjection/INamedTaskFlowFactory.cs b/TaskFlow.Extensions.Microsoft.DependencyInjection/INamedTaskFlowFactory.cs
index 2566bea..db9ecea 100644
--- a/TaskFlow.Extensions.Microsoft.DependencyInjection/INamedTaskFlowFactory.cs
+++ b/TaskFlow.Extensions.Microsoft.DependencyInjection/INamedTaskFlowFactory.cs
@@ -1,9 +1,213 @@
namespace System.Threading.Tasks.Flow
{
+ ///
+ /// Defines a named factory contract for creating instances with specific configurations.
+ ///
+ ///
+ ///
+ /// The interface extends the factory pattern to support named
+ /// configurations, allowing multiple task flow factories to coexist within the same dependency
+ /// injection container. Each factory is associated with a specific name and provides custom
+ /// creation logic for that particular configuration.
+ ///
+ ///
+ /// Named factories enable:
+ ///
+ ///
+ /// Multiple configurations - Different task flow types for different purposes
+ /// Specialized implementations - Custom task flow types for specific scenarios
+ /// Environment-specific behavior - Different implementations for testing vs. production
+ /// Feature-specific optimizations - Tailored task flows for specific application features
+ ///
+ ///
+ /// The factory system works hierarchically:
+ ///
+ ///
+ /// Named factories are checked first when creating task flows
+ /// If no named factory exists, the default factory is used
+ /// Options and scheduler chains can still be applied to named factory results
+ ///
+ ///
+ /// Common use cases include:
+ ///
+ ///
+ /// Background processing with dedicated thread task flows
+ /// UI operations with current thread task flows
+ /// High-throughput scenarios with custom parallel implementations
+ /// Testing scenarios with mock or instrumented task flows
+ ///
+ ///
+ ///
+ /// Creating a custom named factory:
+ ///
+ /// public class BackgroundTaskFlowFactory : INamedTaskFlowFactory
+ /// {
+ /// public string Name => "background";
+ ///
+ /// public ITaskFlow Create(TaskFlowOptions options)
+ /// {
+ /// // Create a dedicated thread task flow for background processing
+ /// return new DedicatedThreadTaskFlow(options);
+ /// }
+ /// }
+ ///
+ /// public class UiTaskFlowFactory : INamedTaskFlowFactory
+ /// {
+ /// public string Name => "ui";
+ ///
+ /// public ITaskFlow Create(TaskFlowOptions options)
+ /// {
+ /// // Create a current thread task flow for UI operations
+ /// return new CurrentThreadTaskFlow(options);
+ /// }
+ /// }
+ ///
+ /// Registering named factories:
+ ///
+ /// // Register multiple named factories
+ /// services.AddSingleton<INamedTaskFlowFactory, BackgroundTaskFlowFactory>();
+ /// services.AddSingleton<INamedTaskFlowFactory, UiTaskFlowFactory>();
+ ///
+ /// // Register using delegate factory
+ /// services.AddTaskFlow("database", (provider, options) =>
+ /// new TaskFlow(options with { MaxConcurrency = 1 }));
+ ///
+ /// Using named factories:
+ ///
+ /// public class ApplicationService
+ /// {
+ /// private readonly ITaskFlowFactory _factory;
+ ///
+ /// public ApplicationService(ITaskFlowFactory factory)
+ /// {
+ /// _factory = factory;
+ /// }
+ ///
+ /// public async Task ProcessInBackgroundAsync()
+ /// {
+ /// using var taskFlow = _factory.CreateTaskFlow("background");
+ /// await taskFlow.Enqueue(() => DoBackgroundWorkAsync());
+ /// }
+ ///
+ /// public async Task UpdateUiAsync()
+ /// {
+ /// using var taskFlow = _factory.CreateTaskFlow("ui");
+ /// await taskFlow.Enqueue(() => UpdateUserInterfaceAsync());
+ /// }
+ /// }
+ ///
+ ///
public interface INamedTaskFlowFactory
{
+ ///
+ /// Gets the name that identifies this factory configuration.
+ ///
+ ///
+ /// A string that uniquely identifies this factory within the dependency injection container.
+ /// This name is used to resolve which factory should be used when creating named task flow instances.
+ ///
+ ///
+ ///
+ /// The name serves as the key for factory resolution in the dependency injection system.
+ /// When is called with a specific name,
+ /// the factory system searches for a registered with a
+ /// matching property.
+ ///
+ ///
+ /// Name matching considerations:
+ ///
+ ///
+ /// Case sensitivity - Names are typically case-sensitive
+ /// Uniqueness - Each factory should have a unique name within the container
+ /// Stability - The name should remain constant throughout the factory's lifetime
+ /// Null handling - Names should not be null (use empty string for default if needed)
+ ///
+ ///
+ /// If multiple factories are registered with the same name, the behavior depends on the
+ /// dependency injection container implementation, but typically the last registered factory
+ /// will be used.
+ ///
+ ///
+ ///
+ ///
+ /// public class DatabaseTaskFlowFactory : INamedTaskFlowFactory
+ /// {
+ /// // This factory will be used when CreateTaskFlow("database") is called
+ /// public string Name => "database";
+ ///
+ /// public ITaskFlow Create(TaskFlowOptions options)
+ /// {
+ /// // Create task flow optimized for database operations
+ /// return new TaskFlow(options with { MaxConcurrency = 1 });
+ /// }
+ /// }
+ ///
+ ///
string Name { get; }
+ ///
+ /// Creates a new instance with the specified configuration options.
+ ///
+ /// The configuration options to use for creating the task flow instance.
+ /// A new instance configured according to this factory's implementation and the provided options.
+ /// Thrown when is null.
+ ///
+ ///
+ /// This method implements the core creation logic for this named factory. Unlike the default
+ /// factory, named factories can provide completely custom implementations, different task flow
+ /// types, or specialized configurations based on their intended purpose.
+ ///
+ ///
+ /// Implementation guidelines:
+ ///
+ ///
+ /// Options respect - Should honor relevant settings from the options parameter
+ /// Consistent behavior - Should create task flows with predictable characteristics
+ /// Resource management - Created task flows should support proper disposal
+ /// Thread safety - The factory method should be thread-safe for concurrent calls
+ ///
+ ///
+ /// Named factories can:
+ ///
+ ///
+ /// Create different task flow implementations (e.g., , )
+ /// Apply specific option modifications or defaults
+ /// Add decorators or wrappers for logging, monitoring, or other concerns
+ /// Integrate with external systems or configuration sources
+ ///
+ ///
+ /// The factory should not modify the provided options object directly, as it may be shared
+ /// across multiple factory calls. If option modifications are needed, create a copy or use
+ /// immutable update patterns.
+ ///
+ ///
+ ///
+ ///
+ /// public ITaskFlow Create(TaskFlowOptions options)
+ /// {
+ /// // Validate input
+ /// if (options == null)
+ /// throw new ArgumentNullException(nameof(options));
+ ///
+ /// // Create specialized task flow for this factory's purpose
+ /// ITaskFlow taskFlow = Name switch
+ /// {
+ /// "background" => new DedicatedThreadTaskFlow(options),
+ /// "ui" => new CurrentThreadTaskFlow(options),
+ /// "parallel" => new TaskFlow(options with { MaxConcurrency = Environment.ProcessorCount }),
+ /// _ => new TaskFlow(options)
+ /// };
+ ///
+ /// // Add any common decorators
+ /// if (_enableLogging)
+ /// {
+ /// taskFlow = new LoggingTaskFlowWrapper(taskFlow, _logger);
+ /// }
+ ///
+ /// return taskFlow;
+ /// }
+ ///
+ ///
ITaskFlow Create(TaskFlowOptions options);
}
}
\ No newline at end of file
diff --git a/TaskFlow.Extensions.Microsoft.DependencyInjection/ITaskFlowFactory.cs b/TaskFlow.Extensions.Microsoft.DependencyInjection/ITaskFlowFactory.cs
index f7fbcab..65a2fb0 100644
--- a/TaskFlow.Extensions.Microsoft.DependencyInjection/ITaskFlowFactory.cs
+++ b/TaskFlow.Extensions.Microsoft.DependencyInjection/ITaskFlowFactory.cs
@@ -1,7 +1,115 @@
namespace System.Threading.Tasks.Flow
{
+ ///
+ /// Defines a factory contract for creating instances with optional naming support.
+ ///
+ ///
+ ///
+ /// The interface provides a standardized way to create task flow instances
+ /// within dependency injection containers. It supports named instances, allowing multiple task flow
+ /// configurations to coexist within the same application.
+ ///
+ ///
+ /// This factory interface is the primary entry point for creating task flows in dependency injection
+ /// scenarios. It abstracts the complexity of:
+ ///
+ ///
+ /// Named configuration resolution
+ /// Custom factory delegation
+ /// Option configuration
+ /// Scheduler chain configuration
+ /// Default factory fallback
+ ///
+ ///
+ /// The factory supports multiple configuration patterns:
+ ///
+ ///
+ /// Default instances - Created with default options when no name is specified
+ /// Named instances - Created with specific configurations based on the provided name
+ /// Custom factories - Delegate to user-provided factory implementations
+ /// Chained schedulers - Apply scheduler wrapper chains for cross-cutting concerns
+ ///
+ ///
+ ///
+ /// Basic factory usage in dependency injection:
+ ///
+ /// // Register TaskFlow services
+ /// services.AddTaskFlow();
+ ///
+ /// // Inject and use the factory
+ /// public class SomeService
+ /// {
+ /// private readonly ITaskFlowFactory _taskFlowFactory;
+ ///
+ /// public SomeService(ITaskFlowFactory taskFlowFactory)
+ /// {
+ /// _taskFlowFactory = taskFlowFactory;
+ /// }
+ ///
+ /// public async Task ProcessDataAsync()
+ /// {
+ /// using var taskFlow = _taskFlowFactory.CreateTaskFlow();
+ /// await taskFlow.Enqueue(() => DoWorkAsync());
+ /// }
+ /// }
+ ///
+ ///
public interface ITaskFlowFactory
{
+ ///
+ /// Creates a new instance with the specified name or default configuration.
+ ///
+ ///
+ /// The optional name identifying which configuration to use. If null or empty,
+ /// the default configuration is used.
+ ///
+ ///
+ /// A new instance configured according to the specified name or default settings.
+ ///
+ ///
+ ///
+ /// This method creates task flow instances based on the configuration associated with the provided name.
+ /// The factory resolves the configuration through the following precedence:
+ ///
+ ///
+ /// Named factory - If a custom factory is registered for the name, it is used
+ /// Default factory - If no named factory exists, the default factory is used
+ /// Options configuration - Named options are applied if registered
+ /// Scheduler chains - Named scheduler chains are applied if registered
+ /// Fallback - Default options and configuration are used if nothing else is found
+ ///
+ ///
+ /// The name parameter supports:
+ ///
+ ///
+ /// null - Uses default configuration (equivalent to empty string)
+ /// Empty string - Uses default configuration
+ /// Named string - Uses configuration registered with that specific name
+ ///
+ ///
+ /// Created task flows should be properly disposed when no longer needed to ensure
+ /// resource cleanup and proper shutdown of any background operations.
+ ///
+ ///
+ /// If multiple configurations are registered with the same name, the behavior depends
+ /// on the specific registration order and DI container implementation. Generally,
+ /// the last registered configuration takes precedence.
+ ///
+ ///
+ ///
+ ///
+ /// // Create default task flow
+ /// using var defaultFlow = factory.CreateTaskFlow();
+ ///
+ /// // Create named task flow
+ /// using var namedFlow = factory.CreateTaskFlow("background-processor");
+ ///
+ /// // Both are equivalent for default configuration
+ /// using var flow1 = factory.CreateTaskFlow(null);
+ /// using var flow2 = factory.CreateTaskFlow("");
+ /// using var flow3 = factory.CreateTaskFlow();
+ ///
+ ///
ITaskFlow CreateTaskFlow(string? name = null);
}
}
\ No newline at end of file
diff --git a/TaskFlow.Extensions.Microsoft.DependencyInjection/ServiceCollectionExtensions.cs b/TaskFlow.Extensions.Microsoft.DependencyInjection/ServiceCollectionExtensions.cs
index f781432..d1a8d2f 100644
--- a/TaskFlow.Extensions.Microsoft.DependencyInjection/ServiceCollectionExtensions.cs
+++ b/TaskFlow.Extensions.Microsoft.DependencyInjection/ServiceCollectionExtensions.cs
@@ -5,13 +5,128 @@ namespace System.Threading.Tasks.Flow
using System.Threading.Tasks.Flow.Annotations;
using System.Threading.Tasks.Flow.Internal;
+ ///
+ /// Provides extension methods for to register TaskFlow services and configurations in dependency injection containers.
+ ///
+ ///
+ ///
+ /// The class serves as the primary entry point for integrating
+ /// TaskFlow with Microsoft's dependency injection system. It provides a comprehensive set of extension methods
+ /// that enable registration of task flow services with various configuration options and customization points.
+ ///
+ ///
+ /// Key registration features:
+ ///
+ ///
+ /// Default registration - Simple registration with default settings
+ /// Options-based registration - Registration with explicit configuration options
+ /// Named configurations - Support for multiple named task flow configurations
+ /// Custom factories - Integration with custom task flow creation logic
+ /// Scheduler chains - Configuration of cross-cutting concerns through wrapper chains
+ ///
+ ///
+ /// Service lifetime patterns:
+ ///
+ ///
+ /// Singleton factories - Configuration and factory services are registered as singletons
+ /// Scoped instances - Task flow instances are scoped to dependency injection scopes
+ /// Automatic disposal - Task flows are automatically disposed when scopes end
+ ///
+ ///
+ /// The extension methods register the following services:
+ ///
+ ///
+ /// - Factory for creating task flow instances
+ /// - Task scheduler interface implemented by scoped task flows
+ /// - Information interface implemented by scoped task flows
+ /// - Default factory for standard task flow creation
+ ///
+ ///
+ /// Note that itself is not registered directly. Instead, scoped wrapper
+ /// instances provide the and interfaces,
+ /// allowing controlled access to task flow functionality while ensuring proper lifecycle management.
+ ///
+ ///
public static class ServiceCollectionExtensions
{
+ ///
+ /// Adds TaskFlow services to the specified with default configuration.
+ ///
+ /// The to add TaskFlow services to.
+ /// The for method chaining.
+ /// Thrown when is null.
+ ///
+ ///
+ /// This is the simplest registration method that adds TaskFlow services with default settings.
+ /// It registers all necessary services for basic TaskFlow functionality without any custom configuration.
+ ///
+ ///
+ /// Services registered:
+ ///
+ ///
+ /// as singleton
+ /// as singleton
+ /// as scoped
+ /// as scoped
+ ///
+ ///
+ /// The scoped services provide access to a task flow instance that is created per dependency injection
+ /// scope and automatically disposed when the scope ends. This ensures proper resource management
+ /// and clean shutdown of background operations.
+ ///
+ ///
+ ///
+ ///
+ /// public void ConfigureServices(IServiceCollection services)
+ /// {
+ /// services.AddTaskFlow();
+ ///
+ /// services.AddScoped<MyService>();
+ /// }
+ ///
+ /// public class MyService
+ /// {
+ /// private readonly ITaskScheduler _scheduler;
+ ///
+ /// public MyService(ITaskScheduler scheduler)
+ /// {
+ /// _scheduler = scheduler;
+ /// }
+ ///
+ /// public Task DoWorkAsync() => _scheduler.Enqueue(() => ProcessDataAsync());
+ /// }
+ ///
+ ///
public static IServiceCollection AddTaskFlow(this IServiceCollection services)
{
return AddTaskFlow(services, name: null);
}
+ ///
+ /// Adds TaskFlow services to the specified with the specified options.
+ ///
+ /// The to add TaskFlow services to.
+ /// The to use for configuring the default task flow instances.
+ /// The for method chaining.
+ /// Thrown when or is null.
+ ///
+ ///
+ /// This method registers TaskFlow services with explicit configuration options that will be used
+ /// for all default task flow instances. The options are applied to the default (unnamed) configuration.
+ ///
+ ///
+ /// The provided options object is used directly, so it should not be modified after registration.
+ /// If you need different options for different scenarios, consider using named configurations instead.
+ ///
+ ///
+ ///
+ ///
+ /// services.AddTaskFlow(new TaskFlowOptions
+ /// {
+ /// SynchronousDisposeTimeout = TimeSpan.FromSeconds(30)
+ /// });
+ ///
+ ///
public static IServiceCollection AddTaskFlow(this IServiceCollection services, TaskFlowOptions options)
{
Argument.NotNull(options);
@@ -19,6 +134,39 @@ public static IServiceCollection AddTaskFlow(this IServiceCollection services, T
return AddTaskFlow(services, name: null, baseTaskFlowFactory: null, _ => options, configureSchedulerChain: null);
}
+ ///
+ /// Adds TaskFlow services to the specified with a named configuration and specified options.
+ ///
+ /// The to add TaskFlow services to.
+ /// The name to associate with this configuration. Must not be null or empty.
+ /// The to use for configuring task flow instances with this name.
+ /// The for method chaining.
+ /// Thrown when or is null.
+ /// Thrown when is null or empty.
+ ///
+ ///
+ /// This method registers a named configuration that can be accessed by calling
+ /// with the specified name. This enables
+ /// different parts of an application to use task flows with different configurations.
+ ///
+ ///
+ /// Named configurations are additive - you can register multiple named configurations and they
+ /// will coexist without interfering with each other or the default configuration.
+ ///
+ ///
+ ///
+ ///
+ /// // Register database configuration for single-threaded access
+ /// services.AddTaskFlow("database", new TaskFlowOptions { SynchronousDisposeTimeout = TimeSpan.FromSeconds(30) });
+ ///
+ /// // Register API configuration for high concurrency
+ /// services.AddTaskFlow("api", new TaskFlowOptions { SynchronousDisposeTimeout = TimeSpan.FromSeconds(10) });
+ ///
+ /// // Usage
+ /// var databaseFlow = factory.CreateTaskFlow("database");
+ /// var apiFlow = factory.CreateTaskFlow("api");
+ ///
+ ///
public static IServiceCollection AddTaskFlow(this IServiceCollection services, string name, TaskFlowOptions options)
{
Argument.NotEmpty(name);
@@ -27,6 +175,88 @@ public static IServiceCollection AddTaskFlow(this IServiceCollection services, s
return AddTaskFlow(services, name, baseTaskFlowFactory: null, _ => options, configureSchedulerChain: null);
}
+ ///
+ /// Adds TaskFlow services to the specified with comprehensive configuration options.
+ ///
+ /// The to add TaskFlow services to.
+ /// The optional name to associate with this configuration. If null, applies to the default configuration.
+ /// An optional custom factory function for creating the base task flow instances.
+ /// An optional function for configuring task flow options based on the service provider.
+ /// An optional function for configuring the scheduler chain to apply cross-cutting concerns.
+ /// The for method chaining.
+ /// Thrown when is null.
+ ///
+ ///
+ /// This is the most comprehensive registration method that provides full control over task flow creation
+ /// and configuration. It allows customization of every aspect of the task flow creation process through
+ /// the provided delegate functions.
+ ///
+ ///
+ /// Configuration precedence and application order:
+ ///
+ ///
+ /// is called to determine the options
+ /// is called to create the base task flow (or default factory if null)
+ /// is called to wrap the scheduler with additional functionality
+ ///
+ ///
+ /// All delegate functions receive the as a parameter, allowing them to
+ /// access other registered services for configuration purposes. This enables complex configuration
+ /// scenarios based on runtime conditions, configuration files, or other services.
+ ///
+ ///
+ /// Factory and chain delegates are only called when task flows are actually created, not during
+ /// service registration. This enables lazy evaluation and access to scoped services if needed.
+ ///
+ ///
+ ///
+ /// Custom factory with dependency injection:
+ ///
+ /// services.AddTaskFlow("custom",
+ /// baseTaskFlowFactory: (provider, options) => {
+ /// var logger = provider.GetRequiredService<ILogger<TaskFlow>>();
+ /// var taskFlow = new TaskFlow(options);
+ /// return new LoggingTaskFlowWrapper(taskFlow, logger);
+ /// });
+ ///
+ /// Dynamic options configuration:
+ ///
+ /// services.AddTaskFlow("adaptive",
+ /// configureOptions: provider => {
+ /// var config = provider.GetRequiredService<IConfiguration>();
+ /// var environment = provider.GetRequiredService<IWebHostEnvironment>();
+ ///
+ /// return new TaskFlowOptions
+ /// {
+ /// SynchronousDisposeTimeout = environment.IsDevelopment() ? TimeSpan.FromSeconds(30) : config.GetValue<int>("TaskFlow:SynchronousDisposeTimeout")
+ /// };
+ /// });
+ ///
+ /// Comprehensive scheduler chain:
+ ///
+ /// services.AddTaskFlow("robust",
+ /// configureSchedulerChain: (scheduler, provider) => {
+ /// var logger = provider.GetRequiredService<ILogger>();
+ /// var metrics = provider.GetRequiredService<IMetrics>();
+ /// var config = provider.GetRequiredService<IConfiguration>();
+ ///
+ /// var chain = scheduler
+ /// .WithOperationName("RobustOperation")
+ /// .WithTimeout(TimeSpan.FromSeconds(config.GetValue<int>("Timeout", 30)))
+ /// .OnError<Exception>(ex => {
+ /// logger.LogError(ex, "Operation failed");
+ /// metrics.IncrementCounter("errors");
+ /// });
+ ///
+ /// if (config.GetValue<bool>("EnableThrottling"))
+ /// {
+ /// chain = chain.WithDebounce(TimeSpan.FromMilliseconds(500));
+ /// }
+ ///
+ /// return chain;
+ /// });
+ ///
+ ///
public static IServiceCollection AddTaskFlow(
this IServiceCollection services,
string? name,
diff --git a/TaskFlow.Extensions.Microsoft.DependencyInjection/TaskFlowFactory.cs b/TaskFlow.Extensions.Microsoft.DependencyInjection/TaskFlowFactory.cs
index f9d003f..ea9aed2 100644
--- a/TaskFlow.Extensions.Microsoft.DependencyInjection/TaskFlowFactory.cs
+++ b/TaskFlow.Extensions.Microsoft.DependencyInjection/TaskFlowFactory.cs
@@ -5,6 +5,103 @@ namespace System.Threading.Tasks.Flow
using System.Threading.Tasks.Flow.Annotations;
using System.Threading.Tasks.Flow.Internal;
+ ///
+ /// Provides a comprehensive factory implementation for creating instances with support for named configurations, custom factories, and scheduler chains.
+ ///
+ ///
+ ///
+ /// The class serves as the central orchestrator for task flow creation in
+ /// dependency injection scenarios. It coordinates multiple configuration sources to create appropriately
+ /// configured task flow instances based on named configurations or default settings.
+ ///
+ ///
+ /// The factory implements a sophisticated resolution system that supports:
+ ///
+ ///
+ /// Named factories - Custom factory implementations for specific configurations
+ /// Named options - Configuration objects specific to named instances
+ /// Scheduler chains - Cross-cutting concern application through wrapper chains
+ /// Default fallback - Consistent behavior when no named configuration exists
+ ///
+ ///
+ /// Resolution algorithm:
+ ///
+ ///
+ /// Name normalization - Null names are converted to empty strings
+ /// Configuration lookup - Search for named factories, options, and chains
+ /// Options resolution - Use named options or fall back to defaults
+ /// Factory selection - Use named factory or default factory for creation
+ /// Chain application - Apply scheduler chains if configured
+ /// Wrapper creation - Create ownership wrapper if chains are applied
+ ///
+ ///
+ /// The factory is designed to work seamlessly with Microsoft's dependency injection container
+ /// and supports multiple named configurations within the same application. This enables different
+ /// parts of an application to use task flows with different characteristics and behaviors.
+ ///
+ ///
+ ///
+ /// Basic factory registration and usage:
+ ///
+ /// // Register TaskFlow services in dependency injection
+ /// services.AddTaskFlow();
+ ///
+ /// // Use the factory
+ /// public class DocumentProcessor
+ /// {
+ /// private readonly ITaskFlowFactory _factory;
+ ///
+ /// public DocumentProcessor(ITaskFlowFactory factory)
+ /// {
+ /// _factory = factory;
+ /// }
+ ///
+ /// public async Task ProcessDocumentAsync()
+ /// {
+ /// using var taskFlow = _factory.CreateTaskFlow();
+ /// await taskFlow.Enqueue(() => ProcessDocumentContentAsync());
+ /// }
+ /// }
+ ///
+ /// Named configuration setup:
+ ///
+ /// // Register multiple named configurations
+ /// services.AddTaskFlow("database", new TaskFlowOptions { ... });
+ /// services.AddTaskFlow("api", new TaskFlowOptions { ... });
+ /// services.AddTaskFlow("background",
+ /// configureSchedulerChain: (scheduler, provider) =>
+ /// scheduler.WithTimeout(TimeSpan.FromMinutes(30)));
+ ///
+ /// // Use named configurations
+ /// var databaseFlow = factory.CreateTaskFlow("database");
+ /// var apiFlow = factory.CreateTaskFlow("api");
+ /// var backgroundFlow = factory.CreateTaskFlow("background"); // With 30-minute timeout
+ ///
+ /// Custom factory and chain integration:
+ ///
+ /// // Custom named factory
+ /// public class UiTaskFlowFactory : INamedTaskFlowFactory
+ /// {
+ /// public string Name => "ui";
+ /// public ITaskFlow Create(TaskFlowOptions options) => new CurrentThreadTaskFlow(options);
+ /// }
+ ///
+ /// // Custom chain configuration
+ /// public class LoggingChain : INamedConfigureTaskFlowChain
+ /// {
+ /// public string Name => "ui";
+ /// public ITaskScheduler ConfigureChain(ITaskScheduler scheduler) =>
+ /// scheduler.OnError(ex => _logger.LogError(ex, "UI operation failed"));
+ /// }
+ ///
+ /// // Registration
+ /// services.AddSingleton<INamedTaskFlowFactory, UiTaskFlowFactory>();
+ /// services.AddSingleton<INamedConfigureTaskFlowChain, LoggingChain>();
+ ///
+ /// // Usage creates CurrentThreadTaskFlow with error logging
+ /// var uiFlow = factory.CreateTaskFlow("ui");
+ ///
+ ///
public class TaskFlowFactory : ITaskFlowFactory
{
private readonly IEnumerable _namedTaskFlowFactories;
@@ -12,6 +109,33 @@ public class TaskFlowFactory : ITaskFlowFactory
private readonly IEnumerable _namedConfigureTaskFlowOptions;
private readonly IDefaultTaskFlowFactory _defaultTaskFlowFactory;
+ ///
+ /// Initializes a new instance of the class with the specified configuration dependencies.
+ ///
+ /// A collection of named task flow factories for custom creation logic.
+ /// A collection of named scheduler chain configurations for applying cross-cutting concerns.
+ /// A collection of named options configurations for different task flow instances.
+ /// The default factory to use when no named factory is available.
+ /// Thrown when any of the parameters is null.
+ ///
+ ///
+ /// This constructor sets up the factory with all necessary dependencies for comprehensive task flow creation.
+ /// The dependencies are typically provided by the dependency injection container and represent the complete
+ /// configuration space for task flow creation.
+ ///
+ ///
+ /// Collection parameters can be empty but should not be null:
+ ///
+ ///
+ /// - Empty collection means no named factories are registered
+ /// - Empty collection means no scheduler chains are configured
+ /// - Empty collection means no named options are configured
+ ///
+ ///
+ /// The is required and serves as the fallback for creating
+ /// task flows when no named factory is available for a particular name.
+ ///
+ ///
public TaskFlowFactory(
IEnumerable namedTaskFlowFactories,
IEnumerable namedConfigureTaskFlowChains,
@@ -29,6 +153,63 @@ public TaskFlowFactory(
_defaultTaskFlowFactory = defaultTaskFlowFactory;
}
+ ///
+ /// Creates a new instance using the configuration associated with the specified name.
+ ///
+ ///
+ /// The optional name identifying which configuration to use. If null or empty,
+ /// the default configuration is used.
+ ///
+ ///
+ /// A new instance configured according to the specified name or default settings.
+ /// The returned instance may be wrapped with scheduler chains if configured.
+ ///
+ ///
+ ///
+ /// This method implements the core factory logic by orchestrating the resolution and application
+ /// of named configurations. The creation process follows these steps:
+ ///
+ ///
+ /// Name normalization - Converts null to empty string for consistent lookup
+ /// Configuration resolution - Searches for named factories, chains, and options
+ /// Options determination - Uses named options or defaults to TaskFlowOptions.Default
+ /// Base creation - Creates task flow using named factory or default factory
+ /// Chain application - Applies scheduler chain if one is configured for the name
+ /// Wrapper creation - Wraps with ownership wrapper if chains were applied
+ ///
+ ///
+ /// Resolution behavior:
+ ///
+ ///
+ /// Single match expected - Uses SingleOrDefault() to find configurations, expects at most one match per name
+ /// Graceful fallback - Missing named configurations result in default behavior rather than errors
+ /// Chain independence - Chains are applied regardless of whether a named factory was used
+ ///
+ ///
+ /// The method creates a new task flow instance on each call - it does not cache or reuse instances.
+ /// Callers are responsible for properly disposing the returned task flow instances.
+ ///
+ ///
+ /// If multiple configurations are registered with the same name, the SingleOrDefault() call will
+ /// throw an exception. This is by design to prevent ambiguous configuration scenarios.
+ ///
+ ///
+ ///
+ ///
+ /// // Create with default configuration
+ /// var defaultFlow = factory.CreateTaskFlow();
+ /// var alsoDefaultFlow = factory.CreateTaskFlow("");
+ /// var nullDefaultFlow = factory.CreateTaskFlow(null);
+ ///
+ /// // Create with named configuration
+ /// var databaseFlow = factory.CreateTaskFlow("database");
+ /// var apiFlow = factory.CreateTaskFlow("api");
+ ///
+ /// // All instances should be disposed when done
+ /// using var flow = factory.CreateTaskFlow("background");
+ /// await flow.Enqueue(() => DoWorkAsync());
+ ///
+ ///
public ITaskFlow CreateTaskFlow(string? name = null)
{
name ??= string.Empty;
diff --git a/TaskFlow/Extensions/AnnotatingTaskSchedulerExtensions.cs b/TaskFlow/Extensions/AnnotatingTaskSchedulerExtensions.cs
index 10a473e..f920562 100644
--- a/TaskFlow/Extensions/AnnotatingTaskSchedulerExtensions.cs
+++ b/TaskFlow/Extensions/AnnotatingTaskSchedulerExtensions.cs
@@ -3,8 +3,110 @@ namespace System.Threading.Tasks.Flow
using System.Linq;
using System.Threading.Tasks.Flow.Annotations;
+ ///
+ /// Provides extension methods for to add operation annotation capabilities.
+ ///
+ ///
+ ///
+ /// This class enables annotating task scheduler operations with metadata that can be used for
+ /// monitoring, debugging, error handling, and other cross-cutting concerns. Annotations are
+ /// attached to operations through extended state and can be retrieved by other extension methods
+ /// in the TaskFlow pipeline.
+ ///
+ ///
+ /// The annotation system works by:
+ ///
+ ///
+ /// Storing annotation data in extended state objects
+ /// Providing methods to enqueue operations with annotation access
+ /// Enabling retrieval of annotations by type in downstream operations
+ ///
+ ///
+ /// Common use cases include:
+ ///
+ ///
+ /// Adding operation names for logging and debugging
+ /// Storing correlation IDs for distributed tracing
+ /// Attaching user context for authorization
+ /// Providing metadata for monitoring and metrics
+ ///
+ ///
+ ///
+ /// Basic operation naming:
+ ///
+ /// ITaskScheduler scheduler = // ... obtain scheduler
+ ///
+ /// // Add operation name annotation
+ /// var namedScheduler = scheduler.WithOperationName("ProcessUserData");
+ ///
+ /// // Enqueue operation with annotation access
+ /// await namedScheduler.AnnotatedEnqueue<string, OperationNameAnnotation>(
+ /// (state, annotation, token) => {
+ /// Console.WriteLine($"Executing: {annotation?.OperationName}")
+ /// return ValueTask.FromResult("completed");
+ /// },
+ /// state: null,
+ /// CancellationToken.None);
+ ///
+ /// Custom annotation integration:
+ ///
+ /// public class UserContextAnnotation : IOperationAnnotation
+ /// {
+ /// public string UserId { get; set; }
+ /// public string Role { get; set; }
+ /// }
+ ///
+ /// var contextScheduler = scheduler.WithExtendedState(new UserContextAnnotation
+ /// {
+ /// UserId = "user123",
+ /// Role = "admin"
+ /// });
+ ///
+ /// await contextScheduler.AnnotatedEnqueue<void, UserContextAnnotation>(
+ /// (state, context, token) => {
+ /// if (context?.Role == "admin") {
+ /// // Execute admin operation
+ /// }
+ /// return ValueTask.CompletedTask;
+ /// },
+ /// state: null,
+ /// CancellationToken.None);
+ ///
+ ///
public static class AnnotatingTaskSchedulerExtensions
{
+ ///
+ /// Creates a task scheduler wrapper that attaches an operation name annotation to all enqueued tasks.
+ ///
+ /// The task scheduler to wrap with operation name annotation.
+ /// The name to associate with operations executed on this scheduler.
+ /// An that includes the operation name annotation in its extended state.
+ /// Thrown when is null, empty, or whitespace.
+ ///
+ ///
+ /// This method creates a wrapper scheduler that automatically attaches an
+ /// to all operations. The operation name can be retrieved by other extension methods in the TaskFlow pipeline,
+ /// such as error handlers, timeout handlers, and logging components.
+ ///
+ ///
+ /// The annotation is stored in the extended state and does not affect the core operation execution.
+ /// Multiple annotations can be layered by chaining extension methods.
+ ///
+ ///
+ ///
+ ///
+ /// ITaskScheduler scheduler = // ... obtain scheduler
+ ///
+ /// var namedScheduler = scheduler.WithOperationName("DataProcessing");
+ ///
+ /// // The operation name will be available to error handlers, timeout handlers, etc.
+ /// var result = await namedScheduler
+ /// .WithTimeout(TimeSpan.FromSeconds(30))
+ /// .OnError<TimeoutException>((sched, ex, name) =>
+ /// Console.WriteLine($"Operation '{name?.OperationName}' timed out"))
+ /// .Enqueue(() => ProcessDataAsync());
+ ///
+ ///
public static ITaskScheduler WithOperationName(this ITaskScheduler taskScheduler, string operationName)
{
Argument.NotEmpty(operationName);
@@ -12,6 +114,66 @@ public static ITaskScheduler WithOperationName(this ITaskScheduler taskScheduler
return taskScheduler.WithExtendedState(new OperationNameAnnotation( operationName));
}
+ ///
+ /// Enqueues a task function that can access annotation data attached to the scheduler.
+ ///
+ /// The type of result produced by the task function.
+ /// The type of annotation to retrieve and pass to the task function.
+ /// The task scheduler to enqueue the operation on.
+ /// The function to execute that accepts state, annotation, and cancellation token parameters.
+ /// An optional state object that is passed to the .
+ /// A cancellation token that can be used to cancel the operation.
+ /// A representing the result of the enqueued task function.
+ /// Thrown when or is null.
+ /// Thrown if the scheduler has been disposed.
+ ///
+ ///
+ /// This method provides a convenient way to enqueue operations that need access to annotation metadata.
+ /// The method automatically extracts the first annotation of type
+ /// from the scheduler's extended state and passes it to the task function.
+ ///
+ ///
+ /// The annotation parameter will be null if:
+ ///
+ ///
+ /// No annotation of the specified type is found in the extended state
+ /// The scheduler has no extended state
+ /// The annotation type doesn't match any stored annotations
+ ///
+ ///
+ /// Annotation resolution works by unwrapping nested extended state objects and looking for the
+ /// first match of the specified annotation type. This allows for complex annotation hierarchies
+ /// created by chaining multiple extension methods.
+ ///
+ ///
+ ///
+ ///
+ /// // Setup scheduler with multiple annotations
+ /// var scheduler = taskFlow
+ /// .WithOperationName("UserOperation")
+ /// .WithExtendedState(new CustomAnnotation { Priority = "High" });
+ ///
+ /// // Access operation name annotation
+ /// await scheduler.AnnotatedEnqueue<string, OperationNameAnnotation>(
+ /// (state, nameAnnotation, token) => {
+ /// var operationName = nameAnnotation?.OperationName ?? "Unknown";
+ /// Console.WriteLine($"Executing: {operationName}");
+ /// return ValueTask.FromResult("completed");
+ /// },
+ /// state: null,
+ /// CancellationToken.None);
+ ///
+ /// // Access custom annotation
+ /// await scheduler.AnnotatedEnqueue<void, CustomAnnotation>(
+ /// (state, customAnnotation, token) => {
+ /// var priority = customAnnotation?.Priority ?? "Normal";
+ /// Console.WriteLine($"Priority: {priority}");
+ /// return ValueTask.CompletedTask;
+ /// },
+ /// state: null,
+ /// CancellationToken.None);
+ ///
+ ///
public static Task AnnotatedEnqueue(this ITaskScheduler taskScheduler, Func