go.uber.org/cadence@v1.2.9/internal/internal_workflow_client.go (about)

     1  // Copyright (c) 2017-2020 Uber Technologies Inc.
     2  // Portions of the Software are attributed to Copyright (c) 2020 Temporal Technologies Inc.
     3  //
     4  // Permission is hereby granted, free of charge, to any person obtaining a copy
     5  // of this software and associated documentation files (the "Software"), to deal
     6  // in the Software without restriction, including without limitation the rights
     7  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8  // copies of the Software, and to permit persons to whom the Software is
     9  // furnished to do so, subject to the following conditions:
    10  //
    11  // The above copyright notice and this permission notice shall be included in
    12  // all copies or substantial portions of the Software.
    13  //
    14  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    20  // THE SOFTWARE.
    21  
    22  package internal
    23  
    24  import (
    25  	"context"
    26  	"encoding/json"
    27  	"errors"
    28  	"fmt"
    29  	"reflect"
    30  	"time"
    31  
    32  	"go.uber.org/cadence/internal/common/serializer"
    33  
    34  	"github.com/opentracing/opentracing-go"
    35  	"github.com/pborman/uuid"
    36  	"github.com/uber-go/tally"
    37  
    38  	"go.uber.org/cadence/.gen/go/cadence/workflowserviceclient"
    39  	s "go.uber.org/cadence/.gen/go/shared"
    40  	"go.uber.org/cadence/internal/common"
    41  	"go.uber.org/cadence/internal/common/backoff"
    42  	"go.uber.org/cadence/internal/common/metrics"
    43  )
    44  
    45  // Assert that structs do indeed implement the interfaces
    46  var _ Client = (*workflowClient)(nil)
    47  var _ DomainClient = (*domainClient)(nil)
    48  
    49  const (
    50  	defaultDecisionTaskTimeoutInSecs = 10
    51  	defaultGetHistoryTimeoutInSecs   = 25
    52  )
    53  
    54  var (
    55  	maxListArchivedWorkflowTimeout = time.Minute * 3
    56  )
    57  
    58  type (
    59  	// workflowClient is the client for starting a workflow execution.
    60  	workflowClient struct {
    61  		workflowService    workflowserviceclient.Interface
    62  		domain             string
    63  		registry           *registry
    64  		metricsScope       *metrics.TaggedScope
    65  		identity           string
    66  		dataConverter      DataConverter
    67  		contextPropagators []ContextPropagator
    68  		tracer             opentracing.Tracer
    69  		featureFlags       FeatureFlags
    70  	}
    71  
    72  	// domainClient is the client for managing domains.
    73  	domainClient struct {
    74  		workflowService workflowserviceclient.Interface
    75  		metricsScope    tally.Scope
    76  		identity        string
    77  		featureFlags    FeatureFlags
    78  	}
    79  
    80  	// WorkflowRun represents a started non child workflow
    81  	WorkflowRun interface {
    82  		// GetID return workflow ID, which will be same as StartWorkflowOptions.ID if provided.
    83  		GetID() string
    84  
    85  		// GetRunID return the first started workflow run ID (please see below)
    86  		GetRunID() string
    87  
    88  		// Get will fill the workflow execution result to valuePtr,
    89  		// if workflow execution is a success, or return corresponding,
    90  		// error. This is a blocking API.
    91  		Get(ctx context.Context, valuePtr interface{}) error
    92  
    93  		// NOTE: if the started workflow return ContinueAsNewError during the workflow execution, the
    94  		// return result of GetRunID() will be the started workflow run ID, not the new run ID caused by ContinueAsNewError,
    95  		// however, Get(ctx context.Context, valuePtr interface{}) will return result from the run which did not return ContinueAsNewError.
    96  		// Say ExecuteWorkflow started a workflow, in its first run, has run ID "run ID 1", and returned ContinueAsNewError,
    97  		// the second run has run ID "run ID 2" and return some result other than ContinueAsNewError:
    98  		// GetRunID() will always return "run ID 1" and  Get(ctx context.Context, valuePtr interface{}) will return the result of second run.
    99  		// NOTE: DO NOT USE client.ExecuteWorkflow API INSIDE A WORKFLOW, USE workflow.ExecuteChildWorkflow instead
   100  	}
   101  
   102  	// workflowRunImpl is an implementation of WorkflowRun
   103  	workflowRunImpl struct {
   104  		workflowFn    interface{}
   105  		workflowID    string
   106  		firstRunID    string
   107  		currentRunID  string
   108  		iterFn        func(ctx context.Context, runID string) HistoryEventIterator
   109  		dataConverter DataConverter
   110  		registry      *registry
   111  	}
   112  
   113  	// HistoryEventIterator represents the interface for
   114  	// history event iterator
   115  	HistoryEventIterator interface {
   116  		// HasNext return whether this iterator has next value
   117  		HasNext() bool
   118  		// Next returns the next history events and error
   119  		// The errors it can return:
   120  		//	- EntityNotExistsError
   121  		//	- BadRequestError
   122  		//	- InternalServiceError
   123  		Next() (*s.HistoryEvent, error)
   124  	}
   125  
   126  	// historyEventIteratorImpl is the implementation of HistoryEventIterator
   127  	historyEventIteratorImpl struct {
   128  		// whether this iterator is initialized
   129  		initialized bool
   130  		// local cached history events and corresponding consuming index
   131  		nextEventIndex int
   132  		events         []*s.HistoryEvent
   133  		// token to get next page of history events
   134  		nexttoken []byte
   135  		// err when getting next page of history events
   136  		err error
   137  		// func which use a next token to get next page of history events
   138  		paginate func(nexttoken []byte) (*s.GetWorkflowExecutionHistoryResponse, error)
   139  	}
   140  )
   141  
   142  // StartWorkflow starts a workflow execution
   143  // The user can use this to start using a functor like.
   144  // Either by
   145  //
   146  //	StartWorkflow(options, "workflowTypeName", arg1, arg2, arg3)
   147  //	or
   148  //	StartWorkflow(options, workflowExecuteFn, arg1, arg2, arg3)
   149  //
   150  // The current timeout resolution implementation is in seconds and uses math.Ceil(d.Seconds()) as the duration. But is
   151  // subjected to change in the future.
   152  func (wc *workflowClient) StartWorkflow(
   153  	ctx context.Context,
   154  	options StartWorkflowOptions,
   155  	workflowFunc interface{},
   156  	args ...interface{},
   157  ) (*WorkflowExecution, error) {
   158  	workflowID := options.ID
   159  	if len(workflowID) == 0 {
   160  		workflowID = uuid.NewRandom().String()
   161  	}
   162  
   163  	if options.TaskList == "" {
   164  		return nil, errors.New("missing TaskList")
   165  	}
   166  
   167  	executionTimeout := common.Int32Ceil(options.ExecutionStartToCloseTimeout.Seconds())
   168  	if executionTimeout <= 0 {
   169  		return nil, errors.New("missing or invalid ExecutionStartToCloseTimeout")
   170  	}
   171  
   172  	decisionTaskTimeout := common.Int32Ceil(options.DecisionTaskStartToCloseTimeout.Seconds())
   173  	if decisionTaskTimeout < 0 {
   174  		return nil, errors.New("negative DecisionTaskStartToCloseTimeout provided")
   175  	}
   176  	if decisionTaskTimeout == 0 {
   177  		decisionTaskTimeout = defaultDecisionTaskTimeoutInSecs
   178  	}
   179  
   180  	// Validate type and its arguments.
   181  	workflowType, input, err := getValidatedWorkflowFunction(workflowFunc, args, wc.dataConverter, wc.registry)
   182  	if err != nil {
   183  		return nil, err
   184  	}
   185  
   186  	memo, err := getWorkflowMemo(options.Memo, wc.dataConverter)
   187  	if err != nil {
   188  		return nil, err
   189  	}
   190  
   191  	searchAttr, err := serializeSearchAttributes(options.SearchAttributes)
   192  	if err != nil {
   193  		return nil, err
   194  	}
   195  
   196  	delayStartSeconds := common.Int32Ceil(options.DelayStart.Seconds())
   197  	if delayStartSeconds < 0 {
   198  		return nil, errors.New("Invalid DelayStart option")
   199  	}
   200  
   201  	jitterStartSeconds := common.Int32Ceil(options.JitterStart.Seconds())
   202  	if jitterStartSeconds < 0 {
   203  		return nil, errors.New("Invalid JitterStart option")
   204  	}
   205  
   206  	// create a workflow start span and attach it to the context object.
   207  	// N.B. we need to finish this immediately as jaeger does not give us a way
   208  	// to recreate a span given a span context - which means we will run into
   209  	// issues during replay. we work around this by creating and ending the
   210  	// workflow start span and passing in that context to the workflow. So
   211  	// everything beginning with the StartWorkflowExecutionRequest will be
   212  	// parented by the created start workflow span.
   213  	ctx, span := createOpenTracingWorkflowSpan(ctx, wc.tracer, time.Now(), fmt.Sprintf("StartWorkflow-%s", workflowType.Name), workflowID)
   214  	span.Finish()
   215  
   216  	// get workflow headers from the context
   217  	header := wc.getWorkflowHeader(ctx)
   218  
   219  	// run propagators to extract information about tracing and other stuff, store in headers field
   220  	startRequest := &s.StartWorkflowExecutionRequest{
   221  		Domain:                              common.StringPtr(wc.domain),
   222  		RequestId:                           common.StringPtr(uuid.New()),
   223  		WorkflowId:                          common.StringPtr(workflowID),
   224  		WorkflowType:                        workflowTypePtr(*workflowType),
   225  		TaskList:                            common.TaskListPtr(s.TaskList{Name: common.StringPtr(options.TaskList)}),
   226  		Input:                               input,
   227  		ExecutionStartToCloseTimeoutSeconds: common.Int32Ptr(executionTimeout),
   228  		TaskStartToCloseTimeoutSeconds:      common.Int32Ptr(decisionTaskTimeout),
   229  		Identity:                            common.StringPtr(wc.identity),
   230  		WorkflowIdReusePolicy:               options.WorkflowIDReusePolicy.toThriftPtr(),
   231  		RetryPolicy:                         convertRetryPolicy(options.RetryPolicy),
   232  		CronSchedule:                        common.StringPtr(options.CronSchedule),
   233  		Memo:                                memo,
   234  		SearchAttributes:                    searchAttr,
   235  		Header:                              header,
   236  		DelayStartSeconds:                   common.Int32Ptr(delayStartSeconds),
   237  		JitterStartSeconds:                  common.Int32Ptr(jitterStartSeconds),
   238  	}
   239  
   240  	var response *s.StartWorkflowExecutionResponse
   241  
   242  	// Start creating workflow request.
   243  	err = backoff.Retry(ctx,
   244  		func() error {
   245  			tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags)
   246  			defer cancel()
   247  
   248  			var err1 error
   249  			response, err1 = wc.workflowService.StartWorkflowExecution(tchCtx, startRequest, opt...)
   250  			return err1
   251  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
   252  
   253  	if err != nil {
   254  		return nil, err
   255  	}
   256  
   257  	if wc.metricsScope != nil {
   258  		scope := wc.metricsScope.GetTaggedScope(tagTaskList, options.TaskList, tagWorkflowType, workflowType.Name)
   259  		scope.Counter(metrics.WorkflowStartCounter).Inc(1)
   260  	}
   261  
   262  	executionInfo := &WorkflowExecution{
   263  		ID:    workflowID,
   264  		RunID: response.GetRunId()}
   265  	return executionInfo, nil
   266  }
   267  
   268  // ExecuteWorkflow starts a workflow execution and returns a WorkflowRun that will allow you to wait until this workflow
   269  // reaches the end state, such as workflow finished successfully or timeout.
   270  // The user can use this to start using a functor like below and get the workflow execution result, as Value
   271  // Either by
   272  //
   273  //	ExecuteWorkflow(options, "workflowTypeName", arg1, arg2, arg3)
   274  //	or
   275  //	ExecuteWorkflow(options, workflowExecuteFn, arg1, arg2, arg3)
   276  //
   277  // The current timeout resolution implementation is in seconds and uses math.Ceil(d.Seconds()) as the duration. But is
   278  // subjected to change in the future.
   279  // NOTE: the context.Context should have a fairly large timeout, since workflow execution may take a while to be finished
   280  func (wc *workflowClient) ExecuteWorkflow(ctx context.Context, options StartWorkflowOptions, workflow interface{}, args ...interface{}) (WorkflowRun, error) {
   281  
   282  	// start the workflow execution
   283  	var runID string
   284  	var workflowID string
   285  	executionInfo, err := wc.StartWorkflow(ctx, options, workflow, args...)
   286  	if err != nil {
   287  		if alreadyStartedErr, ok := err.(*s.WorkflowExecutionAlreadyStartedError); ok {
   288  			runID = alreadyStartedErr.GetRunId()
   289  			// Assumption is that AlreadyStarted is never returned when options.ID is empty as UUID generated by
   290  			// StartWorkflow is not going to collide ever.
   291  			workflowID = options.ID
   292  		} else {
   293  			return nil, err
   294  		}
   295  	} else {
   296  		runID = executionInfo.RunID
   297  		workflowID = executionInfo.ID
   298  	}
   299  
   300  	iterFn := func(fnCtx context.Context, fnRunID string) HistoryEventIterator {
   301  		return wc.GetWorkflowHistory(fnCtx, workflowID, fnRunID, true, s.HistoryEventFilterTypeCloseEvent)
   302  	}
   303  
   304  	return &workflowRunImpl{
   305  		workflowFn:    workflow,
   306  		workflowID:    workflowID,
   307  		firstRunID:    runID,
   308  		currentRunID:  runID,
   309  		iterFn:        iterFn,
   310  		dataConverter: wc.dataConverter,
   311  		registry:      wc.registry,
   312  	}, nil
   313  }
   314  
   315  // GetWorkflow gets a workflow execution and returns a WorkflowRun that will allow you to wait until this workflow
   316  // reaches the end state, such as workflow finished successfully or timeout.
   317  // The current timeout resolution implementation is in seconds and uses math.Ceil(d.Seconds()) as the duration. But is
   318  // subjected to change in the future.
   319  func (wc *workflowClient) GetWorkflow(ctx context.Context, workflowID string, runID string) WorkflowRun {
   320  
   321  	iterFn := func(fnCtx context.Context, fnRunID string) HistoryEventIterator {
   322  		return wc.GetWorkflowHistory(fnCtx, workflowID, fnRunID, true, s.HistoryEventFilterTypeCloseEvent)
   323  	}
   324  
   325  	return &workflowRunImpl{
   326  		workflowID:    workflowID,
   327  		firstRunID:    runID,
   328  		currentRunID:  runID,
   329  		iterFn:        iterFn,
   330  		dataConverter: wc.dataConverter,
   331  		registry:      wc.registry,
   332  	}
   333  }
   334  
   335  // SignalWorkflow signals a workflow in execution.
   336  func (wc *workflowClient) SignalWorkflow(ctx context.Context, workflowID string, runID string, signalName string, arg interface{}) error {
   337  	input, err := encodeArg(wc.dataConverter, arg)
   338  	if err != nil {
   339  		return err
   340  	}
   341  	return signalWorkflow(ctx, wc.workflowService, wc.identity, wc.domain, workflowID, runID, signalName, input, wc.featureFlags)
   342  }
   343  
   344  // SignalWithStartWorkflow sends a signal to a running workflow.
   345  // If the workflow is not running or not found, it starts the workflow and then sends the signal in transaction.
   346  func (wc *workflowClient) SignalWithStartWorkflow(ctx context.Context, workflowID string, signalName string, signalArg interface{},
   347  	options StartWorkflowOptions, workflowFunc interface{}, workflowArgs ...interface{}) (*WorkflowExecution, error) {
   348  
   349  	signalInput, err := encodeArg(wc.dataConverter, signalArg)
   350  	if err != nil {
   351  		return nil, err
   352  	}
   353  
   354  	if workflowID == "" {
   355  		workflowID = uuid.NewRandom().String()
   356  	}
   357  
   358  	if options.TaskList == "" {
   359  		return nil, errors.New("missing TaskList")
   360  	}
   361  
   362  	executionTimeout := common.Int32Ceil(options.ExecutionStartToCloseTimeout.Seconds())
   363  	if executionTimeout <= 0 {
   364  		return nil, errors.New("missing or invalid ExecutionStartToCloseTimeout")
   365  	}
   366  
   367  	decisionTaskTimeout := common.Int32Ceil(options.DecisionTaskStartToCloseTimeout.Seconds())
   368  	if decisionTaskTimeout < 0 {
   369  		return nil, errors.New("negative DecisionTaskStartToCloseTimeout provided")
   370  	}
   371  	if decisionTaskTimeout == 0 {
   372  		decisionTaskTimeout = defaultDecisionTaskTimeoutInSecs
   373  	}
   374  
   375  	// Validate type and its arguments.
   376  	workflowType, input, err := getValidatedWorkflowFunction(workflowFunc, workflowArgs, wc.dataConverter, wc.registry)
   377  	if err != nil {
   378  		return nil, err
   379  	}
   380  
   381  	memo, err := getWorkflowMemo(options.Memo, wc.dataConverter)
   382  	if err != nil {
   383  		return nil, err
   384  	}
   385  
   386  	searchAttr, err := serializeSearchAttributes(options.SearchAttributes)
   387  	if err != nil {
   388  		return nil, err
   389  	}
   390  
   391  	delayStartSeconds := common.Int32Ceil(options.DelayStart.Seconds())
   392  	if delayStartSeconds < 0 {
   393  		return nil, errors.New("Invalid DelayStart option")
   394  	}
   395  
   396  	jitterStartSeconds := common.Int32Ceil(options.JitterStart.Seconds())
   397  	if jitterStartSeconds < 0 {
   398  		return nil, errors.New("Invalid JitterStart option")
   399  	}
   400  
   401  	// create a workflow start span and attach it to the context object. finish it immediately
   402  	ctx, span := createOpenTracingWorkflowSpan(ctx, wc.tracer, time.Now(), fmt.Sprintf("SignalWithStartWorkflow-%s", workflowType.Name), workflowID)
   403  	span.Finish()
   404  
   405  	// get workflow headers from the context
   406  	header := wc.getWorkflowHeader(ctx)
   407  
   408  	signalWithStartRequest := &s.SignalWithStartWorkflowExecutionRequest{
   409  		Domain:                              common.StringPtr(wc.domain),
   410  		RequestId:                           common.StringPtr(uuid.New()),
   411  		WorkflowId:                          common.StringPtr(workflowID),
   412  		WorkflowType:                        workflowTypePtr(*workflowType),
   413  		TaskList:                            common.TaskListPtr(s.TaskList{Name: common.StringPtr(options.TaskList)}),
   414  		Input:                               input,
   415  		ExecutionStartToCloseTimeoutSeconds: common.Int32Ptr(executionTimeout),
   416  		TaskStartToCloseTimeoutSeconds:      common.Int32Ptr(decisionTaskTimeout),
   417  		SignalName:                          common.StringPtr(signalName),
   418  		SignalInput:                         signalInput,
   419  		Identity:                            common.StringPtr(wc.identity),
   420  		RetryPolicy:                         convertRetryPolicy(options.RetryPolicy),
   421  		CronSchedule:                        common.StringPtr(options.CronSchedule),
   422  		Memo:                                memo,
   423  		SearchAttributes:                    searchAttr,
   424  		WorkflowIdReusePolicy:               options.WorkflowIDReusePolicy.toThriftPtr(),
   425  		Header:                              header,
   426  		DelayStartSeconds:                   common.Int32Ptr(delayStartSeconds),
   427  		JitterStartSeconds:                  common.Int32Ptr(jitterStartSeconds),
   428  	}
   429  
   430  	var response *s.StartWorkflowExecutionResponse
   431  
   432  	// Start creating workflow request.
   433  	err = backoff.Retry(ctx,
   434  		func() error {
   435  			tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags)
   436  			defer cancel()
   437  
   438  			var err1 error
   439  			response, err1 = wc.workflowService.SignalWithStartWorkflowExecution(tchCtx, signalWithStartRequest, opt...)
   440  			return err1
   441  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
   442  
   443  	if err != nil {
   444  		return nil, err
   445  	}
   446  
   447  	if wc.metricsScope != nil {
   448  		scope := wc.metricsScope.GetTaggedScope(tagTaskList, options.TaskList, tagWorkflowType, workflowType.Name)
   449  		scope.Counter(metrics.WorkflowSignalWithStartCounter).Inc(1)
   450  	}
   451  
   452  	executionInfo := &WorkflowExecution{
   453  		ID:    options.ID,
   454  		RunID: response.GetRunId()}
   455  	return executionInfo, nil
   456  }
   457  
   458  // CancelWorkflow cancels a workflow in execution.  It allows workflow to properly clean up and gracefully close.
   459  // workflowID is required, other parameters are optional.
   460  // 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, opts ...Option) error {
   462  	request := &s.RequestCancelWorkflowExecutionRequest{
   463  		Domain: common.StringPtr(wc.domain),
   464  		WorkflowExecution: &s.WorkflowExecution{
   465  			WorkflowId: common.StringPtr(workflowID),
   466  			RunId:      getRunID(runID),
   467  		},
   468  		Identity: common.StringPtr(wc.identity),
   469  	}
   470  
   471  	for _, opt := range opts {
   472  		switch o := opt.(type) {
   473  		case CancelReason:
   474  			cause := string(o)
   475  			request.Cause = &cause
   476  		}
   477  	}
   478  
   479  	return backoff.Retry(ctx,
   480  		func() error {
   481  			tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags)
   482  			defer cancel()
   483  			return wc.workflowService.RequestCancelWorkflowExecution(tchCtx, request, opt...)
   484  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
   485  }
   486  
   487  // TerminateWorkflow terminates a workflow execution.
   488  // workflowID is required, other parameters are optional.
   489  // If runID is omit, it will terminate currently running workflow (if there is one) based on the workflowID.
   490  func (wc *workflowClient) TerminateWorkflow(ctx context.Context, workflowID string, runID string, reason string, details []byte) error {
   491  	request := &s.TerminateWorkflowExecutionRequest{
   492  		Domain: common.StringPtr(wc.domain),
   493  		WorkflowExecution: &s.WorkflowExecution{
   494  			WorkflowId: common.StringPtr(workflowID),
   495  			RunId:      getRunID(runID),
   496  		},
   497  		Reason:   common.StringPtr(reason),
   498  		Details:  details,
   499  		Identity: common.StringPtr(wc.identity),
   500  	}
   501  
   502  	err := backoff.Retry(ctx,
   503  		func() error {
   504  			tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags)
   505  			defer cancel()
   506  			return wc.workflowService.TerminateWorkflowExecution(tchCtx, request, opt...)
   507  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
   508  
   509  	return err
   510  }
   511  
   512  // GetWorkflowHistory return a channel which contains the history events of a given workflow
   513  func (wc *workflowClient) GetWorkflowHistory(
   514  	ctx context.Context,
   515  	workflowID string,
   516  	runID string,
   517  	isLongPoll bool,
   518  	filterType s.HistoryEventFilterType,
   519  ) HistoryEventIterator {
   520  
   521  	domain := wc.domain
   522  	paginate := func(nextToken []byte) (*s.GetWorkflowExecutionHistoryResponse, error) {
   523  		request := &s.GetWorkflowExecutionHistoryRequest{
   524  			Domain: common.StringPtr(domain),
   525  			Execution: &s.WorkflowExecution{
   526  				WorkflowId: common.StringPtr(workflowID),
   527  				RunId:      getRunID(runID),
   528  			},
   529  			WaitForNewEvent:        common.BoolPtr(isLongPoll),
   530  			HistoryEventFilterType: &filterType,
   531  			NextPageToken:          nextToken,
   532  			SkipArchival:           common.BoolPtr(isLongPoll),
   533  		}
   534  
   535  		var response *s.GetWorkflowExecutionHistoryResponse
   536  		var err error
   537  	Loop:
   538  		for {
   539  			var isFinalLongPoll bool
   540  			err = backoff.Retry(ctx,
   541  				func() error {
   542  					var err1 error
   543  					tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags, func(builder *contextBuilder) {
   544  						if isLongPoll {
   545  							builder.Timeout = defaultGetHistoryTimeoutInSecs * time.Second
   546  							deadline, ok := ctx.Deadline()
   547  							if ok && deadline.Before(time.Now().Add(builder.Timeout)) {
   548  								// insufficient time for another poll, so this needs to be the last attempt
   549  								isFinalLongPoll = true
   550  							}
   551  						}
   552  					})
   553  					defer cancel()
   554  					response, err1 = wc.workflowService.GetWorkflowExecutionHistory(tchCtx, request, opt...)
   555  
   556  					if err1 != nil {
   557  						return err1
   558  					}
   559  
   560  					if response.RawHistory != nil {
   561  						history, err := serializer.DeserializeBlobDataToHistoryEvents(response.RawHistory, filterType)
   562  						if err != nil {
   563  							return err
   564  						}
   565  						response.History = history
   566  					}
   567  					return err1
   568  				},
   569  				createDynamicServiceRetryPolicy(ctx),
   570  				func(err error) bool {
   571  					return isServiceTransientError(err) || isEntityNonExistFromPassive(err)
   572  				},
   573  			)
   574  
   575  			if err != nil {
   576  				return nil, err
   577  			}
   578  			if isLongPoll && len(response.History.Events) == 0 && len(response.NextPageToken) != 0 {
   579  				if isFinalLongPoll {
   580  					// essentially a deadline exceeded, the last attempt did not get a result.
   581  					// this is necessary because the server does not know if we are able to try again,
   582  					// so it returns an empty result slightly before a timeout occurs, so the next
   583  					// attempt's token can be returned if it wishes to retry.
   584  					return nil, fmt.Errorf("timed out waiting for the workflow to finish: %w", context.DeadlineExceeded)
   585  				}
   586  				request.NextPageToken = response.NextPageToken
   587  				continue Loop
   588  			}
   589  			break Loop
   590  		}
   591  		return response, nil
   592  	}
   593  
   594  	return &historyEventIteratorImpl{
   595  		paginate: paginate,
   596  	}
   597  }
   598  
   599  func isEntityNonExistFromPassive(err error) bool {
   600  	if nonExistError, ok := err.(*s.EntityNotExistsError); ok {
   601  		return nonExistError.GetActiveCluster() != "" &&
   602  			nonExistError.GetCurrentCluster() != "" &&
   603  			nonExistError.GetActiveCluster() != nonExistError.GetCurrentCluster()
   604  	}
   605  
   606  	return false
   607  }
   608  
   609  // CompleteActivity reports activity completed. activity Execute method can return activity.ErrResultPending to
   610  // indicate the activity is not completed when it's Execute method returns. In that case, this CompleteActivity() method
   611  // should be called when that activity is completed with the actual result and error. If err is nil, activity task
   612  // completed event will be reported; if err is CanceledError, activity task cancelled event will be reported; otherwise,
   613  // activity task failed event will be reported.
   614  func (wc *workflowClient) CompleteActivity(ctx context.Context, taskToken []byte, result interface{}, err error) error {
   615  	if taskToken == nil {
   616  		return errors.New("invalid task token provided")
   617  	}
   618  
   619  	var data []byte
   620  	if result != nil {
   621  		var err0 error
   622  		data, err0 = encodeArg(wc.dataConverter, result)
   623  		if err0 != nil {
   624  			return err0
   625  		}
   626  	}
   627  	request := convertActivityResultToRespondRequest(wc.identity, taskToken, data, err, wc.dataConverter)
   628  	return reportActivityComplete(ctx, wc.workflowService, request, wc.metricsScope, wc.featureFlags)
   629  }
   630  
   631  // CompleteActivityById reports activity completed. Similar to CompleteActivity
   632  // It takes domain name, workflowID, runID, activityID as arguments.
   633  func (wc *workflowClient) CompleteActivityByID(ctx context.Context, domain, workflowID, runID, activityID string,
   634  	result interface{}, err error) error {
   635  
   636  	if activityID == "" || workflowID == "" || domain == "" {
   637  		return errors.New("empty activity or workflow id or domainName")
   638  	}
   639  
   640  	var data []byte
   641  	if result != nil {
   642  		var err0 error
   643  		data, err0 = encodeArg(wc.dataConverter, result)
   644  		if err0 != nil {
   645  			return err0
   646  		}
   647  	}
   648  
   649  	request := convertActivityResultToRespondRequestByID(wc.identity, domain, workflowID, runID, activityID, data, err, wc.dataConverter)
   650  	return reportActivityCompleteByID(ctx, wc.workflowService, request, wc.metricsScope, wc.featureFlags)
   651  }
   652  
   653  // RecordActivityHeartbeat records heartbeat for an activity.
   654  func (wc *workflowClient) RecordActivityHeartbeat(ctx context.Context, taskToken []byte, details ...interface{}) error {
   655  	data, err := encodeArgs(wc.dataConverter, details)
   656  	if err != nil {
   657  		return err
   658  	}
   659  	return recordActivityHeartbeat(ctx, wc.workflowService, wc.identity, taskToken, data, wc.featureFlags)
   660  }
   661  
   662  // RecordActivityHeartbeatByID records heartbeat for an activity.
   663  func (wc *workflowClient) RecordActivityHeartbeatByID(ctx context.Context,
   664  	domain, workflowID, runID, activityID string, details ...interface{}) error {
   665  	data, err := encodeArgs(wc.dataConverter, details)
   666  	if err != nil {
   667  		return err
   668  	}
   669  	return recordActivityHeartbeatByID(ctx, wc.workflowService, wc.identity, domain, workflowID, runID, activityID, data, wc.featureFlags)
   670  }
   671  
   672  // ListClosedWorkflow gets closed workflow executions based on request filters
   673  // The errors it can throw:
   674  //   - BadRequestError
   675  //   - InternalServiceError
   676  //   - EntityNotExistError
   677  func (wc *workflowClient) ListClosedWorkflow(ctx context.Context, request *s.ListClosedWorkflowExecutionsRequest) (*s.ListClosedWorkflowExecutionsResponse, error) {
   678  	if len(request.GetDomain()) == 0 {
   679  		request.Domain = common.StringPtr(wc.domain)
   680  	}
   681  	var response *s.ListClosedWorkflowExecutionsResponse
   682  	err := backoff.Retry(ctx,
   683  		func() error {
   684  			var err1 error
   685  			tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags)
   686  			defer cancel()
   687  			response, err1 = wc.workflowService.ListClosedWorkflowExecutions(tchCtx, request, opt...)
   688  			return err1
   689  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
   690  	if err != nil {
   691  		return nil, err
   692  	}
   693  	return response, nil
   694  }
   695  
   696  // ListOpenWorkflow gets open workflow executions based on request filters
   697  // The errors it can throw:
   698  //   - BadRequestError
   699  //   - InternalServiceError
   700  //   - EntityNotExistError
   701  func (wc *workflowClient) ListOpenWorkflow(ctx context.Context, request *s.ListOpenWorkflowExecutionsRequest) (*s.ListOpenWorkflowExecutionsResponse, error) {
   702  	if len(request.GetDomain()) == 0 {
   703  		request.Domain = common.StringPtr(wc.domain)
   704  	}
   705  	var response *s.ListOpenWorkflowExecutionsResponse
   706  	err := backoff.Retry(ctx,
   707  		func() error {
   708  			var err1 error
   709  			tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags)
   710  			defer cancel()
   711  			response, err1 = wc.workflowService.ListOpenWorkflowExecutions(tchCtx, request, opt...)
   712  			return err1
   713  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
   714  	if err != nil {
   715  		return nil, err
   716  	}
   717  	return response, nil
   718  }
   719  
   720  // ListWorkflow implementation
   721  func (wc *workflowClient) ListWorkflow(ctx context.Context, request *s.ListWorkflowExecutionsRequest) (*s.ListWorkflowExecutionsResponse, error) {
   722  	if len(request.GetDomain()) == 0 {
   723  		request.Domain = common.StringPtr(wc.domain)
   724  	}
   725  	var response *s.ListWorkflowExecutionsResponse
   726  	err := backoff.Retry(ctx,
   727  		func() error {
   728  			var err1 error
   729  			tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags)
   730  			defer cancel()
   731  			response, err1 = wc.workflowService.ListWorkflowExecutions(tchCtx, request, opt...)
   732  			return err1
   733  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
   734  	if err != nil {
   735  		return nil, err
   736  	}
   737  	return response, nil
   738  }
   739  
   740  // ListArchivedWorkflow implementation
   741  func (wc *workflowClient) ListArchivedWorkflow(ctx context.Context, request *s.ListArchivedWorkflowExecutionsRequest) (*s.ListArchivedWorkflowExecutionsResponse, error) {
   742  	if len(request.GetDomain()) == 0 {
   743  		request.Domain = common.StringPtr(wc.domain)
   744  	}
   745  	var response *s.ListArchivedWorkflowExecutionsResponse
   746  	err := backoff.Retry(ctx,
   747  		func() error {
   748  			var err1 error
   749  			timeout := maxListArchivedWorkflowTimeout
   750  			now := time.Now()
   751  			if ctx != nil {
   752  				if expiration, ok := ctx.Deadline(); ok && expiration.After(now) {
   753  					timeout = expiration.Sub(now)
   754  					if timeout > maxListArchivedWorkflowTimeout {
   755  						timeout = maxListArchivedWorkflowTimeout
   756  					} else if timeout < minRPCTimeout {
   757  						timeout = minRPCTimeout
   758  					}
   759  				}
   760  			}
   761  			tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags, chanTimeout(timeout))
   762  			defer cancel()
   763  			response, err1 = wc.workflowService.ListArchivedWorkflowExecutions(tchCtx, request, opt...)
   764  			return err1
   765  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
   766  	if err != nil {
   767  		return nil, err
   768  	}
   769  	return response, nil
   770  }
   771  
   772  // ScanWorkflow implementation
   773  func (wc *workflowClient) ScanWorkflow(ctx context.Context, request *s.ListWorkflowExecutionsRequest) (*s.ListWorkflowExecutionsResponse, error) {
   774  	if len(request.GetDomain()) == 0 {
   775  		request.Domain = common.StringPtr(wc.domain)
   776  	}
   777  	var response *s.ListWorkflowExecutionsResponse
   778  	err := backoff.Retry(ctx,
   779  		func() error {
   780  			var err1 error
   781  			tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags)
   782  			defer cancel()
   783  			response, err1 = wc.workflowService.ScanWorkflowExecutions(tchCtx, request, opt...)
   784  			return err1
   785  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
   786  	if err != nil {
   787  		return nil, err
   788  	}
   789  	return response, nil
   790  }
   791  
   792  // CountWorkflow implementation
   793  func (wc *workflowClient) CountWorkflow(ctx context.Context, request *s.CountWorkflowExecutionsRequest) (*s.CountWorkflowExecutionsResponse, error) {
   794  	if len(request.GetDomain()) == 0 {
   795  		request.Domain = common.StringPtr(wc.domain)
   796  	}
   797  	var response *s.CountWorkflowExecutionsResponse
   798  	err := backoff.Retry(ctx,
   799  		func() error {
   800  			var err1 error
   801  			tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags)
   802  			defer cancel()
   803  			response, err1 = wc.workflowService.CountWorkflowExecutions(tchCtx, request, opt...)
   804  			return err1
   805  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
   806  	if err != nil {
   807  		return nil, err
   808  	}
   809  	return response, nil
   810  }
   811  
   812  // ResetWorkflow implementation
   813  func (wc *workflowClient) ResetWorkflow(ctx context.Context, request *s.ResetWorkflowExecutionRequest) (*s.ResetWorkflowExecutionResponse, error) {
   814  	if len(request.GetDomain()) == 0 {
   815  		request.Domain = common.StringPtr(wc.domain)
   816  	}
   817  	var response *s.ResetWorkflowExecutionResponse
   818  	err := backoff.Retry(ctx,
   819  		func() error {
   820  			var err1 error
   821  			tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags)
   822  			defer cancel()
   823  			response, err1 = wc.workflowService.ResetWorkflowExecution(tchCtx, request, opt...)
   824  			return err1
   825  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
   826  	if err != nil {
   827  		return nil, err
   828  	}
   829  	return response, nil
   830  }
   831  
   832  // GetSearchAttributes implementation
   833  func (wc *workflowClient) GetSearchAttributes(ctx context.Context) (*s.GetSearchAttributesResponse, error) {
   834  	var response *s.GetSearchAttributesResponse
   835  	err := backoff.Retry(ctx,
   836  		func() error {
   837  			var err1 error
   838  			tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags)
   839  			defer cancel()
   840  			response, err1 = wc.workflowService.GetSearchAttributes(tchCtx, opt...)
   841  			return err1
   842  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
   843  	if err != nil {
   844  		return nil, err
   845  	}
   846  	return response, nil
   847  }
   848  
   849  // DescribeWorkflowExecution returns information about the specified workflow execution.
   850  // The errors it can return:
   851  //   - BadRequestError
   852  //   - InternalServiceError
   853  //   - EntityNotExistError
   854  func (wc *workflowClient) DescribeWorkflowExecution(ctx context.Context, workflowID, runID string) (*s.DescribeWorkflowExecutionResponse, error) {
   855  	request := &s.DescribeWorkflowExecutionRequest{
   856  		Domain: common.StringPtr(wc.domain),
   857  		Execution: &s.WorkflowExecution{
   858  			WorkflowId: common.StringPtr(workflowID),
   859  			RunId:      common.StringPtr(runID),
   860  		},
   861  	}
   862  	var response *s.DescribeWorkflowExecutionResponse
   863  	err := backoff.Retry(ctx,
   864  		func() error {
   865  			var err1 error
   866  			tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags)
   867  			defer cancel()
   868  			response, err1 = wc.workflowService.DescribeWorkflowExecution(tchCtx, request, opt...)
   869  			return err1
   870  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
   871  	if err != nil {
   872  		return nil, err
   873  	}
   874  	return response, nil
   875  }
   876  
   877  // QueryWorkflow queries a given workflow execution
   878  // workflowID and queryType are required, other parameters are optional.
   879  // - workflow ID of the workflow.
   880  // - runID can be default(empty string). if empty string then it will pick the running execution of that workflow ID.
   881  // - taskList can be default(empty string). If empty string then it will pick the taskList of the running execution of that workflow ID.
   882  // - queryType is the type of the query.
   883  // - args... are the optional query parameters.
   884  // The errors it can return:
   885  //   - BadRequestError
   886  //   - InternalServiceError
   887  //   - EntityNotExistError
   888  //   - QueryFailError
   889  func (wc *workflowClient) QueryWorkflow(ctx context.Context, workflowID string, runID string, queryType string, args ...interface{}) (Value, error) {
   890  	queryWorkflowWithOptionsRequest := &QueryWorkflowWithOptionsRequest{
   891  		WorkflowID: workflowID,
   892  		RunID:      runID,
   893  		QueryType:  queryType,
   894  		Args:       args,
   895  	}
   896  	result, err := wc.QueryWorkflowWithOptions(ctx, queryWorkflowWithOptionsRequest)
   897  	if err != nil {
   898  		return nil, err
   899  	}
   900  	return result.QueryResult, nil
   901  }
   902  
   903  // QueryWorkflowWithOptionsRequest is the request to QueryWorkflowWithOptions
   904  type QueryWorkflowWithOptionsRequest struct {
   905  	// WorkflowID is a required field indicating the workflow which should be queried.
   906  	WorkflowID string
   907  
   908  	// RunID is an optional field used to identify a specific run of the queried workflow.
   909  	// If RunID is not provided the latest run will be used.
   910  	RunID string
   911  
   912  	// QueryType is a required field which specifies the query you want to run.
   913  	// By default, cadence supports "__stack_trace" as a standard query type, which will return string value
   914  	// representing the call stack of the target workflow. The target workflow could also setup different query handler to handle custom query types.
   915  	// See comments at workflow.SetQueryHandler(ctx Context, queryType string, handler interface{}) for more details on how to setup query handler within the target workflow.
   916  	QueryType string
   917  
   918  	// Args is an optional field used to identify the arguments passed to the query.
   919  	Args []interface{}
   920  
   921  	// QueryRejectCondition is an optional field used to reject queries based on workflow state.
   922  	// QueryRejectConditionNotOpen will reject queries to workflows which are not open
   923  	// QueryRejectConditionNotCompletedCleanly will reject queries to workflows which completed in any state other than completed (e.g. terminated, canceled timeout etc...)
   924  	QueryRejectCondition *s.QueryRejectCondition
   925  
   926  	// QueryConsistencyLevel is an optional field used to control the consistency level.
   927  	// QueryConsistencyLevelEventual means that query will eventually reflect up to date state of a workflow.
   928  	// QueryConsistencyLevelStrong means that query will reflect a workflow state of having applied all events which came before the query.
   929  	QueryConsistencyLevel *s.QueryConsistencyLevel
   930  }
   931  
   932  // QueryWorkflowWithOptionsResponse is the response to QueryWorkflowWithOptions
   933  type QueryWorkflowWithOptionsResponse struct {
   934  	// QueryResult contains the result of executing the query.
   935  	// This will only be set if the query was completed successfully and not rejected.
   936  	QueryResult Value
   937  
   938  	// QueryRejected contains information about the query rejection.
   939  	QueryRejected *s.QueryRejected
   940  }
   941  
   942  // QueryWorkflowWithOptions queries a given workflow execution and returns the query result synchronously.
   943  // See QueryWorkflowWithOptionsRequest and QueryWorkflowWithOptionsResult for more information.
   944  // The errors it can return:
   945  //   - BadRequestError
   946  //   - InternalServiceError
   947  //   - EntityNotExistError
   948  //   - QueryFailError
   949  func (wc *workflowClient) QueryWorkflowWithOptions(ctx context.Context, request *QueryWorkflowWithOptionsRequest) (*QueryWorkflowWithOptionsResponse, error) {
   950  	var input []byte
   951  	if len(request.Args) > 0 {
   952  		var err error
   953  		if input, err = encodeArgs(wc.dataConverter, request.Args); err != nil {
   954  			return nil, err
   955  		}
   956  	}
   957  	req := &s.QueryWorkflowRequest{
   958  		Domain: common.StringPtr(wc.domain),
   959  		Execution: &s.WorkflowExecution{
   960  			WorkflowId: common.StringPtr(request.WorkflowID),
   961  			RunId:      getRunID(request.RunID),
   962  		},
   963  		Query: &s.WorkflowQuery{
   964  			QueryType: common.StringPtr(request.QueryType),
   965  			QueryArgs: input,
   966  		},
   967  		QueryRejectCondition:  request.QueryRejectCondition,
   968  		QueryConsistencyLevel: request.QueryConsistencyLevel,
   969  	}
   970  
   971  	var resp *s.QueryWorkflowResponse
   972  	err := backoff.Retry(ctx,
   973  		func() error {
   974  			tchCtx, cancel, opt := newChannelContextForQuery(ctx, wc.featureFlags)
   975  			defer cancel()
   976  			var err error
   977  			resp, err = wc.workflowService.QueryWorkflow(tchCtx, req, opt...)
   978  			return err
   979  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
   980  	if err != nil {
   981  		return nil, err
   982  	}
   983  
   984  	if resp.QueryRejected != nil {
   985  		return &QueryWorkflowWithOptionsResponse{
   986  			QueryRejected: resp.QueryRejected,
   987  			QueryResult:   nil,
   988  		}, nil
   989  	}
   990  	return &QueryWorkflowWithOptionsResponse{
   991  		QueryRejected: nil,
   992  		QueryResult:   newEncodedValue(resp.QueryResult, wc.dataConverter),
   993  	}, nil
   994  }
   995  
   996  // DescribeTaskList returns information about the target tasklist, right now this API returns the
   997  // pollers which polled this tasklist in last few minutes.
   998  // - tasklist name of tasklist
   999  // - tasklistType type of tasklist, can be decision or activity
  1000  // The errors it can return:
  1001  //   - BadRequestError
  1002  //   - InternalServiceError
  1003  //   - EntityNotExistError
  1004  func (wc *workflowClient) DescribeTaskList(ctx context.Context, tasklist string, tasklistType s.TaskListType) (*s.DescribeTaskListResponse, error) {
  1005  	request := &s.DescribeTaskListRequest{
  1006  		Domain:       common.StringPtr(wc.domain),
  1007  		TaskList:     &s.TaskList{Name: common.StringPtr(tasklist)},
  1008  		TaskListType: &tasklistType,
  1009  	}
  1010  
  1011  	var resp *s.DescribeTaskListResponse
  1012  	err := backoff.Retry(ctx,
  1013  		func() error {
  1014  			tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags)
  1015  			defer cancel()
  1016  			var err error
  1017  			resp, err = wc.workflowService.DescribeTaskList(tchCtx, request, opt...)
  1018  			return err
  1019  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
  1020  	if err != nil {
  1021  		return nil, err
  1022  	}
  1023  
  1024  	return resp, nil
  1025  }
  1026  
  1027  // RefreshWorkflowTasks refreshes all the tasks of a given workflow.
  1028  // - workflow ID of the workflow.
  1029  // - runID can be default(empty string). if empty string then it will pick the running execution of that workflow ID.
  1030  // The errors it can return:
  1031  //   - BadRequestError
  1032  //   - DomainNotActiveError
  1033  //   - ServiceBusyError
  1034  //   - EntityNotExistError
  1035  func (wc *workflowClient) RefreshWorkflowTasks(ctx context.Context, workflowID, runID string) error {
  1036  	request := &s.RefreshWorkflowTasksRequest{
  1037  		Domain: common.StringPtr(wc.domain),
  1038  		Execution: &s.WorkflowExecution{
  1039  			WorkflowId: common.StringPtr(workflowID),
  1040  			RunId:      getRunID(runID),
  1041  		},
  1042  	}
  1043  
  1044  	return backoff.Retry(ctx,
  1045  		func() error {
  1046  			tchCtx, cancel, opt := newChannelContext(ctx, wc.featureFlags)
  1047  			defer cancel()
  1048  			return wc.workflowService.RefreshWorkflowTasks(tchCtx, request, opt...)
  1049  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
  1050  }
  1051  
  1052  func (wc *workflowClient) getWorkflowHeader(ctx context.Context) *s.Header {
  1053  	header := &s.Header{
  1054  		Fields: make(map[string][]byte),
  1055  	}
  1056  	writer := NewHeaderWriter(header)
  1057  	for _, ctxProp := range wc.contextPropagators {
  1058  		ctxProp.Inject(ctx, writer)
  1059  	}
  1060  	return header
  1061  }
  1062  
  1063  // Register a domain with cadence server
  1064  // The errors it can throw:
  1065  //   - DomainAlreadyExistsError
  1066  //   - BadRequestError
  1067  //   - InternalServiceError
  1068  func (dc *domainClient) Register(ctx context.Context, request *s.RegisterDomainRequest) error {
  1069  	return backoff.Retry(ctx,
  1070  		func() error {
  1071  			tchCtx, cancel, opt := newChannelContext(ctx, dc.featureFlags)
  1072  			defer cancel()
  1073  			return dc.workflowService.RegisterDomain(tchCtx, request, opt...)
  1074  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
  1075  }
  1076  
  1077  // Describe a domain. The domain has 3 part of information
  1078  // DomainInfo - Which has Name, Status, Description, Owner Email
  1079  // DomainConfiguration - Configuration like Workflow Execution Retention Period In Days, Whether to emit metrics.
  1080  // ReplicationConfiguration - replication config like clusters and active cluster name
  1081  // The errors it can throw:
  1082  //   - EntityNotExistsError
  1083  //   - BadRequestError
  1084  //   - InternalServiceError
  1085  func (dc *domainClient) Describe(ctx context.Context, name string) (*s.DescribeDomainResponse, error) {
  1086  	request := &s.DescribeDomainRequest{
  1087  		Name: common.StringPtr(name),
  1088  	}
  1089  
  1090  	var response *s.DescribeDomainResponse
  1091  	err := backoff.Retry(ctx,
  1092  		func() error {
  1093  			tchCtx, cancel, opt := newChannelContext(ctx, dc.featureFlags)
  1094  			defer cancel()
  1095  			var err error
  1096  			response, err = dc.workflowService.DescribeDomain(tchCtx, request, opt...)
  1097  			return err
  1098  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
  1099  	if err != nil {
  1100  		return nil, err
  1101  	}
  1102  	return response, nil
  1103  }
  1104  
  1105  // Update a domain.
  1106  // The errors it can throw:
  1107  //   - EntityNotExistsError
  1108  //   - BadRequestError
  1109  //   - InternalServiceError
  1110  func (dc *domainClient) Update(ctx context.Context, request *s.UpdateDomainRequest) error {
  1111  	return backoff.Retry(ctx,
  1112  		func() error {
  1113  			tchCtx, cancel, opt := newChannelContext(ctx, dc.featureFlags)
  1114  			defer cancel()
  1115  			_, err := dc.workflowService.UpdateDomain(tchCtx, request, opt...)
  1116  			return err
  1117  		}, createDynamicServiceRetryPolicy(ctx), isServiceTransientError)
  1118  }
  1119  
  1120  func getRunID(runID string) *string {
  1121  	if runID == "" {
  1122  		// Cadence Server will pick current runID if provided empty.
  1123  		return nil
  1124  	}
  1125  	return common.StringPtr(runID)
  1126  }
  1127  
  1128  func (iter *historyEventIteratorImpl) HasNext() bool {
  1129  	if iter.nextEventIndex < len(iter.events) || iter.err != nil {
  1130  		return true
  1131  	} else if !iter.initialized || len(iter.nexttoken) != 0 {
  1132  		iter.initialized = true
  1133  		response, err := iter.paginate(iter.nexttoken)
  1134  		iter.nextEventIndex = 0
  1135  		if err == nil {
  1136  			iter.events = response.History.Events
  1137  			iter.nexttoken = response.NextPageToken
  1138  			iter.err = nil
  1139  		} else {
  1140  			iter.events = nil
  1141  			iter.nexttoken = nil
  1142  			iter.err = err
  1143  		}
  1144  
  1145  		if iter.nextEventIndex < len(iter.events) || iter.err != nil {
  1146  			return true
  1147  		}
  1148  		return false
  1149  	}
  1150  
  1151  	return false
  1152  }
  1153  
  1154  func (iter *historyEventIteratorImpl) Next() (*s.HistoryEvent, error) {
  1155  	// if caller call the Next() when iteration is over, just return nil, nil
  1156  	if !iter.HasNext() {
  1157  		panic("HistoryEventIterator Next() called without checking HasNext()")
  1158  	}
  1159  
  1160  	// we have cached events
  1161  	if iter.nextEventIndex < len(iter.events) {
  1162  		index := iter.nextEventIndex
  1163  		iter.nextEventIndex++
  1164  		return iter.events[index], nil
  1165  	} else if iter.err != nil {
  1166  		// we have err, clear that iter.err and return err
  1167  		err := iter.err
  1168  		iter.err = nil
  1169  		return nil, err
  1170  	}
  1171  
  1172  	panic("HistoryEventIterator Next() should return either a history event or a err")
  1173  }
  1174  
  1175  func (workflowRun *workflowRunImpl) GetRunID() string {
  1176  	return workflowRun.firstRunID
  1177  }
  1178  
  1179  func (workflowRun *workflowRunImpl) GetID() string {
  1180  	return workflowRun.workflowID
  1181  }
  1182  
  1183  func (workflowRun *workflowRunImpl) Get(ctx context.Context, valuePtr interface{}) error {
  1184  
  1185  	iter := workflowRun.iterFn(ctx, workflowRun.currentRunID)
  1186  	if !iter.HasNext() {
  1187  		panic("could not get last history event for workflow")
  1188  	}
  1189  	closeEvent, err := iter.Next()
  1190  	if err != nil {
  1191  		return err
  1192  	}
  1193  
  1194  	switch closeEvent.GetEventType() {
  1195  	case s.EventTypeWorkflowExecutionCompleted:
  1196  		attributes := closeEvent.WorkflowExecutionCompletedEventAttributes
  1197  		if valuePtr == nil || attributes.Result == nil {
  1198  			return nil
  1199  		}
  1200  		rf := reflect.ValueOf(valuePtr)
  1201  		if rf.Type().Kind() != reflect.Ptr {
  1202  			return errors.New("value parameter is not a pointer")
  1203  		}
  1204  		err = deSerializeFunctionResult(workflowRun.workflowFn, attributes.Result, valuePtr, workflowRun.dataConverter, workflowRun.registry)
  1205  	case s.EventTypeWorkflowExecutionFailed:
  1206  		attributes := closeEvent.WorkflowExecutionFailedEventAttributes
  1207  		err = constructError(attributes.GetReason(), attributes.Details, workflowRun.dataConverter)
  1208  	case s.EventTypeWorkflowExecutionCanceled:
  1209  		attributes := closeEvent.WorkflowExecutionCanceledEventAttributes
  1210  		details := newEncodedValues(attributes.Details, workflowRun.dataConverter)
  1211  		err = NewCanceledError(details)
  1212  	case s.EventTypeWorkflowExecutionTerminated:
  1213  		err = newTerminatedError()
  1214  	case s.EventTypeWorkflowExecutionTimedOut:
  1215  		attributes := closeEvent.WorkflowExecutionTimedOutEventAttributes
  1216  		err = NewTimeoutError(attributes.GetTimeoutType())
  1217  	case s.EventTypeWorkflowExecutionContinuedAsNew:
  1218  		attributes := closeEvent.WorkflowExecutionContinuedAsNewEventAttributes
  1219  		workflowRun.currentRunID = attributes.GetNewExecutionRunId()
  1220  		return workflowRun.Get(ctx, valuePtr)
  1221  	default:
  1222  		err = fmt.Errorf("Unexpected event type %s when handling workflow execution result", closeEvent.GetEventType())
  1223  	}
  1224  	return err
  1225  }
  1226  
  1227  func getWorkflowMemo(input map[string]interface{}, dc DataConverter) (*s.Memo, error) {
  1228  	if input == nil {
  1229  		return nil, nil
  1230  	}
  1231  
  1232  	memo := make(map[string][]byte)
  1233  	for k, v := range input {
  1234  		memoBytes, err := encodeArg(dc, v)
  1235  		if err != nil {
  1236  			return nil, fmt.Errorf("encode workflow memo error: %v", err.Error())
  1237  		}
  1238  		memo[k] = memoBytes
  1239  	}
  1240  	return &s.Memo{Fields: memo}, nil
  1241  }
  1242  
  1243  func serializeSearchAttributes(input map[string]interface{}) (*s.SearchAttributes, error) {
  1244  	if input == nil {
  1245  		return nil, nil
  1246  	}
  1247  
  1248  	attr := make(map[string][]byte)
  1249  	for k, v := range input {
  1250  		attrBytes, err := json.Marshal(v)
  1251  		if err != nil {
  1252  			return nil, fmt.Errorf("encode search attribute [%s] error: %v", k, err)
  1253  		}
  1254  		attr[k] = attrBytes
  1255  	}
  1256  	return &s.SearchAttributes{IndexedFields: attr}, nil
  1257  }