Skip to content

Commit a3fe700

Browse files
Adding ability to provide cancellation reason to cancelWorkflow API (#1213)
1 parent 67036c4 commit a3fe700

File tree

5 files changed

+181
-108
lines changed

5 files changed

+181
-108
lines changed

client/client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ type (
162162
// - BadRequestError
163163
// - InternalServiceError
164164
// - WorkflowExecutionAlreadyCompletedError
165-
CancelWorkflow(ctx context.Context, workflowID string, runID string) error
165+
CancelWorkflow(ctx context.Context, workflowID string, runID string, opts ...internal.Option) error
166166

167167
// TerminateWorkflow terminates a workflow execution.
168168
// workflowID is required, other parameters are optional.

internal/client.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,18 @@ const (
4545
QueryTypeOpenSessions string = "__open_sessions"
4646
)
4747

48+
type Option interface{ private() }
49+
50+
type cancelReason string
51+
52+
func (cancelReason) private() {}
53+
54+
func WithCancelReason(reason string) Option {
55+
return cancelReason(reason)
56+
}
57+
4858
type (
59+
4960
// Client is the client for starting and getting information about a workflow executions as well as
5061
// completing activities asynchronously.
5162
Client interface {
@@ -139,7 +150,7 @@ type (
139150
// - BadRequestError
140151
// - InternalServiceError
141152
// - WorkflowExecutionAlreadyCompletedError
142-
CancelWorkflow(ctx context.Context, workflowID string, runID string) error
153+
CancelWorkflow(ctx context.Context, workflowID string, runID string, opts ...Option) error
143154

144155
// TerminateWorkflow terminates a workflow execution.
145156
// workflowID is required, other parameters are optional.

internal/internal_workflow_client.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ func (wc *workflowClient) SignalWithStartWorkflow(ctx context.Context, workflowI
458458
// CancelWorkflow cancels a workflow in execution. It allows workflow to properly clean up and gracefully close.
459459
// workflowID is required, other parameters are optional.
460460
// If runID is omit, it will terminate currently running workflow (if there is one) based on the workflowID.
461-
func (wc *workflowClient) CancelWorkflow(ctx context.Context, workflowID string, runID string) error {
461+
func (wc *workflowClient) CancelWorkflow(ctx context.Context, workflowID string, runID string, opts ...Option) error {
462462
request := &s.RequestCancelWorkflowExecutionRequest{
463463
Domain: common.StringPtr(wc.domain),
464464
WorkflowExecution: &s.WorkflowExecution{
@@ -468,6 +468,14 @@ func (wc *workflowClient) CancelWorkflow(ctx context.Context, workflowID string,
468468
Identity: common.StringPtr(wc.identity),
469469
}
470470

471+
for _, opt := range opts {
472+
switch o := opt.(type) {
473+
case cancelReason:
474+
cause := string(o)
475+
request.Cause = &cause
476+
}
477+
}
478+
471479
return backoff.Retry(ctx,
472480
func() error {
473481
tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags)

internal/internal_workflow_client_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,3 +1403,44 @@ func serializeEvents(events []*shared.HistoryEvent) *shared.DataBlob {
14031403
Data: blob.Data,
14041404
}
14051405
}
1406+
1407+
func (s *workflowClientTestSuite) TestCancelWorkflow() {
1408+
s.service.EXPECT().RequestCancelWorkflowExecution(gomock.Any(), newPartialCancelRequestMatcher(common.StringPtr("testWf"), common.StringPtr("test reason")), gomock.All(gomock.Any())).Return(nil)
1409+
1410+
err := s.client.CancelWorkflow(context.Background(), "testWf", "testRun", WithCancelReason("test reason"))
1411+
1412+
s.Nil(err)
1413+
}
1414+
1415+
func (s *workflowClientTestSuite) TestCancelWorkflowBackwardsCompatible() {
1416+
s.service.EXPECT().RequestCancelWorkflowExecution(gomock.Any(), newPartialCancelRequestMatcher(common.StringPtr("testWf"), nil), gomock.All(gomock.Any())).Return(nil)
1417+
1418+
err := s.client.CancelWorkflow(context.Background(), "testWf", "testRun")
1419+
1420+
s.Nil(err)
1421+
}
1422+
1423+
type PartialCancelRequestMatcher struct {
1424+
wfId *string
1425+
cause *string
1426+
}
1427+
1428+
func newPartialCancelRequestMatcher(wfId *string, cause *string) gomock.Matcher {
1429+
return &PartialCancelRequestMatcher{
1430+
wfId: wfId,
1431+
cause: cause,
1432+
}
1433+
}
1434+
1435+
func (m *PartialCancelRequestMatcher) Matches(a interface{}) bool {
1436+
aEx, ok := a.(*shared.RequestCancelWorkflowExecutionRequest)
1437+
if !ok {
1438+
return false
1439+
}
1440+
1441+
return (aEx.Cause == m.cause || *aEx.Cause == *m.cause) && *aEx.WorkflowExecution.WorkflowId == *m.wfId
1442+
}
1443+
1444+
func (m *PartialCancelRequestMatcher) String() string {
1445+
return "partial cancellation request matcher matches cause and wfId fields"
1446+
}

0 commit comments

Comments
 (0)