-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Eager Workflow Start test (#374)
- Loading branch information
1 parent
6e7388c
commit 46d78ca
Showing
4 changed files
with
89 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Successful start of a workflow using eager mode | ||
Eager Workflow Start (EWS) is a latency optimization to reduce the time to start processing the first task of a workflow. The starter program provisions a slot in a suitable worker, requests that the server starts a workflow in eager mode, and then, when it receives the first WFT in the response, it directly schedules the task to the worker, eliminating a network roundtrip and a database transaction. | ||
|
||
In each scenario, the starter program and the worker should share a client. The starter program will create a simple workflow in eager mode, and then verify that eager mode was actually used, and the first workflow task was processed correctly. | ||
|
||
# Detailed spec | ||
* The `EnableEagerStart` start workflow option should be `true`. | ||
* The server response to start workflow should include a non-nil `eager_workflow_task` field. | ||
* The task timeout for the workflow should be large enough to hang the program on a task retry. A server response with an `eager_workflow_task` alone does not guarantee eager execution because the worker could still refuse to process it. In that exceptional case the task would be retried through the non-eager path, and may succeed. A large timeout effectively disables retries, ensuring success always comes from the eager path. | ||
* The simple workflow should return `"Hello World"` and exit without errors. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package successful_start | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"sync/atomic" | ||
"time" | ||
|
||
"github.com/temporalio/features/harness/go/harness" | ||
"go.temporal.io/api/workflowservice/v1" | ||
"go.temporal.io/sdk/client" | ||
"go.temporal.io/sdk/workflow" | ||
"google.golang.org/grpc" | ||
) | ||
|
||
const expectedResult = "Hello World" | ||
|
||
var numEagerlyStarted atomic.Uint64 | ||
|
||
var Feature = harness.Feature{ | ||
Workflows: Workflow, | ||
StartWorkflowOptions: client.StartWorkflowOptions{EnableEagerStart: true, WorkflowTaskTimeout: 1 * time.Hour}, | ||
CheckResult: CheckResult, | ||
ClientOptions: client.Options{ | ||
ConnectionOptions: client.ConnectionOptions{ | ||
DialOptions: []grpc.DialOption{grpc.WithUnaryInterceptor(EagerDetector(&numEagerlyStarted))}, | ||
}, | ||
}, | ||
} | ||
|
||
// A "hello world" workflow | ||
func Workflow(ctx workflow.Context) (string, error) { | ||
return expectedResult, nil | ||
} | ||
|
||
func CheckResult(ctx context.Context, runner *harness.Runner, run client.WorkflowRun) error { | ||
var result string | ||
if err := run.Get(ctx, &result); err != nil { | ||
return err | ||
} | ||
if result != expectedResult { | ||
return fmt.Errorf("expected %s, got: %s", expectedResult, result) | ||
} | ||
if numEager := numEagerlyStarted.Load(); numEager != 1 { | ||
// There is no way to check that this dynamic config is enabled in the namespace, | ||
// unless we run this test... | ||
// Instead of failing the test just skip it. | ||
msg := fmt.Sprintf("Enable dynamic config system.enableEagerWorkflowStart=true: numEagerlyStarted=%d", numEager) | ||
return runner.Skip(msg) | ||
} | ||
return nil | ||
} | ||
|
||
func EagerDetector(cntEager *atomic.Uint64) grpc.UnaryClientInterceptor { | ||
return func(ctx context.Context, method string, req, response interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { | ||
request_eager := false | ||
switch o := req.(type) { | ||
case *workflowservice.StartWorkflowExecutionRequest: | ||
request_eager = o.RequestEagerExecution | ||
} | ||
|
||
err := invoker(ctx, method, req, response, cc, opts...) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
switch o := response.(type) { | ||
case *workflowservice.StartWorkflowExecutionResponse: | ||
if request_eager && o.GetEagerWorkflowTask() != nil { | ||
cntEager.Add(1) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters