ABP VNext + Elsa Workflow:实现可视化流程引擎

🚀 ABP VNext + Elsa Workflow:实现可视化流程引擎 🎉



1. 背景与动机 🤔

在大型企事业单位中,请假报销工单等审批流程往往跨越多部门、多层级,硬编码实现难以维护。
可视化流程引擎 能让业务人员通过拖拽定义流程,开发人员只需聚焦节点扩展与平台集成。

应用平台
可视化引擎
业务需求
ABP VNext
Elsa Workflows
请假审批
报销流程
工单流转

2. 核心技术点 🌟

2.1 安装所需 NuGet 包 📦

dotnet add package Elsa.Workflows.Core
dotnet add package Elsa.Activities.Http
dotnet add package Elsa.Activities.Console
dotnet add package Elsa.Activities.UserTask
dotnet add package Elsa.Persistence.EntityFramework.Core
dotnet add package Elsa.Persistence.EntityFramework.PostgreSql
dotnet add package Elsa.Metrics.Prometheus
dotnet add package Microsoft.EntityFrameworkCore.Design

如需其他数据库,替换对应的 EF 提供器包即可。


2.2 ABP Module 中集成 Elsa 🔗

[DependsOn(
    typeof(AbpAspNetCoreMvcModule),
    typeof(AbpDistributedLockingModule)
)]
public class MyCompanyWorkflowModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        var configuration = context.Services.GetConfiguration();

        context.Services
            .AddElsa(elsa => elsa
                // 持久化配置
                .UseEntityFrameworkPersistence(ef => ef
                    .UseNpgsql(configuration.GetConnectionString("Default"))
                    .UseJsonSerializer()
                    .UseTablePrefix("Elsa_"))
                // 内置活动
                .AddConsoleActivities()
                .AddHttpActivities(ops => ops
                    .WithClientFactory("RetryClient", client => client
                        .ConfigureHttpClient(c => c.Timeout = TimeSpan.FromSeconds(10))
                        .AddPolicyHandler(Policy
                            .Handle<HttpRequestException>()
                            .WaitAndRetryAsync(3, _ => TimeSpan.FromSeconds(2)))))
                // 自定义活动
                .AddActivity<SendNotificationActivity>())
            .AddElsaApiEndpoints();
    }
}
Elsa 引擎
ABP 应用
Http Activities
Console Activities
SendNotificationActivity
持久化 (PostgreSQL)
DI 容器
MyCompanyWorkflowModule
Elsa Services

2.3 Workflow Definition DSL 📝

{
  "Activities": [
    { "Type": "Elsa.Activities.Http.HttpEndpoint", "Id": "start",
      "Properties": { "Path": "/api/workflows/leave", "Method": "POST" } },
    { "Type": "Elsa.Activities.UserTask.UserTask", "Id": "deptApproval",
      "Properties": { "Title": "部门审批" } },
    { "Type": "Elsa.Activities.UserTask.UserTask", "Id": "hrApproval",
      "Properties": { "Title": "HR 审批" } },
    { "Type": "Elsa.Activities.Http.HttpResponse", "Id": "end",
      "Properties": { "Content": "审批完成" } }
  ],
  "Connections": [
    { "Source": "start",       "Target": "deptApproval" },
    { "Source": "deptApproval", "Target": "hrApproval"   },
    { "Source": "hrApproval",   "Target": "end"          }
  ]
}

Elsa 2.3+ 支持 Connections,低版本请参考 Outcome


2.4 自定义 Activity 示例 ⚙️

public class SendNotificationActivity : Activity
{
    private readonly ILogger<SendNotificationActivity> _logger;
    public SendNotificationActivity(ILogger<SendNotificationActivity> logger) =>
        _logger = logger;

    protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context)
    {
        try
        {
            var dto = context.GetInput<LeaveRequest>();
            var notifier = context.ServiceProvider
                                 .GetRequiredService<INotificationPublisher>();
            notifier.PublishAsync("LeaveApproved", dto);
            return Done();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "通知发送失败");
            return Fault(ex);
        }
    }
}

2.5 持久化、审计与监控 📊

2.5.1 EF Core 迁移 🛠️
dotnet ef migrations add Elsa_Init -c ElsaContext -o Migrations/Elsa
dotnet ef database update -c ElsaContext
2.5.2 审计日志关联 📝
Configure<AbpAuditingOptions>(options =>
{
    options.EntityHistorySelectors.Add<WorkflowInstance>(selector =>
        selector.Include(x => x.Id)
                .Include(x => x.Status)
                .Include(x => x.Variables));
});
2.5.3 Prometheus & Grafana 📈
services.AddElsaMetrics(metrics => metrics.AddPrometheus());
// appsettings.Production.json
{
  "Metrics": {
    "Prometheus": {
      "Enabled": true
    }
  }
}
# prometheus.yml
scrape_configs:
  - job_name: 'elsa'
    static_configs:
      - targets: ['localhost:5000']
Prometheus 抓取 /metrics
时序数据库
Grafana 可视化
监控面板

3. 实战演示:“请假审批”流程 🚀

客户端 POST /api/workflows/leave
LeaveController.StartLeaveWorkflow
Elsa HTTP 活动触发
引擎执流程
PostgreSQL 保存状态
ABP 审计日志
[Authorize]
[ApiController]
[Route("api/workflows")]
public class LeaveController : ControllerBase
{
    private readonly IWorkflowRunner _workflowRunner;
    public LeaveController(IWorkflowRunner workflowRunner) =>
        _workflowRunner = workflowRunner;

    [HttpPost("leave")]
    public async Task<IActionResult> StartLeaveWorkflow([FromBody] LeaveRequest dto)
    {
        var wfInstance = await _workflowRunner
            .TriggerAsync("LeaveWorkflow", new Variables(dto));
        return Ok(new { WorkflowInstanceId = wfInstance.Id });
    }
}

4. 优化指南 🔧

4.1 配置分层与安全 🔒

  • 分层管理:将连接串、Prometheus 配置分别放在 appsettings.Development.json / appsettings.Production.json,并通过 IConfiguration.GetSection(...) 读取。
  • Secret 管理:生产环境使用环境变量、Azure Key Vault 或 HashiCorp Vault 管理敏感信息,避免硬编码。

4.2 异常处理与超时 ⏱️

  • 在自定义 Activity 中捕获异常并返回 Fault(ex)
  • 在 HTTP 活动中通过 ConfigureHttpClient(c => c.Timeout = ...) 设置超时,结合 Polly 实现重试。

4.3 单元测试 & 端到端测试 🧪

[Fact]
public void SendNotificationActivity_Should_Done()
{
    var services = new ServiceCollection()
        .AddSingleton<INotificationPublisher, FakePublisher>()
        .BuildServiceProvider();

    var context = new ActivityExecutionContext(/*...*/, services);
    var activity = new SendNotificationActivity(
        services.GetService<ILogger<SendNotificationActivity>>());
    var result = activity.OnExecute(context);
    Assert.IsType<DoneResult>(result);
    Assert.True(((FakePublisher)services.GetService<INotificationPublisher>()).WasCalled);
}

端到端测试可使用 InMemoryProvider 启动流程,验证各节点执行顺序与结果。

4.4 版本兼容与升级路线 🚀

  • Elsa v3 预览:关注 JSON 架构、API 调用变化。
  • ABP 升级:小版本间 DI、Module 生命周期可能有细微差异,建议锁定兼容范围。

4.5 健康检查与日志聚合 🏥

services.AddHealthChecks()
    .AddDbContextCheck<ElsaContext>("Elsa DB")
    .AddCheck<CustomQueueHealthCheck>("消息队列");

使用 Serilog + Seq/ELK 汇总 Elsa 运行时日志,便于异常排查。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kookoos

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值