Skip to content
bitzorcas
中EN

Guide

Workflow 通知 Pipeline

讲解事件分发、接收人、默认模板、偏好、平台通知适配、JobHost 接线、事务性失败语义与外部投递对账。

Last updated

Workflow 通知的站内信事实已并入流程命令的事务边界:平台 INotificationChannel 实现逐接收人调用 Notifications 模块写入收件箱并产生 CAP Outbox 记录,任一接收人失败都会让整个流转命令失败回滚。“审批成功但通知悄悄丢了”不再是合法状态;跨网络的外部投递(邮件、钉钉等)仍由 Notifications 模块的消费者异步完成——送达确认属于它的职责域。

1. 分发链

CAP / deliveryNotificationComposerINotificationChannelNotificationDispatcherEventDispatcherWorkflow RuntimeCAP / deliveryNotificationComposerINotificationChannelNotificationDispatcherEventDispatcherWorkflow Runtimelog then rethrow — transition fails and rolls backtask or lifecycle eventlistener callbackresolve recipient/template/preferenceWorkflowNotificationComposeAsync per recipient (inbox + outbox)throw on any recipient failureexternal delivery (async consumer)

EventDispatcher 按注册顺序调用 Task、Execution 和 WorkflowEvent listener;监听器异常记录日志后向上重抛。

2. 事件与接收人

事件默认接收人
TaskCreatedTask.Assignee
TaskCompleted当前申请人
TaskRejected当前申请人
TaskTransferred / Delegateddata.recipientUserIds
ParticipantAdded新参与人
InstanceCompleted/Cancelled/Terminated/Withdrawn当前申请人
CcCreated抄送人
TaskRemind当前 Pending Assignee

IApplicantResolver 可动态解析申请人;失败回退 CurrentApplicantId/StarterId。TaskCreated 每个解析用户已有独立 Task,因此通知按具体 Assignee。

3. 模板

NotificationDispatcher 可使用 IWorkflowNotificationTemplateResolver 按 eventType、businessType、语言解析模板;不存在或失败时回退内置中文默认文案(如 "您有新的审批任务:{title}")。变量只做受控花括号插值。

独立构建器接入模板
var engine = new WorkflowEngineBuilder()
// 直接 Builder 才会把模板与偏好端口完整传给 Dispatcher。
.UsePersistence(store)
.UseExpressionEvaluator(new DefaultExpressionEvaluator())
.UseNotificationChannel(channel)
.UseNotificationTemplateResolver(templateResolver)
.UseNotificationPreferenceStore(preferenceStore)
// Build 只验证必需端口,不提供通知持久化与重试。
.Build();

4. 偏好

若 Builder 直接接入 IWorkflowNotificationPreferenceStore,只有 InboxEnabled 或 ExternalDeliveryEnabled 任一为 true 才保留接收人。偏好查询失败时 fail-open,保留接收人并写日志。

平台 NotificationService 也有自身偏好与外部投递抑制。双层策略需要统一,否则可能出现引擎层丢弃、平台层再判断,或 UI 配置与实际分发不一致。

5. 平台适配

WorkflowNotificationAdapter 实现引擎的 INotificationChannel,底层调用 Notifications 模块的 INotificationComposer:code 为 workflow.{EventType},严重度映射 Urgent→Error、High→Warning、其余 Info,类型映射把审批类事件归 Approval、终态事件归 Business、抄送归 Todo;Metadata JSON 携带 instanceId、businessKey、eventType、definitionKey、officeId。任一接收人的 Compose 返回失败或抛异常都会累计计数:

当前逐接收人语义
foreach (string userId in notification.RecipientUserIds)
{
try
{
var result = await _notificationComposer.ComposeAsync(
tenantId: notification.TenantId,
userId: userId,
code: $"workflow.{notification.EventType}",
title: notification.Title,
body: notification.Body,
type: type,
category: notification.BusinessType,
severity: severity,
linkUrl: null,
linkText: null,
metadataJson: metadataJson,
cancellationToken: cancellationToken);
// 站内信写失败只是计数:通道要在遍历完所有接收人后统一决策。
if (!result.IsSuccess)
{
failedRecipients++;
}
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception exception) when (exception is not OutOfMemoryException)
{
failedRecipients++;
}
}
if (failedRecipients > 0)
{
// 任一接收人落库失败都升级为通道异常,交由上层令整个流转失败回滚。
throw new InvalidOperationException(
$"Workflow notification persistence failed for {failedRecipients} recipient(s).");
}

这保证”成功提交 ⇒ 站内信与 Outbox 已写”;代价是通知通道故障会阻断审批动作本身——按事务一致性设计监控告警是运维义务,不是可选项。

6. 节点 DSL 通知

NodeListenerDispatcher 对 type=notification 的 listener 读取 __listenerRecipients 变量,Title 使用 channel 或 node-listener,Body 使用 expression。它与标准 NotificationDispatcher 是两条不同路径。

接收人列表为空或变量缺失时直接跳过发送(不发空通知);而任何真实发送失败的异常会沿新的失败链条抛出并使流转失败。

7. JobHost 接线

后台催办不再是缺口。WorkflowBackgroundJobsExtensions.AddWorkflowBackgroundJobs 在 hasSqlSugar 时注册完整处理链:

  • SqlSugarWorkflowPersistenceStore 与计时器租户执行作用域;
  • 定时任务专用系统权限检查器 WorkflowTimerSystemPermissionChecker;
  • INotificationChannel → WorkflowNotificationAdapter;
  • 作 业身份 BackgroundJobIdentities.WorkflowTimer.JobName = "workflow-timer",Quartz 端 [DisallowConcurrentExecution],默认每 5 分钟扫描,可用 BackgroundJobs:workflow-timer:IntervalSeconds 覆盖。

WorkflowTimerProcessor 以 ILicenseGate 为必选依赖推进到期 Timer、超时升级(escalate)与超时转办(transfer)。执行作用域保证业务动作、通知 Outbox 与 Fired 状态在租户上下文内原子提交。无 SqlSugar 的纯内存宿主则整链不注册,作业也不会被描述符登记。

8. 失败语义

失败点当前结果
模板解析记录警告,使用默认模板
偏好查询记录警告,保留接收人
单个接收人 Compose计入失败计数,继续其他接收人
接收人整体结束且有失败抛 InvalidOperationException,分发器重抛,流转失败回滚
监听器异常EventDispatcher 日志 + 重抛
CAP 外部投递由 Notifications 模块异步消费,Workflow 内不等待

9. 外部投递的对账边界

站内信与 Outbox 已随事务原子化;尚无跨网络的 delivery receipt、attempt 台账和死信对账——它们是 Notifications 模块消费侧的关注点。需要强 SLA 的产品应在消费侧补充:

Workflow transaction

Inbox + CAP Outbox

Notifications consumer

External channels

delivery receipt / retry / DLQ

replay and reconciliation

模板版本与最终渲染内容也应作为证据保存,避免重试时模板变更产生不同文案。

10. 安全与隐私

Variables 可能含敏感数据,NotificationDispatcher 会把变量带入 WorkflowNotification;平台 Metadata 当前只选择少数字段,但标题/正文仍可能插值泄露。模板 allowlist、长度、HTML/URL 上下文编码、收件人租户校验和日志脱敏都必须测试。

11. 测试清单

  • 每种事件的接收人和无接收人路径;
  • 申请人解析失败回退;
  • 模板缺失/异常与偏好 fail-open;
  • 多接收人部分失败导致整单回滚;
  • 相同 Transition 重放不重复站内信;
  • JobHost Reminder 实际发送与 Fired 原子提交;
  • CAP 停机、恢复、重复投递和对账;
  • 模板注入、超长变量和跨租户用户。

下一篇:API 参考

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%