后端工作流自动化流程编排【免费下载链接】workflow-coreLightweight workflow engine for .NET Standard项目地址https://gitcode.com/gh_mirrors/wo/workflow-core点击查看免费下载导读本文以 Workflow Core 1.2.8 的官方发布说明为骨架深入讲解该版本引入的四个核心能力——.Schedule()未来时刻并行分支、.Delay()分支休眠、可访问上下文对象的.Input()重载以及内联 Action 步骤 API并结合仓库源码Schedule.cs、Delay.cs、StepBuilder.cs与集成测试DelayScenario.cs剖析其底层实现原理帮你彻底掌握这四类时间控制与精简建模技巧并能直接照搬到自己的工作流中。同时梳理 1.2.8 停止支持 .NET 4.5.2 的兼容性变化。Workflow Core 是一款面向 .NET Standard 的轻量级工作流引擎。版本 1.2.8 是其在时间控制能力上的一次重要补强此前用户只能依赖自定义 StepBody 内部编写ExecutionResult.Sleep(...)来实现延迟而 1.2.8 把「按需定时」和「分支休眠」做成了开箱即用的流式 API并大幅简化了步骤的编写方式。下面逐项展开。一、.Schedule()把一段步骤调度到未来并行执行1.2.8 最重磅的新增是.Schedule()API。它的语义是将一段子步骤块「预约」到未来的某个时刻届时与工作流的其余部分并行运行。也就是说调度子块不会阻塞主流程——主流程继续向下执行被调度的块在到达指定时间点后才开始独立运行。官方发布说明给出的示例是 3 天后执行一个步骤块builder .StartWithHelloWorld() .Schedule(data TimeSpan.FromDays(3)).Do(block block.StartWithDoSomething() .ThenDoSomethingElse()) .ThenGoodbyeWorld();1. 调度时长的两种写法.Schedule()接收的参数是ExpressionFuncTData, TimeSpan因此调度时长既可以写死如TimeSpan.FromDays(3)也可以根据工作流数据动态计算如data data.DueIn。这一点与延迟时长、循环间隔的写法完全一致。仓库中的真实示例见 ScheduleWorkflow.cs它展示了更短的调度周期builder .StartWith(context Console.WriteLine(Hello)) .Schedule(data TimeSpan.FromSeconds(5)).Do(schedule schedule .StartWith(context Console.WriteLine(Doing scheduled tasks)) ) .Then(context Console.WriteLine(Doing normal tasks));可以看到Schedule(...)之后必须紧跟.Do(...)来定义被调度的子块.Do返回的 builder 会自动跳回调度点之后的主流程即接着写.Then(...)继续主分支这正是ReturnStepBuilderTData, Schedule, TStepBody的设计目的见 ReturnStepBuilder.cs 的Do方法。2. 底层实现原理.Schedule()对应的步骤类型是 Schedule.cs 中的Schedule : ContainerStepBody它有三个关键字段Interval由.Schedule()的表达式通过 StepBuilder.cs 中的MemberMapParameter映射注入见该方法实现ExpressionFuncSchedule, TimeSpan inputExpr (x x.Interval)SchedulePersistenceDataSchedulePersistenceData.cs仅含一个Elapsed布尔标志用于记录「定时是否已到期」。其Run方法的状态机非常清晰三次执行完成整个生命周期首次执行PersistenceData null返回ExecutionResult.Sleep(Interval, new SchedulePersistenceData { Elapsed false })即把当前执行指针「睡」到未来时间并记录Elapsed false。到期后再次执行Elapsed false返回ExecutionResult.Branch(new Listobject { context.Item }, new SchedulePersistenceData { Elapsed true })通过分支Branch机制把子块步骤激活——子块从此并行运行此时主流程的执行指针早已越过调度点继续前进。子块完成后第三次执行IsBranchComplete为 true返回ExecutionResult.Next()调度块正式收尾。如果子块尚未完成则返回ExecutionResult.Persist(...)保持挂起等待下一轮执行。整个状态流转依赖ExecutionResult.Sleep/Branch/Persist这三种静态工厂方法定义见 ExecutionResult.cs。3. 「睡到未来」是如何被唤醒的Sleep会把SleepUntil时间戳写到执行指针上见 ExecutionResultProcessor.cs其中pointer.SleepUntil _datetimeProvider.UtcNow.Add(result.SleepFor.Value); pointer.Status PointerStatus.Sleeping;。后台的RunnablePoller会按WorkflowOptions.PollInterval默认 10 秒见 WorkflowOptions.cs周期性地调用GetRunnableInstances(DateTime)找出所有SleepUntil已到期的实例并入队执行RunnablePoller.cs。也就是说Schedule/Delay 的触发精度取决于轮询间隔默认约 10 秒的延迟容忍度可通过UsePollInterval(...)调小以换取更高触发频率。二、.Delay()让当前分支「睡」指定时长如果说.Schedule()是旁路并行调度那么.Delay()则是在当前执行分支上原地等待工作流走到该步骤后暂停指定时间时间一到继续往下走。发布说明示例builder .StartWithHelloWorld() .Delay(data TimeSpan.FromMinutes(5)) .ThenGoodbyeWorld();与Schedule相同延迟时长也支持数据驱动data data.WaitTime之类的表达式均可。二者的本质区别在于Delay 是串行语义Schedule 是并行语义——Delay 等待期间主流程不会推进Schedule 等待期间主流程照常执行。1. 底层实现原理.Delay()对应的步骤类型是 Delay.cs 中的Delay : StepBody实现极其简洁public override ExecutionResult Run(IStepExecutionContext context) { if (context.PersistenceData ! null) return ExecutionResult.Next(); return ExecutionResult.Sleep(Period, true); }第一次执行返回Sleep(Period, true)挂起当前指针被RunnablePoller唤醒后的下一次执行PersistenceData ! null直接返回Next()继续后续步骤。Period属性由 StepBuilder.cs 的Delay方法通过MemberMapParameter注入。2. 集成测试验证仓库的 DelayScenario.cs 对 Delay 行为做了完整验证它构建了「Step1 → Delay(WaitTime) → Step2」的工作流将WaitTime设为PollInterval 1 秒断言最终工作流状态为Complete、无未处理错误、且两个步骤各自恰好执行一次var workflowId StartWorkflow(new DelayWorkflow.MyDataClass() { WaitTime Host.Options.PollInterval.Add(TimeSpan.FromSeconds(1)) }); WaitForWorkflowToComplete(workflowId, TimeSpan.FromSeconds(30)); GetStatus(workflowId).Should().Be(WorkflowStatus.Complete); UnhandledStepErrors.Count.Should().Be(0); DelayWorkflow.Step1Ticker.Should().Be(1); DelayWorkflow.Step2Ticker.Should().Be(1);这组断言同时验证了「延迟确实生效」Step2 不会在 Step1 后立即执行与「唤醒后流程正确继续」Step2 最终恰好执行一次。若你要基于 WorkflowTest.cs 编写时间相关测试这个场景是很好的模板——注意把等待时长与PollInterval关联起来避免测试抖动。3. 与自定义 Sleep 步骤的对比在 1.2.8 之前实现延迟的标准做法是手写一个像 SleepStep.cs 这样的步骤public class SleepStep : StepBody { public TimeSpan Period { get; set; } public override ExecutionResult Run(IStepExecutionContext context) { if (context.PersistenceData null) return ExecutionResult.Sleep(Period, new object()); else return ExecutionResult.Next(); } }这正是 DeferSampleWorkflow.cs 中Sample05演示的延迟思路。.Delay()出现后这段样板代码可以被一行流式调用取代二者底层机制完全一致都是Sleep 持久化标记.Delay()只是把模板封装进了引擎。三、.Input()新重载在表达式中访问执行上下文1.2.8 为.Input()增加了第二个重载允许数据映射表达式同时接收工作流数据和步骤执行上下文IStepExecutionContext。发布说明中的示例展示了它在ForEach场景下的价值——直接读取上下文中的当前迭代项context.Itembuilder .StartWithSayHello() .ForEach(data new Listint() { 1, 2, 3, 4 }) .Do(x x .StartWithDisplayContext() .Input(step step.Item, (data, context) context.Item) .ThenDoSomething()) .ThenSayGoodbye();1. 两个重载的分工对照 StepBuilder.cs 可以看到.Input()的两个成员映射重载// 旧签名只能从工作流数据取值 public IStepBuilderTData, TStepBody InputTInput( ExpressionFuncTStepBody, TInput stepProperty, ExpressionFuncTData, TInput value) // 1.2.8 新增可从 (data, context) 二元组取值 public IStepBuilderTData, TStepBody InputTInput( ExpressionFuncTStepBody, TInput stepProperty, ExpressionFuncTData, IStepExecutionContext, TInput value)2. 底层如何区分两种表达式两个重载最终都会创建MemberMapParameterMemberMapParameter.cs。在它的Assign方法中根据源表达式的参数个数决定求值方式switch (_source.Parameters.Count) { case 1: resolvedValue _compiledSource.DynamicInvoke(sourceObject); break; case 2: resolvedValue _compiledSource.DynamicInvoke(sourceObject, context); break; default: throw new ArgumentException(); }即单参表达式data ...只接收数据对象双参表达式(data, context) ...会额外注入IStepExecutionContext。IStepExecutionContext定义于 IStepExecutionContext.cs暴露了Item、ExecutionPointer、PersistenceData、Step、Workflow、CancellationToken等成员。其中context.Item在ForEach、Schedule、Parallel、Recur等容器步骤中代表「当前分支正在处理的条目」——这正是上面示例里迭代当前项的数据来源context.ExecutionPointer当前执行指针可用于读取SleepUntil、ContextItem、Children等状态见 ExecutionPointer.cscontext.PersistenceData步骤挂起期间持久化的数据。这也解释了为什么ForEachForeach.cs在分支时要把每个迭代项通过ExecutionResult.Branch(values, ...)传入子指针再由子步骤通过context.Item取回。新版.Input()让「取当前项」从「先写自定义步骤再依赖IStepBody内部逻辑」变成了纯声明式映射。提示ForEach默认RunParallel true见 Foreach.cs即各迭代分支并行执行若需要串行逐个迭代可改用带runParallel参数的重载StepBuilder.cs。四、内联 Action 步骤一行 Lambda 搞定简单逻辑1.2.8 还引入了内联步骤 API让你无需为「打印一行日志」「调用一个方法」这类简单逻辑单独定义 StepBody 类builder .StartWith(context Console.WriteLine(Hello!)) .Then(context Console.WriteLine(Bye!));1. 两种内联形式的区分在 StepBuilder.cs 中Then根据 Lambda 返回类型被重载分派到两条路径Then(ActionIStepExecutionContext body)无返回值void的 Lambda包装为ActionStepBody。其Run直接调用Body(context)并返回ExecutionResult.Next()见 ActionStepBody.cs。上面的context Console.WriteLine(...)走的就是这条路径。Then(FuncIStepExecutionContext, ExecutionResult body)返回ExecutionResult的 Lambda包装为WorkflowStepInline/InlineStepBody见 WorkflowStepInline.cs 与 InlineStepBody.cs。InlineStepBody.Run原样调用委托并返回其结果因此这类内联步骤可以自由控制流程走向Next()、Sleep(...)、Branch(...)、WaitForEvent(...)等。一个直观的对照StartWith(context Console.WriteLine(Workflow started))如果想让内联步骤具备返回值语义写法是StartWith(context { Console.WriteLine(...); return ExecutionResult.Next(); })——这正是 DeferSampleWorkflow.cs 中采用的模式。2. 内联步骤的适用边界适合日志输出、简单赋值、调用单条方法、快速原型验证、测试桩不适合需要复杂输入输出映射、需要依赖注入的服务步骤、需要补偿CompensateWith的业务步骤——这类场景仍应定义独立的IStepBody类保持可测试性与可复用性。值得注意的是内联 Action 并非只能用于「叶步骤」——StepBuilder.cs 还提供了CompensateWith(ActionIStepExecutionContext body)与CompensateWith(FuncIStepExecutionContext, ExecutionResult body)两个重载意味着补偿逻辑同样可以用内联 Lambda 定义。五、.NET 4.5.2 支持终止兼容性变化说明1.2.8 的另一项重要变化是停止支持 .NET Framework 4.5.2。发布说明原文的说明是.NET 4.6与.NET Standard 1.3兼容。含义如下自 1.2.8 起使用 .NET Framework 4.5.2 的项目无法再引用该版本最低可用的传统 .NET Framework 目标提升到 4.6其与 .NET Standard 1.3 具备 API 兼容性面向现代 .NET如 .NET 6/7/8/9的项目不受影响因为 .NET 5 原生实现 .NET Standard 2.0 规范。如果你的项目仍在 .NET Framework 4.5.2 上升级路径是先迁移到 .NET Framework 4.6再升级 Workflow Core 到 1.2.8 及以后版本如果必须停留在 4.5.2则应锁定 1.2.8 之前的版本。相关框架信息可在 WorkflowCore.csproj 中核对当前目标框架。六、版本特性速查与实战要点小结特性API语义核心实现类/文件典型使用场景定时并行分支.Schedule(ts).Do(block)未来时刻启动子块与主流程并行Schedule.cs延迟通知、定时任务、限时审批提醒分支休眠.Delay(ts)当前分支原地等待后继续Delay.cs冷却时间、节流、业务等待上下文感知输入.Input(p, (data, context) ...)数据映射可读取执行上下文StepBuilder.csForEach 中取context.Item等内联步骤.StartWith(Action)/.Then(Func)无需自定义类即可写步骤ActionStepBody.cs / InlineStepBody.cs日志、轻量操作、快速原型兼容性变化—停止支持 .NET 4.5.2WorkflowCore.csproj老框架项目升级前需确认三条实战建议触发精度与轮询间隔强相关Schedule/Delay 的到期检查由RunnablePoller按PollInterval默认 10 秒驱动。对触发时间要求较高的场景可用services.AddWorkflow(x x.UsePollInterval(TimeSpan.FromSeconds(1)))调低轮询间隔代价是数据库/存储层查询频率上升。持久化保障Sleep 状态SleepUntilPersistenceData会被持久化提供程序保存因此工作流进程重启后睡着的步骤会按原定时间点继续不会丢失进度——前提是你配置了持久化提供程序如 SQL Server/MySQL/PostgreSQL/MongoDB 等见 providers 目录下的各实现。组合使用.Schedule()与.Recur()是近亲——Recur(data TimeSpan.FromSeconds(5), data data.Counter 5).Do(...)见 RecurSampleWorkflow.cs在 1.2.8 的后续版本中提供周期性执行语义当需求从「定时一次」演变为「周期反复」时可直接切换为 Recur 模式。以上特性均可在 ReleaseNotes 目录的版本记录中溯源相关示例与测试可在 samples 与 test/WorkflowCore.IntegrationTests/Scenarios 下找到供你在实际项目中参考和扩展。赞分享后端工作流自动化流程编排【免费下载链接】workflow-coreLightweight workflow engine for .NET Standard项目地址https://gitcode.com/gh_mirrors/wo/workflow-core点击查看免费下载相关推荐KubeVela restart-workflow 工作流步骤详解实现定时任务、延迟执行与周期性编排KubeVela restart workflow 工作流步骤详解实现定时任务、延迟执行与周期性编排 本文以 KubeVela 内置工作流步骤 restart云原生DevOps运维微服务Lodash异步延迟执行终极指南defer与delay的实战应用技巧Lodash异步延迟执行终极指南defer与delay的实战应用技巧 Lodash是一个强大的现代JavaScript实用工具库提供了模块化、高性能和额外功前端后端fre:ac 免费开源音频转换器完整指南从CD抓轨到批量转码的实战手册fre:ac 免费开源音频转换器完整指南从CD抓轨到批量转码的实战手册 还在为下载的 FLAC 无损音频在手机上无法播放而发愁还在为一摞老旧 CD 无法数字音视频桌面应用上一篇NTRIP协议终极指南快速构建高精度定位系统的完整教程下一篇青龙面板脚本自动化完全指南5分钟快速配置滑稽脚本库创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考 SEO 优化官网定制响应式建站教育培训建站