feat: persist workflow signals and arbitrate poll completion
This commit is contained in:
@@ -4,14 +4,11 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.yuntuo.hk/k2safe/orbit/internal/fault"
|
||||
core "git.yuntuo.hk/k2safe/orbit/model"
|
||||
"git.yuntuo.hk/k2safe/orbit/platform/auth"
|
||||
pulse "git.yuntuo.hk/k2safe/orbit/pulse/model"
|
||||
"git.yuntuo.hk/k2safe/orbit/pulse/service"
|
||||
)
|
||||
|
||||
@@ -56,68 +53,15 @@ func (s *TaskStore) CancelTask(ctx context.Context, token auth.Token, id core.ID
|
||||
if owner.Valid && owner.String != "schedule" {
|
||||
return fault.Conflict
|
||||
}
|
||||
var attempt *pulse.Attempt
|
||||
if view.State == pulse.TaskLeased || view.State == pulse.TaskRunning {
|
||||
if task.current == nil {
|
||||
return errors.New("active task lacks attempt")
|
||||
}
|
||||
a, err := readAttempt(ctx, tx, token.NamespaceID, *task.current)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if a.TaskID != id || a.Epoch != task.epoch || string(a.State) != string(view.State) {
|
||||
return errors.New("task attempt identity or state mismatch")
|
||||
}
|
||||
attempt = &a
|
||||
}
|
||||
now, err := dbNow(ctx, tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
next := view.State
|
||||
lease := task.lease
|
||||
var completed *time.Time
|
||||
if view.State == pulse.TaskWaiting || view.State == pulse.TaskLeased {
|
||||
next = pulse.TaskCancelled
|
||||
completed = &now
|
||||
lease = nil
|
||||
if view.EffectUncertain {
|
||||
next, completed = pulse.TaskNeedsReview, nil
|
||||
}
|
||||
if attempt != nil {
|
||||
if attempt.AuthorizedAt != nil {
|
||||
return errors.New("leased attempt already authorized")
|
||||
}
|
||||
result, err := tx.ExecContext(ctx, `UPDATE pulse_attempts SET state='CANCELLED',ended_at=?,error_code='CANCELLED_BEFORE_START',revision=revision+1,updated_at=? WHERE namespace_id=? AND id=? AND revision=?`, now, now, token.NamespaceID, attempt.ID, attempt.Revision)
|
||||
if err := exactlyOne(result, err); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := releasePermits(ctx, tx, token.NamespaceID, attempt.ID, now); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
result, err := tx.ExecContext(ctx, `UPDATE pulse_tasks SET state=?,cancel_requested_at=?,lease_until=?,completed_at=?,updated_at=?,revision=revision+1 WHERE namespace_id=? AND id=? AND revision=?`, next, now, lease, completed, now, token.NamespaceID, id, in.ExpectedRevision)
|
||||
if err := exactlyOne(result, err); err != nil {
|
||||
return err
|
||||
}
|
||||
if next.Terminal() {
|
||||
if err := releaseQueueTask(ctx, tx, token.NamespaceID, view.QueueID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
out.Task, err = readTask(ctx, tx, token.NamespaceID, id, false)
|
||||
out.Task, err = cancelExecutionTask(ctx, tx, token.NamespaceID, task, now, "CANCEL_REQUESTED")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event := resultEvent(next)
|
||||
if next == view.State {
|
||||
event = "task.cancel_requested"
|
||||
}
|
||||
if err := emitEvent(ctx, tx, token.NamespaceID, id, out.Task.Revision, "task", event, map[string]any{"task_id": id, "state": next, "reason": "CANCEL_REQUESTED", "effect_uncertain": view.EffectUncertain}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := appendAudit(ctx, tx, token, identity, id, "task", "task.cancel", in.Reason, map[string]any{"state": view.State, "revision": fmt.Sprint(view.Revision)}, map[string]any{"state": next, "revision": fmt.Sprint(out.Task.Revision), "cancel_requested_at": now}); err != nil {
|
||||
if err := appendAudit(ctx, tx, token, identity, id, "task", "task.cancel", in.Reason, map[string]any{"state": view.State, "revision": fmt.Sprint(view.Revision)}, map[string]any{"state": out.Task.State, "revision": fmt.Sprint(out.Task.Revision), "cancel_requested_at": now}); err != nil {
|
||||
return err
|
||||
}
|
||||
return saveIdentity(ctx, tx, token.NamespaceID, identity, out)
|
||||
|
||||
Reference in New Issue
Block a user