You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Elsa Workflow中按条件停止Timer并实现3次间隔提醒后终止

Elsa Workflow 提醒邮件与自动终止实现问题

我是Elsa Workflow新手,表述不当之处请见谅。我已自定义了文档审批工作流,目前运行正常。现在需要实现以下场景:

  • 仅发送3次不同间隔的提醒邮件:
    1. 首次提醒:审批邮件发送1小时后
    2. 第二次提醒:审批邮件发送5小时后
    3. 第三次提醒:审批邮件发送24小时后
  • 第三次提醒后再等待24小时,若仍无响应则取消工作流或标记为故障
  • 提醒次数不得超过3次,最终工作流需终止为故障或取消状态

我已创建自定义方法GetTimerValue()和CheckReminderLimitReached(),通过本地文件存储计数器(不使用数据库)跟踪提醒发送次数:

  • GetTimerValue():根据当前计数器值返回对应提醒的Duration并将计数器加1
  • CheckReminderLimitReached():返回计数器是否达到上限

我尝试了如下代码但未能实现需求,已卡5天,恳请帮助。


项目信息

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Elsa" Version="2.13.0" />
    <PackageReference Include="Elsa.Activities.Email" Version="2.13.0" />
    <PackageReference Include="Elsa.Activities.Http" Version="2.13.0" />
    <PackageReference Include="Elsa.Activities.Temporal.Quartz" Version="2.13.0" />
    <PackageReference Include="Elsa.Designer.Components.Web" Version="2.13.0" />
    <PackageReference Include="Elsa.Persistence.EntityFramework.Sqlite" Version="2.13.0" />
    <PackageReference Include="Elsa.Scripting.JavaScript" Version="2.13.0" />
    <PackageReference Include="Elsa.Scripting.Liquid" Version="2.13.0" />
    <PackageReference Include="Elsa.Server.Api" Version="2.13.0" />
    <PackageReference Include="Microsoft.Extensions.Logging.Log4Net.AspNetCore" Version="7.0.0" />
  </ItemGroup>

  <ItemGroup>
    <Folder Include="Utility\" />
  </ItemGroup>

  <ItemGroup>
    <Content Update="log4net.config">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

</Project>

尝试的工作流代码

fork
  .When("Remind")
  //.Timer(Duration.FromSeconds(0)).WithName("Reminder")
  //.IfTrue(CheckReminderLimitReached,context=>context.ThenNamed("Reminder").WorkflowBuilder.Finish())
  //.IfFalse(CheckReminderLimitReached)

  //.If(context => CheckReminderLimitReached(context))
  //    .When("true")
  //        .CancelTimer(context => context.ActivityId).Break()
  
  .Timer(context => GetTimerValue(context)).WithName("Reminder")
  .If(context=> CheckReminderLimitReached(context)).When("true").Timer().CancelTimer(context => context.ActivityId).Finish()
  .SendEmail( // some code
)

自定义方法代码

private bool CheckReminderLimitReached(ActivityExecutionContext context)
{
    string ticketId = context.GetVariable<ApprovalRequestModel>("Approval")!.ticket_id!;
    string path = $"C:\\Apps\\DotNet\\UatTickets\\{ticketId}\\rem_counter.txt";

    var content = string.Empty;
    var reminders = 0;
    if (File.Exists(path))
    {
       content = File.ReadAllText(path);
    }

    if (!string.IsNullOrEmpty(content))
    {
       reminders = Int32.Parse(content);
    }

    bool result = reminders == 3;
    return result;
    
}

private Duration GetTimerValue(ActivityExecutionContext context)
{
    
    string ticketId = context.GetVariable<ApprovalRequestModel>("Approval")!.ticket_id!;
    string path = $"C:\\Apps\\DotNet\\UatTickets\\{ticketId}\\rem_counter.txt";

    var timerDict = new Dictionary<int, int>()
    {
        {0,60 },
        {1,120 },
        {2,180 },
        {3,180 }
    };

    var reminderCount = 0;

    var content = File.ReadAllText(path);
    if (!string.IsNullOrEmpty(content))
    {
        reminderCount = Int32.Parse(content);
    }

    // increase the counter
    File.WriteAllText(path, $"{reminderCount+1}");

    //return Duration.FromSeconds(10);
    var result = Duration.FromSeconds(timerDict[reminderCount]);
    return result;

}

解决方案

问题分析

  1. 原工作流缺少循环触发提醒的逻辑,仅执行一次Timer和SendEmail,无法实现多次提醒
  2. GetTimerValue中的时间配置错误,当前用秒数(60/120/180),不符合需求的小时间隔
  3. 缺少第三次提醒后等待24小时再终止的逻辑
  4. 文件操作未加锁,可能出现并发读写导致计数器错乱

修正后的工作流代码

// 主分支:保留原有审批响应处理逻辑
fork
    .When("ApprovalResponse")
        // 此处添加原有审批完成的处理逻辑(如接收回调、标记工作流完成)
        .Finish()
    .When("RemindLoop")
        .If(context => !CheckReminderLimitReached(context))
            .When("true")
                .Timer(context => GetTimerValue(context)).WithName("ReminderTimer")
                .SendEmail(/* 你的邮件发送逻辑 */)
                .Goto("RemindLoop") // 循环回到判断节点,继续检查是否需要下一次提醒
            .When("false")
                .Timer(Duration.FromHours(24)) // 第三次提醒后等待24小时
                .MarkAsFaulted("审批超时未响应") // 或使用.CancelWorkflow()取消工作流
                .Finish()

修正后的自定义方法

private bool CheckReminderLimitReached(ActivityExecutionContext context)
{
    string ticketId = context.GetVariable<ApprovalRequestModel>("Approval")!.ticket_id!;
    string path = $"C:\\Apps\\DotNet\\UatTickets\\{ticketId}\\rem_counter.txt";
    int reminders = 0;

    // 加锁保证文件读写原子性,避免并发问题
    lock (this)
    {
        if (File.Exists(path))
        {
            var content = File.ReadAllText(path);
            int.TryParse(content, out reminders);
        }
    }

    return reminders >= 3; // 改为>=3更严谨,避免计数器异常溢出
}

private Duration GetTimerValue(ActivityExecutionContext context)
{
    string ticketId = context.GetVariable<ApprovalRequestModel>("Approval")!.ticket_id!;
    string path = $"C:\\Apps\\DotNet\\UatTickets\\{ticketId}\\rem_counter.txt";
    int reminderCount = 0;

    lock (this)
    {
        if (File.Exists(path))
        {
            var content = File.ReadAllText(path);
            int.TryParse(content, out reminderCount);
        }

        // 更新计数器
        File.WriteAllText(path, $"{reminderCount + 1}");
    }

    // 修正时间配置为需求的小时数
    var timerDict = new Dictionary<int, Duration>()
    {
        {0, Duration.FromHours(1) },
        {1, Duration.FromHours(5) },
        {2, Duration.FromHours(24) }
    };

    // 容错处理:避免计数器超出范围导致KeyNotFoundException
    return timerDict.TryGetValue(reminderCount, out var duration) ? duration : Duration.Zero;
}

关键说明

  1. 循环逻辑:通过Goto("RemindLoop")实现提醒循环,每次发送邮件后回到判断节点,检查是否达到提醒上限
  2. 时间修正:将GetTimerValue中的时间单位从秒改为小时,完全匹配需求间隔
  3. 并发安全:添加lock确保文件读写操作原子性,防止计数器错乱
  4. 超时终止:提醒次数耗尽后,等待24小时再标记工作流为故障或取消
  5. 容错处理:使用int.TryParse避免文件内容异常导致程序崩溃

内容的提问来源于stack exchange,提问作者Chetan Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 00:44:56