






















Elsa 3.5.3
builder.Services.AddElsa();
如果具体版本中无法使用此逻辑,可以通过workflow的meta字段存储,并在中间件中读取执行结束时的所有变量并保存,在恢复执行时重新创建参数注入即可
var variable = new Variable(paraName, obj);
//将变量保存在流程的持久化数据中
variable.WithWorkflowStorage();
variable.WithMemoryStorage();
variable.WithStorage();
如果需要使用elsa提供的方法则需要保证流程正确的保存,保存后就可以用便捷的方式恢复流程继续运行
//主要使用这些方法
// IWorkflowDefinitionStore s;
//s.SaveAsync();
//IWorkflowDefinitionPublisher p;
// p.PublishAsync
//IWorkflowRegistry 注册工作流
var flow=new WorkFlow();
// 3. 创建或获取工作流定义
var workflowDefinition = new WorkflowDefinition
{
DefinitionId = flow.DefinitionHandle.DefinitionId,
Id = Guid.NewGuid().ToString("N"),
//Name = workflowDefinition.Name,
//Description = workflowDefinition.Description,
//Version = flow.DefinitionHandle.VersionOptions.Value + 1,
CreatedAt = DateTimeOffset.UtcNow
};
// 4. 设置工作流定义属性
workflowDefinition.MaterializerName = "Json";
//workflowDefinition.StringData = rootActivityJson; // 存储序列化数据
workflowDefinition.IsLatest = true;
workflowDefinition.IsPublished = false; // 先保存为草稿
//物化流程
var store = serviceProvider.GetService<IWorkflowDefinitionStore>();
store.SaveAsync(workflowDefinition);
//发布流程
var publisher = serviceProvider.GetService<IWorkflowDefinitionPublisher>();
publisher.PublishAsync(flow.DefinitionHandle.DefinitionId);
var workflowRuntime = serviceProvider.GetService<IWorkflowRuntime>();
var workflowDefinitionId = "f9f9adebad8a4f6bb63fc4b50aabcfb1";
//var workflowInstance = await _workflowInstanceStore.FindAsync(filter);
//options.BookmarkId = workflowInstance.WorkflowState.Bookmarks.First().Id;
// 1. 创建通用客户端(无参数)
var workflowClient = await workflowRuntime.CreateClientAsync(cancellationToken: CancellationToken.None);
// 2. 使用 CreateAndRunInstanceAsync 启动工作流
var startRequest = new CreateAndRunWorkflowInstanceRequest
{
// 关键:通过 WorkflowDefinitionHandle 指定要启动的工作流定义
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(workflowDefinitionId),
// 可选:指定特定版本
// WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionVersionId(workflowDefinition.Id),
// 传入输入参数
//Input = new
//{
// OrderId = 12345,
// UserName = "张三",
// // 或者直接使用您的 para 字典
// // Data = para
//},
// 关联ID(用于业务追踪)
CorrelationId = "ORDER-12345",
// 实例名称
Name = "订单处理流程",
// 父工作流ID(如果是子工作流)
// ParentId = parentInstanceId,
// 附加属性
Properties = new Dictionary<string, object>
{
["Source"] = "API调用",
["CreatedBy"] = "System"
}
};
// 3. 执行启动
var runResult = await workflowClient.CreateAndRunInstanceAsync(startRequest);
var workflowInstanceStore = serviceProvider.GetService<IWorkflowInstanceStore>();
var options = new RunWorkflowOptions();
options.WorkflowInstanceId = request.InstanceId;
var filter = new Elsa.Workflows.Management.Filters.WorkflowInstanceFilter();
filter.Id = request.InstanceId;
//恢复执行
var workflowInstance = await workflowInstanceStore.FindAsync(filter);
var bookmarkId = workflowInstance.WorkflowState.Bookmarks.First().Id;
var existingInstanceId = request.InstanceId;
var workflowRuntime = serviceProvider.GetService<IWorkflowRuntime>();
var workflowDefinitionId = "f9f9adebad8a4f6bb63fc4b50aabcfb1";
// 1. 为特定实例创建客户端(传入实例ID)
var instanceClient = await workflowRuntime.CreateClientAsync(
workflowInstanceId: existingInstanceId, // 已存在的工作流实例ID
cancellationToken: CancellationToken.None);
// 2. 使用 RunInstanceAsync 恢复执行
var resumeRequest = new RunWorkflowInstanceRequest
{
// 必须指定要恢复的书签ID
BookmarkId = bookmarkId,
// 恢复时传入的数据
//Input = new
//{
// ApprovalResult = "Approved",
// Approver = "李四",
// Timestamp = DateTime.UtcNow
//},
// 可选:指定恢复的活动(如果知道具体活动)
// ActivityHandle = ActivityHandle.ByActivityId("activity-id"),
// 可选:关联ID
//CorrelationId = "RESUME-ORDER-12345",
// 附加属性
Properties = new Dictionary<string, object>
{
["ResumedAt"] = DateTime.UtcNow,
["ResumedBy"] = "审批系统"
}
};
// 3. 执行恢复
var resumeResult = await instanceClient.RunInstanceAsync(resumeRequest);
//恢复流程
var _workflowResumer = serviceProvider.GetService<IWorkflowResumer>();
await _workflowResumer.ResumeAsync(options.BookmarkId, para);
常用事件
public class WorkflowStartedHandler : INotificationHandler<WorkflowStarted>
{
public Task HandleAsync(WorkflowStarted notification, CancellationToken cancellationToken)
{
var workflowInstance = notification.WorkflowExecutionContext;
Console.WriteLine($"工作流 {workflowInstance.Name} (实例 {workflowInstance.Id}) 已开始");
return Task.CompletedTask;
}
}
//注册事件
builder.Services.AddNotificationHandlersFrom<WorkflowStartedHandler>();
//需要注入对象
IWorkflowRunner workflowRunner;
//顺序工作流
var workflow = new Sequence();
workflow.Activities = new List<IActivity>();
for (int i = 0; i < 3; i++)
{
workflow.Activities.Add(new WriteLine("test"));
}
var result = await workflowRunner.RunAsync(workflow);
//流程
var nameVariable = new Variable<string>();
// Define the activities to put in the flowchart:
var writeLine1 = new WriteLine("Please tell me your name:");
//var writeLine2 = new ReadLine(nameVariable);
var writeLine2 = new WriteLine(nameVariable);
var writeLine3 = new WriteLine(context => $"Nice to meet you, {nameVariable.Get(context)}!");
var cus = new TestActivity();
// Define a flowchart workflow:
var workflow = new Flowchart
{
// Register the name variable.
Variables = { nameVariable },
// Add the activities.
Activities =
{
writeLine1,
writeLine2,
writeLine3,
cus
},
// Setup the connections between activities.
Connections =
{
new Connection(writeLine1, writeLine2),
new Connection(writeLine2, writeLine3),
new Connection(writeLine3, cus)
}
};
var result = await workflowRunner.RunAsync(workflow);
builder.Services.AddElsa(options => options.AddActivity<TestActivity>());
通过context.CompleteActivityAsync标记当前活动已经完成,可以直接执行后续的活动
public class TestActivity : Activity //, IActivityWithResult
{
//public Output Result { get; set; } = new();
//[Input] public Input<decimal> Amount { get; set; } = default!;
//[Output] public Output<string> TransactionId { get; set; } = default!;
/// <summary>
/// 判断活动是否可以执行
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
protected override ValueTask<bool> CanExecuteAsync(ActivityExecutionContext context)
{
//Console.WriteLine("CanExecuteAsync!");
return ValueTask.FromResult(true);
//return base.CanExecuteAsync(context);
}
/// <summary>
/// 活动中执行的具体逻辑
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
protected override ValueTask ExecuteAsync(ActivityExecutionContext context)
{
Console.WriteLine("活动已执行!");
return context.CompleteActivityAsync();
}
}
在定义工作流时定义变量或者在活动节点内部定义
通过Variables属性定义工作流的变量,也可以在后续节点中进行定义
var nameVariable = new Variable<bool>("boolid", true);
var testStrVariable = new Variable<string>("testStr", "testStr");
Input<bool> x = new(false);
//顺序工作流
var workflow = new Sequence();
workflow.Variables = new List<Variable>()
{
nameVariable,
testStrVariable
};
主要是通过上下文对象的几个变量操作的方法进行处理
protected override ValueTask ExecuteAsync(ActivityExecutionContext context)
{
Console.WriteLine("活动已执行!");
//旧版本写法
//var nameVariable = new Variable<bool>("boolid", false);
////nameVariable.Value = true;
//var x = nameVariable.Get(context);
//var testVariable = new Variable<string>("testStr", string.Empty);
//var strValue = testVariable.Get(context);
var boolValue = context.GetVariable<bool>("boolid");
var strValue = context.GetVariable<string>("testStr");
//设置变量值
context.SetVariable("testStr", "act-test");
//添加一个新变量
context.SetVariable("newVar", "newVar");
//获取修改后的变量
strValue = context.GetVariable<string>("testStr");
//var testMetadata = context.GetMetadata<string>("testMetadata");
return context.CompleteActivityAsync();
}
var service = context.GetRequiredService<FlowService>();
通过RunWorkflowOptions的Input属性传递入参
var option = new RunWorkflowOptions();
option.Input = new Dictionary<string, object>();
option.Input.Add("inputStr1", "inputStr1");
var result = await workflowRunner.RunAsync(workflow, option);
在活动节点内部通过上下文的WorkflowInput属性获取
protected override ValueTask ExecuteAsync(ActivityExecutionContext context)
{
var inputStr = context.WorkflowInput["inputStr1"];
return context.CompleteActivityAsync();
}
protected override ValueTask ExecuteAsync(ActivityExecutionContext context)
{
context.WorkflowExecutionContext.Output.Add("outputStr1", "outputstr");
context.WorkflowExecutionContext.Output.Add("outputStr2", "outputstr2");
return context.CompleteActivityAsync();
}
var workflow = ElsaUtil.GetVaraibleTest();
workflow.Name = "Test";
workflow.Id = "testFlowID";
var option = new RunWorkflowOptions();
var result = await workflowRunner.RunAsync(workflow, option);
//获取结果
var output = result.WorkflowState.Output;
IWorkflowRuntime提供了更多高级属性和功能,workflowRunner只提供了基础的功能。
如果希望由触发器触发、消息队列触发工作流时可以用这种方式。
可以参考官方说明IWorkflowRunner vs IWorkflowRuntime vs IWorkflowDispatcher
IWorkflowRunner
IWorkflowRuntime
public class TestFlow : WorkflowBase
{
protected override void Build(IWorkflowBuilder builder)
{
builder.Root = new WriteLine("Hello flow!");
}
}
builder.Services.AddElsa(elsa =>
{
elsa.AddWorkflow<TestFlow>();
}
);
IWorkflowRuntime workflowRuntime;
var client = await workflowRuntime.CreateClientAsync();
var result = await client.CreateAndRunInstanceAsync(new CreateAndRunWorkflowInstanceRequest
{
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId("TestFlow"),
Input = new Dictionary<string, object>
{
["message"] = "Hello from the library!",
["userId"] = 123
},
CorrelationId = "optional-correlation-id",
TriggerActivityId = "testFlowID"
});
前面通过继承Activity可以实现自定义活动,但是需要调用return context.CompleteActivityAsync();通过引擎当前活动已经执行结束可以继续下一个活动。
也可以通过CodeActivity来实现,CodeActivity继承了Activity,可以用来处理简单的有明确输入输出的活动。
Activity可以用来处理复杂的场景,控制暂停和恢复。CodeActivity通常一次执行完成。
支持泛型参数CodeActivity
public class TestCodeActivity : CodeActivity
{
/// <summary>
///
/// </summary>
public Input<string> TestName { get; set; } = default!;
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
protected override ValueTask<bool> CanExecuteAsync(ActivityExecutionContext context)
{
return ValueTask.FromResult(true);
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
protected override ValueTask ExecuteAsync(ActivityExecutionContext context)
{
Console.WriteLine($"活动已执行!{TestName}");
return ValueTask.CompletedTask;
}
}
获取CodeActivity返回值
public class TestCodeGenericActivity : CodeActivity<string>
{
protected override ValueTask<bool> CanExecuteAsync(ActivityExecutionContext context)
{
return ValueTask.FromResult(true);
}
protected override ValueTask ExecuteAsync(ActivityExecutionContext context)
{
context.SetResult("ExecuteAsync-Result");
return ValueTask.CompletedTask;
}
}
public static IActivity TestResult()
{
var testStrVariable = new Variable<string>("testStr", "testStr");
var workflow = new Sequence();
workflow.Variables = new List<Variable>()
{
testStrVariable
};
workflow.Activities = new List<IActivity>();
var resultActivity = new TestCodeGenericActivity()
{
Result = new(testStrVariable)
};
workflow.Activities.Add(resultActivity);
workflow.Activities.Add(new WriteLine(context => $"问候语是:{testStrVariable.Get(context)}"));
return workflow;
}
可以实现先暂停任务,等待外部触发逻辑后继续执行
public class BookmarkTest : Activity
{
protected override void Execute(ActivityExecutionContext context)
{
// 创建一个书签。创建的书签将存储在工作流状态中。
context.CreateBookmark();
// 此活动在事件发生之前不会完成。
}
}
elsa.AddActivity<BookmarkTest>();
var workflow = new Workflow
{
Root = new Sequence
{
Activities =
{
new WriteLine("工作流开始..."),
new BookmarkTest(), // 这将会阻塞后续执行,直到 MyEvent 的书签被恢复。
new WriteLine("事件发生!")
}
}
};
workflow.Name = "Test";
workflow.Id = "testFlowID";
var result = await workflowRunner.RunAsync(workflow);
var instanceID = result.WorkflowExecutionContext.Id;
var workflowState = result.WorkflowState;
var bookmark = workflowState.Bookmarks.Single(); // 获取由 MyEvent 活动创建的书签。
var options = new RunWorkflowOptions();
options.BookmarkId = bookmark.Id;
options.WorkflowInstanceId = instanceID;
// 恢复工作流。
//await workflowRunner.RunAsync(workflow, options);
//内存缓存时可以不传递state,持久化时需要传递否则无法执行标签后续的活动
//await workflowRunner.RunAsync(workflow, options);
await workflowRunner.RunAsync(workflow, workflowState, options);
注入序列化器
IActivitySerializer activitySerializer;
加载并执行到书签后继续执行
var workflowRaw = ElsaUtil.TestBookmark();
workflowRaw.Name = "Test";
workflowRaw.Id = "testFlowID";
var json = activitySerializer.Serialize(workflowRaw);
var workflow = activitySerializer.Deserialize<Workflow>(json);
var result = await workflowRunner.RunAsync(workflow);
var instanceID = result.WorkflowExecutionContext.Id;
var workflowState = result.WorkflowState;
var bookmark = workflowState.Bookmarks.Single();
var options = new RunWorkflowOptions();
options.BookmarkId = bookmark.Id;
options.WorkflowInstanceId = instanceID;
// 恢复工作流。
await workflowRunner.RunAsync(workflow, result.WorkflowState, options);
使用pg,需要安装两个nuget包【Elsa.EntityFrameworkCore】、【Elsa.EntityFrameworkCore.PostgreSql】
builder.Services.AddLogging(logging =>
{
logging.ClearProviders();
logging.AddConsole();
logging.AddDebug();
// 过滤掉 EF Core 的 SQL 日志
logging.AddFilter("Microsoft.EntityFrameworkCore.Database.Command", LogLevel.Warning);
logging.AddFilter("Microsoft.EntityFrameworkCore.Database.Connection", LogLevel.Warning);
logging.AddFilter("Microsoft.EntityFrameworkCore.Infrastructure", LogLevel.Warning);
logging.AddFilter("Microsoft.EntityFrameworkCore.Query", LogLevel.Warning);
});
builder.Services.AddElsa(elsa =>
{
var connectionString = "Host=127.0.0.1;Port=5432;Database=dbName;Username=dev;Password=testPassword;SearchPath=public";
// 配置管理层以使用EF Core。
elsa.UseWorkflowManagement(management => management.UseEntityFrameworkCore(ef =>
ef.UsePostgreSql(connectionString)));
elsa.UseWorkflowRuntime(runtime => runtime.UseEntityFrameworkCore(ef =>
ef.UsePostgreSql(connectionString)));
}
);
var workflow = new Workflow
{
Root = new Sequence
{
Activities =
{
new WriteLine("工作流开始..."),
new BookmarkTest(), // 这将会阻塞后续执行,直到 MyEvent 的书签被恢复。
new WriteLine("事件发生!")
}
}
};
var result = await workflowRunner.RunAsync(workflow);
var bookmarkID = result.WorkflowState.Bookmarks.First().Id;
var instanceID = result.WorkflowExecutionContext.Id;
private readonly IWorkflowInstanceStore _workflowInstanceStore;
var workflow = new Workflow
{
Root = new Sequence
{
Activities =
{
new WriteLine("工作流开始..."),
new BookmarkTest(), // 这将会阻塞后续执行,直到 MyEvent 的书签被恢复。
new WriteLine("事件发生!")
}
}
};
//查找流程实例获取状态属性
var filter = new Elsa.Workflows.Management.Filters.WorkflowInstanceFilter();
filter.Id = instanceID;
var workflowInstance = await _workflowInstanceStore.FindAsync(filter);
// 恢复工作流,需要WorkflowState才能正确执行
await workflowRunner.RunAsync(workflow, workflowInstance.WorkflowState, options);
var workflow = new Flowchart
{
Activities =
{
new WriteLine("工作流开始..."),
new BookmarkTest(), // 这将会阻塞后续执行,直到 MyEvent 的书签被恢复。
new WriteLine("事件发生!")
}
};
var wf = new Workflow
{
Root = workflow
};
var result = await workflowRunner.RunAsync(wf);
var instanceID = result.WorkflowExecutionContext.Id;
var options = new RunWorkflowOptions();
options.WorkflowInstanceId = instanceID;
var filter = new Elsa.Workflows.Management.Filters.WorkflowInstanceFilter();
filter.Id = instanceID;
var workflowInstance = await _workflowInstanceStore.FindAsync(filter);
options.BookmarkId = workflowInstance.WorkflowState.Bookmarks.First().Id;
options.WorkflowInstanceId = instanceID;
await workflowRunner.RunAsync(wf, workflowInstance.WorkflowState, options);
public class WorkflowCompletionMiddleware : IWorkflowExecutionMiddleware
{
private readonly WorkflowMiddlewareDelegate _next;
public WorkflowCompletionMiddleware(WorkflowMiddlewareDelegate next)
{
this._next = next;
}
public async ValueTask InvokeAsync(WorkflowExecutionContext context)
{
// 调用下一个中间件
await _next(context);
//记录流程执行结果
if (context.Status == WorkflowStatus.Finished)
{
var vari = context.Workflow.Variables.ToList();
var result = context.Variables.ToList();
//var testStr = context.Variables.GetPropertyValue<string>("testStr");
//通过容器获取依赖注入的类型
//var sugar = context.GetService<ISqlSugarClient>();
}
}
}
//在原有在AddElsa中通过UseWorkflows调用WithWorkflowExecutionPipeline注册
builder.Services.AddElsa(elsa =>
{
elsa.UseWorkflows(workflows =>
{
workflows.WithWorkflowExecutionPipeline(pipeline =>
{
//pipeline.UseMiddleware<WorkflowCompletionMiddleware>();
//pipeline.UseDefaultPipeline();
//重写UseDefaultPipeline
pipeline.Reset()
.UseMiddleware<WorkflowCompletionMiddleware>()
.UseWorkflowHeartbeat()
.UseEngineExceptionHandling()
.UsePersistentVariables()
.UseExceptionHandling()
.UseDefaultActivityScheduler();
});
});
}
);
可以通过WorkflowExecutionContext类型的Status、SubStatus字段获取。类型定义如下
public enum WorkflowSubStatus
{
//
// 摘要:
// The workflow is pending execution.
Pending,
//
// 摘要:
// The workflow is currently executing.
Executing,
//
// 摘要:
// The workflow is currently suspended and waiting for external stimuli to resume.
Suspended,
//
// 摘要:
// The workflow completed successfully.
Finished,
//
// 摘要:
// The workflow was cancelled.
Cancelled,
//
// 摘要:
// The workflow has faulted.
Faulted
}
在运行时通过RunWorkflowOptions指定WorkflowInstanceId
RunWorkflowOptions option = null;
if (!string.IsNullOrEmpty(newInstanceID))
{
option = new RunWorkflowOptions
{
WorkflowInstanceId = newInstanceID
};
}
return await workflowRunner.RunAsync(workflow, option);
[ActivityAttribute(Category = "Common", Description = nameof(InterruptActivity), DisplayName = nameof(InterruptActivity))]
public class InterruptActivity : CodeActivity, IActivityNode
{
/// <summary>
///
/// </summary>
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
{
context.CreateBookmark(new CreateBookmarkArgs()
{
Callback = ResumeAsync
});
context.CreateBookmark();
}
private async ValueTask ResumeAsync(ActivityExecutionContext context)
{
}
}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。