-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathINamedConfigureTaskFlowChain.cs
More file actions
239 lines (238 loc) · 12 KB
/
Copy pathINamedConfigureTaskFlowChain.cs
File metadata and controls
239 lines (238 loc) · 12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
namespace System.Threading.Tasks.Flow
{
/// <summary>
/// Defines a named configuration contract for applying scheduler chain modifications to named task flow instances.
/// </summary>
/// <remarks>
/// <para>
/// The <see cref="INamedConfigureTaskFlowChain"/> 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.
/// </para>
/// <para>
/// Scheduler chains provide:
/// </para>
/// <list type="bullet">
/// <item><strong>Cross-cutting concerns</strong> - Apply common functionality without modifying core logic</item>
/// <item><strong>Named customization</strong> - Different chains for different named instances</item>
/// <item><strong>Composition</strong> - Chain multiple schedulers together for complex behaviors</item>
/// <item><strong>Dependency injection integration</strong> - Access other services for chain configuration</item>
/// </list>
/// <para>
/// The chain configuration system integrates with:
/// </para>
/// <list type="bullet">
/// <item><see cref="INamedTaskFlowFactory"/> - Chains are applied after factory creation</item>
/// <item><see cref="INamedConfigureTaskFlowOptions"/> - Options are used before chain application</item>
/// <item>TaskFlow extension methods - Chains can use any scheduler extension methods</item>
/// </list>
/// <para>
/// Execution order:
/// </para>
/// <list type="number">
/// <item>Named or default factory creates the base task flow</item>
/// <item>Named chain configuration is applied to wrap the scheduler</item>
/// <item>The wrapped scheduler is used for all task operations</item>
/// </list>
/// <para>
/// Common chain use cases:
/// </para>
/// <list type="bullet">
/// <item>Adding timeout protection to API call task flows</item>
/// <item>Applying error handling and logging to background processing</item>
/// <item>Adding throttling to prevent resource exhaustion</item>
/// <item>Implementing retry logic for unreliable operations</item>
/// <item>Adding monitoring and metrics collection</item>
/// </list>
/// </remarks>
/// <example>
/// <para>Creating a named chain configuration:</para>
/// <code>
/// 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 }));
/// }
/// }
/// </code>
/// <para>Registering named chains:</para>
/// <code>
/// // 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"));
/// });
/// </code>
/// <para>Complex chain configuration:</para>
/// <code>
/// 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;
/// }
/// </code>
/// </example>
public interface INamedConfigureTaskFlowChain
{
/// <summary>
/// Gets the name that identifies this scheduler chain configuration.
/// </summary>
/// <value>
/// 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.
/// </value>
/// <remarks>
/// <para>
/// The name serves as the key for chain resolution in the dependency injection system.
/// When <see cref="ITaskFlowFactory.CreateTaskFlow(string?)"/> is called with a specific name,
/// the factory system searches for a registered <see cref="INamedConfigureTaskFlowChain"/> with a
/// matching <see cref="Name"/> property.
/// </para>
/// <para>
/// Name coordination considerations:
/// </para>
/// <list type="bullet">
/// <item><strong>Consistency</strong> - Should match names used in factories and options for coordinated configuration</item>
/// <item><strong>Case sensitivity</strong> - Names are typically case-sensitive</item>
/// <item><strong>Uniqueness</strong> - Each chain configuration should have a unique name within the container</item>
/// <item><strong>Stability</strong> - The name should remain constant throughout the configuration's lifetime</item>
/// </list>
/// <para>
/// 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.
/// </para>
/// </remarks>
/// <example>
/// <code>
/// 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"));
/// }
/// }
/// </code>
/// </example>
string Name { get; }
/// <summary>
/// Configures and returns a scheduler chain by wrapping the provided task scheduler with additional functionality.
/// </summary>
/// <param name="taskScheduler">The base task scheduler to wrap with additional functionality.</param>
/// <returns>An <see cref="ITaskScheduler"/> that wraps the original scheduler with the configured chain.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="taskScheduler"/> is <c>null</c>.</exception>
/// <remarks>
/// <para>
/// 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.
/// </para>
/// <para>
/// Chain configuration guidelines:
/// </para>
/// <list type="bullet">
/// <item><strong>Composition</strong> - Use TaskFlow extension methods to build the chain</item>
/// <item><strong>Order matters</strong> - The order of chained extensions affects behavior</item>
/// <item><strong>Preserve interface</strong> - Always return an ITaskScheduler implementation</item>
/// <item><strong>Resource management</strong> - Ensure proper disposal is supported throughout the chain</item>
/// </list>
/// <para>
/// Available extension methods for chaining include:
/// </para>
/// <list type="bullet">
/// <item><see cref="AnnotatingTaskSchedulerExtensions.WithOperationName(ITaskScheduler, string)"/> - Add operation naming</item>
/// <item><see cref="TimeoutTaskSchedulerExtensions.WithTimeout(ITaskScheduler, TimeSpan)"/> - Add timeout protection</item>
/// <item><see cref="ThrottlingTaskSchedulerExtensions.WithDebounce(ITaskScheduler, TimeSpan, TimeProvider?)"/> - Add debouncing</item>
/// <item><see cref="ExceptionTaskSchedulerExtensions.OnError{TException}(ITaskScheduler, Action{TException})"/> - Add error handling</item>
/// <item><see cref="CancellationScopeTaskSchedulerExtensions.CreateCancellationScope(ITaskScheduler, CancellationToken)"/> - Add cancellation scopes</item>
/// <item><see cref="CancelPreviousTaskSchedulerExtensions.CreateCancelPrevious(ITaskScheduler)"/> - Add cancel-previous behavior</item>
/// </list>
/// <para>
/// The method can access dependency injection services to configure the chain based on runtime conditions,
/// configuration settings, or other application state.
/// </para>
/// <para>
/// 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.
/// </para>
/// </remarks>
/// <example>
/// <code>
/// 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;
/// }
/// </code>
/// </example>
ITaskScheduler ConfigureChain(ITaskScheduler taskScheduler);
}
}