Files
orbit/examples/internal/flowdemo/runtime.go

120 lines
4.1 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 flowdemo 仅为可运行流程示例提供初始化和有界等待,不属于公开SDK或业务恢复策略。
package flowdemo
import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"time"
orbit "git.yuntuo.hk/k2safe/orbit/sdk/go"
)
func Client() (*orbit.Client, string, string, error) {
raw, err := os.ReadFile(os.Getenv("ORBIT_CREDENTIALS_FILE"))
if err != nil {
return nil, "", "", err
}
var credentials struct {
Token string `json:"token"`
QueueID string `json:"queue_id"`
}
if json.Unmarshal(raw, &credentials) != nil || credentials.Token == "" || credentials.QueueID == "" {
return nil, "", "", errors.New("invalid private credentials file")
}
client, err := orbit.NewClient(os.Getenv("ORBIT_URL"), orbit.Options{Token: credentials.Token})
if err != nil {
return nil, "", "", err
}
operation, err := orbit.NewWorkerMessageID()
return client, credentials.QueueID, operation, err
}
// PublishStart 每次示例运行创建独立身份;不将重新运行命令当作未知响应的原键恢复。
func PublishStart(ctx context.Context, api *orbit.Client, operation, name string, spec orbit.WorkflowSpecification, input json.RawMessage) (orbit.WorkflowInstance, error) {
var empty orbit.WorkflowInstance
fmt.Printf("scenario=%s operation=%s\n", name, operation)
created, err := api.CreateWorkflowDefinition(ctx, operation, orbit.CreateWorkflowDefinitionRequest{Name: name + "." + operation, Description: "controlled standalone workflow example"})
if err != nil {
return empty, err
}
if _, err = api.PublishWorkflowVersion(ctx, created.Definition.ID, operation, orbit.PublishWorkflowVersionRequest{Version: "v1", Specification: spec, Reason: "publish controlled SDK example"}); err != nil {
return empty, err
}
result, err := api.StartWorkflow(ctx, operation, orbit.StartWorkflowRequest{DefinitionID: created.Definition.ID, Version: "v1", BusinessKey: operation, Input: input})
if err != nil {
return empty, err
}
fmt.Printf("workflow=%s version=%s\n", result.Instance.ID, result.Instance.Version)
return result.Instance, nil
}
// Runner 持有一个真实Worker及其结束通知,等待时同时检测Worker异常退出。
type Runner struct {
Worker *orbit.Worker
stop context.CancelFunc
done chan struct{}
err error // err 仅在done关闭后读取,关闭通道建立同步关系。
}
func StartWorker(ctx context.Context, api *orbit.Client, queue string, handlers ...orbit.WorkerHandler) (*Runner, error) {
w, err := orbit.NewWorker(api, orbit.WorkerOptions{QueueID: queue, Capacity: 1, ShutdownTimeout: 5 * time.Second, Handlers: handlers})
if err != nil {
return nil, err
}
workerCtx, stop := context.WithCancel(ctx)
r := &Runner{Worker: w, stop: stop, done: make(chan struct{})}
go func() { r.err = w.Run(workerCtx); close(r.done) }()
return r, nil
}
func (r *Runner) Close() error {
r.stop()
<-r.done
return r.err
}
func (r *Runner) Wait(ctx context.Context, check func() (bool, error)) error {
for {
ready, err := check()
if err != nil || ready {
return err
}
select {
case <-ctx.Done():
return ctx.Err()
case <-r.done:
return fmt.Errorf("example Worker stopped before expected state: %v", r.err)
case <-time.After(100 * time.Millisecond):
}
}
}
func (r *Runner) Step(ctx context.Context, api *orbit.Client, workflow, key string, predicate func(orbit.WorkflowStepDetail) bool) (orbit.WorkflowStepDetail, error) {
var out orbit.WorkflowStepDetail
err := r.Wait(ctx, func() (bool, error) {
var err error
out, err = api.GetWorkflowStep(ctx, workflow, key)
return err == nil && predicate(out), err
})
return out, err
}
func (r *Runner) Workflow(ctx context.Context, api *orbit.Client, workflow, state string) (orbit.WorkflowInstance, error) {
var out orbit.WorkflowInstance
err := r.Wait(ctx, func() (bool, error) {
var err error
out, err = api.GetWorkflow(ctx, workflow)
if err != nil || out.State == state {
return err == nil, err
}
if out.State == "NEEDS_REVIEW" || out.State == "FAILED" || out.State == "CANCELLED" || out.State == "SUCCEEDED" {
return false, fmt.Errorf("unexpected workflow state %s; wanted %s", out.State, state)
}
return false, nil
})
return out, err
}