| @@ -4,10 +4,11 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/google/uuid" | 	"github.com/google/uuid" | ||||||
| 	"github.com/silas/dag" | 	"github.com/silas/dag" | ||||||
|  | 	"github.com/unistack-org/micro/v3/client" | ||||||
|  | 	"github.com/unistack-org/micro/v3/codec" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type microFlow struct { | type microFlow struct { | ||||||
| @@ -87,33 +88,44 @@ func (w *microWorkflow) Execute(ctx context.Context, req interface{}, opts ...Ex | |||||||
| 			return "", err | 			return "", err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	err = w.g.SortedDepthFirstWalk([]dag.Vertex{root}, fn) | 	if options.Reverse { | ||||||
|  | 		err = w.g.SortedReverseDepthFirstWalk([]dag.Vertex{root}, fn) | ||||||
|  | 	} else { | ||||||
|  | 		err = w.g.SortedDepthFirstWalk([]dag.Vertex{root}, fn) | ||||||
|  | 	} | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var wg sync.WaitGroup | 	var wg sync.WaitGroup | ||||||
| 	cherr := make(chan error) | 	cherr := make(chan error, 1) | ||||||
|  | 	defer close(cherr) | ||||||
|  |  | ||||||
| 	select { | 	nctx, cancel := context.WithCancel(ctx) | ||||||
| 	case err = <-cherr: | 	defer cancel() | ||||||
| 		return "", err | 	nopts := make([]ExecuteOption, 0, len(opts)+5) | ||||||
| 	default: | 	nopts = append(nopts, ExecuteClient(w.opts.Client), ExecuteTracer(w.opts.Tracer), ExecuteLogger(w.opts.Logger), ExecuteMeter(w.opts.Meter), ExecuteStore(w.opts.Store)) | ||||||
|  |  | ||||||
|  | 	go func() { | ||||||
| 		for idx := range steps { | 		for idx := range steps { | ||||||
| 			wg.Add(len(steps[idx])) | 			wg.Add(len(steps[idx])) | ||||||
| 			for nidx := range steps[idx] { | 			for nidx := range steps[idx] { | ||||||
| 				go func(step Step) { | 				go func(step Step) { | ||||||
| 					if err = step.Execute(ctx, req, opts...); err != nil { | 					defer wg.Done() | ||||||
|  | 					if err = step.Execute(nctx, req, nopts...); err != nil { | ||||||
| 						cherr <- err | 						cherr <- err | ||||||
|  | 						cancel() | ||||||
| 					} | 					} | ||||||
| 					wg.Done() |  | ||||||
| 				}(steps[idx][nidx]) | 				}(steps[idx][nidx]) | ||||||
| 			} | 			} | ||||||
| 			wg.Wait() | 			wg.Wait() | ||||||
| 		} | 		} | ||||||
| 	} | 		cherr <- nil | ||||||
|  | 	}() | ||||||
|  |  | ||||||
| 	return uid.String(), nil | 	err = <-cherr | ||||||
|  |  | ||||||
|  | 	return uid.String(), err | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewFlow(opts ...Option) Flow { | func NewFlow(opts ...Option) Flow { | ||||||
| @@ -236,9 +248,17 @@ func (s *microCallStep) Hashcode() interface{} { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (s *microCallStep) Execute(ctx context.Context, req interface{}, opts ...ExecuteOption) error { | func (s *microCallStep) Execute(ctx context.Context, req interface{}, opts ...ExecuteOption) error { | ||||||
| 	fmt.Printf("execute %s with %#v\n", s.String(), req) | 	options := NewExecuteOptions(opts...) | ||||||
| 	time.Sleep(1 * time.Second) | 	if options.Client == nil { | ||||||
| 	return nil | 		return fmt.Errorf("client not set") | ||||||
|  | 	} | ||||||
|  | 	rsp := &codec.Frame{} | ||||||
|  | 	copts := []client.CallOption{client.WithRetries(0)} | ||||||
|  | 	if options.Timeout > 0 { | ||||||
|  | 		copts = append(copts, client.WithRequestTimeout(options.Timeout), client.WithDialTimeout(options.Timeout)) | ||||||
|  | 	} | ||||||
|  | 	err := options.Client.Call(ctx, options.Client.NewRequest(s.service, s.method, req), rsp) | ||||||
|  | 	return err | ||||||
| } | } | ||||||
|  |  | ||||||
| type microPublishStep struct { | type microPublishStep struct { | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ package flow | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/unistack-org/micro/v3/client" | 	"github.com/unistack-org/micro/v3/client" | ||||||
| 	"github.com/unistack-org/micro/v3/logger" | 	"github.com/unistack-org/micro/v3/logger" | ||||||
| @@ -116,13 +117,67 @@ type ExecuteOptions struct { | |||||||
| 	// Meter holds the meter | 	// Meter holds the meter | ||||||
| 	Meter meter.Meter | 	Meter meter.Meter | ||||||
| 	// Store used for intermediate results | 	// Store used for intermediate results | ||||||
| 	Store   store.Store | 	Store store.Store | ||||||
|  | 	// Context can be used to abort execution or pass additional opts | ||||||
| 	Context context.Context | 	Context context.Context | ||||||
| 	Start   string | 	// Start step | ||||||
|  | 	Start string | ||||||
|  | 	// Reverse execution | ||||||
|  | 	Reverse bool | ||||||
|  | 	// Timeout for execution | ||||||
|  | 	Timeout time.Duration | ||||||
| } | } | ||||||
|  |  | ||||||
| type ExecuteOption func(*ExecuteOptions) | type ExecuteOption func(*ExecuteOptions) | ||||||
|  |  | ||||||
|  | func ExecuteClient(c client.Client) ExecuteOption { | ||||||
|  | 	return func(o *ExecuteOptions) { | ||||||
|  | 		o.Client = c | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func ExecuteTracer(t tracer.Tracer) ExecuteOption { | ||||||
|  | 	return func(o *ExecuteOptions) { | ||||||
|  | 		o.Tracer = t | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func ExecuteLogger(l logger.Logger) ExecuteOption { | ||||||
|  | 	return func(o *ExecuteOptions) { | ||||||
|  | 		o.Logger = l | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func ExecuteMeter(m meter.Meter) ExecuteOption { | ||||||
|  | 	return func(o *ExecuteOptions) { | ||||||
|  | 		o.Meter = m | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func ExecuteStore(s store.Store) ExecuteOption { | ||||||
|  | 	return func(o *ExecuteOptions) { | ||||||
|  | 		o.Store = s | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func ExecuteContext(ctx context.Context) ExecuteOption { | ||||||
|  | 	return func(o *ExecuteOptions) { | ||||||
|  | 		o.Context = ctx | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func ExecuteReverse(b bool) ExecuteOption { | ||||||
|  | 	return func(o *ExecuteOptions) { | ||||||
|  | 		o.Reverse = b | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func ExecuteTimeout(td time.Duration) ExecuteOption { | ||||||
|  | 	return func(o *ExecuteOptions) { | ||||||
|  | 		o.Timeout = td | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| func NewExecuteOptions(opts ...ExecuteOption) ExecuteOptions { | func NewExecuteOptions(opts ...ExecuteOption) ExecuteOptions { | ||||||
| 	options := ExecuteOptions{} | 	options := ExecuteOptions{} | ||||||
| 	for _, o := range opts { | 	for _, o := range opts { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user