| | | 1 | | namespace Anichron.Worker.Ingestion.Pipeline; |
| | | 2 | | |
| | | 3 | | internal static partial class IngestionPipelineBuilder |
| | | 4 | | { |
| | | 5 | | internal static IngestionDelegate Build(IReadOnlyList<IIngestionMiddleware> middlewares, ILogger logger) |
| | 31 | 6 | | { |
| | 31 | 7 | | IngestionDelegate pipeline = static (_, _) => Task.CompletedTask; |
| | | 8 | | |
| | | 9 | | // Build right-to-left so the composed chain runs left-to-right: |
| | | 10 | | // wrapping middleware[n-1] first means middleware[0] is the outermost caller. |
| | 183 | 11 | | foreach (var middleware in middlewares.Reverse()) |
| | 45 | 12 | | { |
| | | 13 | | // Capture 'pipeline' before reassignment — without this all lambdas would |
| | | 14 | | // close over the final value of the outer variable, not this iteration's. |
| | 45 | 15 | | var next = pipeline; |
| | 45 | 16 | | pipeline = async (context, ct) => |
| | 45 | 17 | | { |
| | 45 | 18 | | if (!middleware.CanInvoke(context)) |
| | 45 | 19 | | { |
| | 45 | 20 | | Log.StepSkipped(logger, middleware.GetType().Name); |
| | 45 | 21 | | await next(context, ct); |
| | 45 | 22 | | return; |
| | 45 | 23 | | } |
| | 45 | 24 | | |
| | 45 | 25 | | Log.StepStarted(logger, middleware.GetType().Name); |
| | 45 | 26 | | await middleware.InvokeAsync(context, next, ct); |
| | 45 | 27 | | }; |
| | 45 | 28 | | } |
| | | 29 | | |
| | 31 | 30 | | return pipeline; |
| | 31 | 31 | | } |
| | | 32 | | |
| | | 33 | | private static partial class Log |
| | | 34 | | { |
| | | 35 | | [LoggerMessage(Level = LogLevel.Debug, Message = "-> {MiddlewareName}")] |
| | | 36 | | public static partial void StepStarted(ILogger logger, string middlewareName); |
| | | 37 | | |
| | | 38 | | [LoggerMessage(Level = LogLevel.Trace, Message = "-- {MiddlewareName} (skipped)")] |
| | | 39 | | public static partial void StepSkipped(ILogger logger, string middlewareName); |
| | | 40 | | } |
| | | 41 | | } |