81 lines
3.3 KiB
Go
81 lines
3.3 KiB
Go
package mysql
|
||
|
||
import (
|
||
"context"
|
||
"database/sql"
|
||
"errors"
|
||
|
||
core "git.yuntuo.hk/k2safe/orbit/model"
|
||
"git.yuntuo.hk/k2safe/orbit/weave/engine"
|
||
)
|
||
|
||
type workflowTaskLink struct {
|
||
Owner sql.NullString
|
||
Activation *core.ID
|
||
Gate *core.ID
|
||
Linked bool
|
||
}
|
||
|
||
// appendWorkflowResult 在原Pulse结果事务内创建内部交付,必须先于外部结果流行锁。
|
||
// 这里只核验稳定归属并写入队列,不锁实例/激活、不推进流程、不锁对外订阅。
|
||
func appendWorkflowResult(ctx context.Context, tx *sql.Tx, ns, eventID, taskID core.ID, revision uint64, snapshot []byte, link workflowTaskLink) error {
|
||
owner, ownerID, gate := link.Owner, link.Activation, link.Gate
|
||
if !owner.Valid || owner.String != engine.TaskOwnerKind {
|
||
if owner.Valid && owner.String != "schedule" {
|
||
return errors.New("unrecognized task owner")
|
||
}
|
||
// 无外键情况下,丢失owner不能把已有流程关联静默降级成普通任务。
|
||
if link.Linked {
|
||
return errors.New("workflow result ownership missing")
|
||
}
|
||
return nil
|
||
}
|
||
if ownerID == nil || gate == nil {
|
||
return errors.New("workflow result owner or gate missing")
|
||
}
|
||
var workflow core.ID
|
||
var kind string
|
||
var activationTask *core.ID
|
||
// 即使旧激活不再是current,也要保存内部事件,消费方再核对当前激活并留痕。
|
||
err := tx.QueryRowContext(ctx, `SELECT a.workflow_id,s.kind,a.task_id
|
||
FROM weave_activations a
|
||
JOIN weave_steps s ON s.namespace_id=a.namespace_id AND s.id=a.step_id AND s.workflow_id=a.workflow_id
|
||
JOIN weave_instances i ON i.namespace_id=a.namespace_id AND i.id=a.workflow_id AND i.gate_id=?
|
||
JOIN pulse_execution_gates g ON g.namespace_id=i.namespace_id AND g.id=i.gate_id
|
||
JOIN weave_definition_versions v ON v.namespace_id=i.namespace_id AND v.id=i.definition_version_id AND v.definition_id=i.definition_id
|
||
JOIN weave_definitions d ON d.namespace_id=i.namespace_id AND d.id=i.definition_id
|
||
WHERE a.namespace_id=? AND a.id=?`, gate, ns, ownerID).Scan(&workflow, &kind, &activationTask)
|
||
if errors.Is(err, sql.ErrNoRows) {
|
||
return errors.New("workflow result associations invalid")
|
||
}
|
||
if err != nil {
|
||
return err
|
||
}
|
||
switch kind {
|
||
case "TASK":
|
||
if activationTask == nil || *activationTask != taskID {
|
||
return errors.New("workflow activation task mismatch")
|
||
}
|
||
case "POLL":
|
||
if activationTask != nil {
|
||
return errors.New("poll activation cannot own a direct task")
|
||
}
|
||
var round uint32
|
||
err = tx.QueryRowContext(ctx, `SELECT r.round FROM weave_poll_rounds r JOIN weave_poll_states p ON p.namespace_id=r.namespace_id AND p.workflow_id=r.workflow_id AND p.activation_id=r.activation_id WHERE r.namespace_id=? AND r.workflow_id=? AND r.activation_id=? AND r.task_id=? AND r.round BETWEEN 1 AND p.used_rounds`, ns, workflow, ownerID, taskID).Scan(&round)
|
||
if errors.Is(err, sql.ErrNoRows) {
|
||
return errors.New("workflow poll task association invalid")
|
||
}
|
||
if err != nil {
|
||
return err
|
||
}
|
||
default:
|
||
return errors.New("workflow task owner kind invalid")
|
||
}
|
||
id, err := core.NewID()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
_, err = tx.ExecContext(ctx, `INSERT INTO weave_inbox(namespace_id,id,workflow_id,event_id,available_at,source_task_id,source_activation_id,source_revision,snapshot) VALUES (?,?,?,?,UTC_TIMESTAMP(6),?,?,?,?)`, ns, id, workflow, eventID, taskID, ownerID, revision, string(snapshot))
|
||
return err
|
||
}
|