Files
orbit/internal/storage/mysql/workflow_events.go

81 lines
3.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}