diff --git a/.gen/go/shared/idl.go b/.gen/go/shared/idl.go index bfe6772a88d..1a1ed9a5fd7 100644 --- a/.gen/go/shared/idl.go +++ b/.gen/go/shared/idl.go @@ -30,8 +30,8 @@ var ThriftModule = &thriftreflect.ThriftModule{ Name: "shared", Package: "github.com/uber/cadence/.gen/go/shared", FilePath: "shared.thrift", - SHA1: "a0c5a7aa1c6f1a5ce46c994741f8c005d42dd0a2", + SHA1: "e92bac909809ac3c45b878593c2f3bb58e5fbf00", Raw: rawIDL, } -const rawIDL = "// Copyright (c) 2017 Uber Technologies, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nnamespace java com.uber.cadence\n\nexception BadRequestError {\n 1: required string message\n}\n\nexception InternalServiceError {\n 1: required string message\n}\n\nexception DomainAlreadyExistsError {\n 1: required string message\n}\n\nexception WorkflowExecutionAlreadyStartedError {\n 10: optional string message\n 20: optional string startRequestId\n 30: optional string runId\n}\n\nexception EntityNotExistsError {\n 1: required string message\n}\n\nexception ServiceBusyError {\n 1: required string message\n}\n\nexception CancellationAlreadyRequestedError {\n 1: required string message\n}\n\nexception QueryFailedError {\n 1: required string message\n}\n\nenum WorkflowIdReusePolicy {\n /*\n * allow start a workflow execution using the same workflow ID,\n * when workflow not running, and the last execution close state is in\n * [terminated, cancelled, timeouted, failed].\n */\n AllowDuplicateFailedOnly,\n /*\n * allow start a workflow execution using the same workflow ID,\n * when workflow not running.\n */\n AllowDuplicate,\n /*\n * do not allow start a workflow execution using the same workflow ID at all\n */\n RejectDuplicate,\n}\n\nenum DomainStatus {\n REGISTERED,\n DEPRECATED,\n DELETED,\n}\n\nenum TimeoutType {\n START_TO_CLOSE,\n SCHEDULE_TO_START,\n SCHEDULE_TO_CLOSE,\n HEARTBEAT,\n}\n\nenum DecisionType {\n ScheduleActivityTask,\n RequestCancelActivityTask,\n StartTimer,\n CompleteWorkflowExecution,\n FailWorkflowExecution,\n CancelTimer,\n CancelWorkflowExecution,\n RequestCancelExternalWorkflowExecution,\n RecordMarker,\n ContinueAsNewWorkflowExecution,\n StartChildWorkflowExecution,\n SignalExternalWorkflowExecution,\n}\n\nenum EventType {\n WorkflowExecutionStarted,\n WorkflowExecutionCompleted,\n WorkflowExecutionFailed,\n WorkflowExecutionTimedOut,\n DecisionTaskScheduled,\n DecisionTaskStarted,\n DecisionTaskCompleted,\n DecisionTaskTimedOut\n DecisionTaskFailed,\n ActivityTaskScheduled,\n ActivityTaskStarted,\n ActivityTaskCompleted,\n ActivityTaskFailed,\n ActivityTaskTimedOut,\n ActivityTaskCancelRequested,\n RequestCancelActivityTaskFailed,\n ActivityTaskCanceled,\n TimerStarted,\n TimerFired,\n CancelTimerFailed,\n TimerCanceled,\n WorkflowExecutionCancelRequested,\n WorkflowExecutionCanceled,\n RequestCancelExternalWorkflowExecutionInitiated,\n RequestCancelExternalWorkflowExecutionFailed,\n ExternalWorkflowExecutionCancelRequested,\n MarkerRecorded,\n WorkflowExecutionSignaled,\n WorkflowExecutionTerminated,\n WorkflowExecutionContinuedAsNew,\n StartChildWorkflowExecutionInitiated,\n StartChildWorkflowExecutionFailed,\n ChildWorkflowExecutionStarted,\n ChildWorkflowExecutionCompleted,\n ChildWorkflowExecutionFailed,\n ChildWorkflowExecutionCanceled,\n ChildWorkflowExecutionTimedOut,\n ChildWorkflowExecutionTerminated,\n SignalExternalWorkflowExecutionInitiated,\n SignalExternalWorkflowExecutionFailed,\n ExternalWorkflowExecutionSignaled,\n}\n\nenum DecisionTaskFailedCause {\n UNHANDLED_DECISION,\n BAD_SCHEDULE_ACTIVITY_ATTRIBUTES,\n BAD_REQUEST_CANCEL_ACTIVITY_ATTRIBUTES,\n BAD_START_TIMER_ATTRIBUTES,\n BAD_CANCEL_TIMER_ATTRIBUTES,\n BAD_RECORD_MARKER_ATTRIBUTES,\n BAD_COMPLETE_WORKFLOW_EXECUTION_ATTRIBUTES,\n BAD_FAIL_WORKFLOW_EXECUTION_ATTRIBUTES,\n BAD_CANCEL_WORKFLOW_EXECUTION_ATTRIBUTES,\n BAD_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_ATTRIBUTES,\n BAD_CONTINUE_AS_NEW_ATTRIBUTES,\n START_TIMER_DUPLICATE_ID,\n RESET_STICKY_TASKLIST,\n WORKFLOW_WORKER_UNHANDLED_FAILURE,\n BAD_SIGNAL_WORKFLOW_EXECUTION_ATTRIBUTES,\n}\n\nenum CancelExternalWorkflowExecutionFailedCause {\n UNKNOWN_EXTERNAL_WORKFLOW_EXECUTION,\n}\n\nenum SignalExternalWorkflowExecutionFailedCause {\n UNKNOWN_EXTERNAL_WORKFLOW_EXECUTION,\n}\n\nenum ChildWorkflowExecutionFailedCause {\n WORKFLOW_ALREADY_RUNNING,\n}\n\nenum WorkflowExecutionCloseStatus {\n COMPLETED,\n FAILED,\n CANCELED,\n TERMINATED,\n CONTINUED_AS_NEW,\n TIMED_OUT,\n}\n\nenum ChildPolicy {\n TERMINATE,\n REQUEST_CANCEL,\n ABANDON,\n}\n\nenum QueryTaskCompletedType {\n COMPLETED,\n FAILED,\n}\n\nenum PendingActivityState {\n SCHEDULED,\n STARTED,\n CANCEL_REQUESTED,\n}\n\nenum HistoryEventFilterType {\n ALL_EVENT,\n CLOSE_EVENT,\n}\n\nenum TaskListKind {\n NORMAL,\n STICKY,\n}\n\nstruct WorkflowType {\n 10: optional string name\n}\n\nstruct ActivityType {\n 10: optional string name\n}\n\nstruct TaskList {\n 10: optional string name\n 20: optional TaskListKind kind\n}\n\nstruct TaskListMetadata {\n 10: optional double maxTasksPerSecond\n}\n\nstruct WorkflowExecution {\n 10: optional string workflowId\n 20: optional string runId\n}\n\nstruct WorkflowExecutionInfo {\n 10: optional WorkflowExecution execution\n 20: optional WorkflowType type\n 30: optional i64 (js.type = \"Long\") startTime\n 40: optional i64 (js.type = \"Long\") closeTime\n 50: optional WorkflowExecutionCloseStatus closeStatus\n 60: optional i64 (js.type = \"Long\") historyLength\n}\n\nstruct WorkflowExecutionConfiguration {\n 10: optional TaskList taskList\n 20: optional i32 executionStartToCloseTimeoutSeconds\n 30: optional i32 taskStartToCloseTimeoutSeconds\n 40: optional ChildPolicy childPolicy\n}\n\nstruct TransientDecisionInfo {\n 10: optional HistoryEvent scheduledEvent\n 20: optional HistoryEvent startedEvent\n}\n\nstruct ScheduleActivityTaskDecisionAttributes {\n 10: optional string activityId\n 20: optional ActivityType activityType\n 25: optional string domain\n 30: optional TaskList taskList\n 40: optional binary input\n 45: optional i32 scheduleToCloseTimeoutSeconds\n 50: optional i32 scheduleToStartTimeoutSeconds\n 55: optional i32 startToCloseTimeoutSeconds\n 60: optional i32 heartbeatTimeoutSeconds\n}\n\nstruct RequestCancelActivityTaskDecisionAttributes {\n 10: optional string activityId\n}\n\nstruct StartTimerDecisionAttributes {\n 10: optional string timerId\n 20: optional i64 (js.type = \"Long\") startToFireTimeoutSeconds\n}\n\nstruct CompleteWorkflowExecutionDecisionAttributes {\n 10: optional binary result\n}\n\nstruct FailWorkflowExecutionDecisionAttributes {\n 10: optional string reason\n 20: optional binary details\n}\n\nstruct CancelTimerDecisionAttributes {\n 10: optional string timerId\n}\n\nstruct CancelWorkflowExecutionDecisionAttributes {\n 10: optional binary details\n}\n\nstruct RequestCancelExternalWorkflowExecutionDecisionAttributes {\n 10: optional string domain\n 20: optional string workflowId\n 30: optional string runId\n 40: optional binary control\n}\n\nstruct SignalExternalWorkflowExecutionDecisionAttributes {\n 10: optional string domain\n 20: optional WorkflowExecution execution\n 30: optional string signalName\n 40: optional binary input\n 50: optional binary control\n}\n\nstruct RecordMarkerDecisionAttributes {\n 10: optional string markerName\n 20: optional binary details\n}\n\nstruct ContinueAsNewWorkflowExecutionDecisionAttributes {\n 10: optional WorkflowType workflowType\n 20: optional TaskList taskList\n 30: optional binary input\n 40: optional i32 executionStartToCloseTimeoutSeconds\n 50: optional i32 taskStartToCloseTimeoutSeconds\n}\n\nstruct StartChildWorkflowExecutionDecisionAttributes {\n 10: optional string domain\n 20: optional string workflowId\n 30: optional WorkflowType workflowType\n 40: optional TaskList taskList\n 50: optional binary input\n 60: optional i32 executionStartToCloseTimeoutSeconds\n 70: optional i32 taskStartToCloseTimeoutSeconds\n 80: optional ChildPolicy childPolicy\n 90: optional binary control\n 100: optional WorkflowIdReusePolicy workflowIdReusePolicy\n}\n\nstruct Decision {\n 10: optional DecisionType decisionType\n 20: optional ScheduleActivityTaskDecisionAttributes scheduleActivityTaskDecisionAttributes\n 25: optional StartTimerDecisionAttributes startTimerDecisionAttributes\n 30: optional CompleteWorkflowExecutionDecisionAttributes completeWorkflowExecutionDecisionAttributes\n 35: optional FailWorkflowExecutionDecisionAttributes failWorkflowExecutionDecisionAttributes\n 40: optional RequestCancelActivityTaskDecisionAttributes requestCancelActivityTaskDecisionAttributes\n 50: optional CancelTimerDecisionAttributes cancelTimerDecisionAttributes\n 60: optional CancelWorkflowExecutionDecisionAttributes cancelWorkflowExecutionDecisionAttributes\n 70: optional RequestCancelExternalWorkflowExecutionDecisionAttributes requestCancelExternalWorkflowExecutionDecisionAttributes\n 80: optional RecordMarkerDecisionAttributes recordMarkerDecisionAttributes\n 90: optional ContinueAsNewWorkflowExecutionDecisionAttributes continueAsNewWorkflowExecutionDecisionAttributes\n 100: optional StartChildWorkflowExecutionDecisionAttributes startChildWorkflowExecutionDecisionAttributes\n 110: optional SignalExternalWorkflowExecutionDecisionAttributes signalExternalWorkflowExecutionDecisionAttributes\n}\n\nstruct WorkflowExecutionStartedEventAttributes {\n 10: optional WorkflowType workflowType\n 20: optional TaskList taskList\n 30: optional binary input\n 40: optional i32 executionStartToCloseTimeoutSeconds\n 50: optional i32 taskStartToCloseTimeoutSeconds\n 60: optional string identity\n}\n\nstruct WorkflowExecutionCompletedEventAttributes {\n 10: optional binary result\n 20: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct WorkflowExecutionFailedEventAttributes {\n 10: optional string reason\n 20: optional binary details\n 30: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct WorkflowExecutionTimedOutEventAttributes {\n 10: optional TimeoutType timeoutType\n}\n\nstruct WorkflowExecutionContinuedAsNewEventAttributes {\n 10: optional string newExecutionRunId\n 20: optional WorkflowType workflowType\n 30: optional TaskList taskList\n 40: optional binary input\n 50: optional i32 executionStartToCloseTimeoutSeconds\n 60: optional i32 taskStartToCloseTimeoutSeconds\n 70: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct DecisionTaskScheduledEventAttributes {\n 10: optional TaskList taskList\n 20: optional i32 startToCloseTimeoutSeconds\n 30: optional i64 (js.type = \"Long\") attempt\n}\n\nstruct DecisionTaskStartedEventAttributes {\n 10: optional i64 (js.type = \"Long\") scheduledEventId\n 20: optional string identity\n 30: optional string requestId\n}\n\nstruct DecisionTaskCompletedEventAttributes {\n 10: optional binary executionContext\n 20: optional i64 (js.type = \"Long\") scheduledEventId\n 30: optional i64 (js.type = \"Long\") startedEventId\n 40: optional string identity\n}\n\nstruct DecisionTaskTimedOutEventAttributes {\n 10: optional i64 (js.type = \"Long\") scheduledEventId\n 20: optional i64 (js.type = \"Long\") startedEventId\n 30: optional TimeoutType timeoutType\n}\n\nstruct DecisionTaskFailedEventAttributes {\n 10: optional i64 (js.type = \"Long\") scheduledEventId\n 20: optional i64 (js.type = \"Long\") startedEventId\n 30: optional DecisionTaskFailedCause cause\n 35: optional binary details\n 40: optional string identity\n}\n\nstruct ActivityTaskScheduledEventAttributes {\n 10: optional string activityId\n 20: optional ActivityType activityType\n 25: optional string domain\n 30: optional TaskList taskList\n 40: optional binary input\n 45: optional i32 scheduleToCloseTimeoutSeconds\n 50: optional i32 scheduleToStartTimeoutSeconds\n 55: optional i32 startToCloseTimeoutSeconds\n 60: optional i32 heartbeatTimeoutSeconds\n 90: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct ActivityTaskStartedEventAttributes {\n 10: optional i64 (js.type = \"Long\") scheduledEventId\n 20: optional string identity\n 30: optional string requestId\n}\n\nstruct ActivityTaskCompletedEventAttributes {\n 10: optional binary result\n 20: optional i64 (js.type = \"Long\") scheduledEventId\n 30: optional i64 (js.type = \"Long\") startedEventId\n 40: optional string identity\n}\n\nstruct ActivityTaskFailedEventAttributes {\n 10: optional string reason\n 20: optional binary details\n 30: optional i64 (js.type = \"Long\") scheduledEventId\n 40: optional i64 (js.type = \"Long\") startedEventId\n 50: optional string identity\n}\n\nstruct ActivityTaskTimedOutEventAttributes {\n 05: optional binary details\n 10: optional i64 (js.type = \"Long\") scheduledEventId\n 20: optional i64 (js.type = \"Long\") startedEventId\n 30: optional TimeoutType timeoutType\n}\n\nstruct ActivityTaskCancelRequestedEventAttributes {\n 10: optional string activityId\n 20: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct RequestCancelActivityTaskFailedEventAttributes{\n 10: optional string activityId\n 20: optional string cause\n 30: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct ActivityTaskCanceledEventAttributes {\n 10: optional binary details\n 20: optional i64 (js.type = \"Long\") latestCancelRequestedEventId\n 30: optional i64 (js.type = \"Long\") scheduledEventId\n 40: optional i64 (js.type = \"Long\") startedEventId\n 50: optional string identity\n}\n\nstruct TimerStartedEventAttributes {\n 10: optional string timerId\n 20: optional i64 (js.type = \"Long\") startToFireTimeoutSeconds\n 30: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct TimerFiredEventAttributes {\n 10: optional string timerId\n 20: optional i64 (js.type = \"Long\") startedEventId\n}\n\nstruct TimerCanceledEventAttributes {\n 10: optional string timerId\n 20: optional i64 (js.type = \"Long\") startedEventId\n 30: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n 40: optional string identity\n}\n\nstruct CancelTimerFailedEventAttributes {\n 10: optional string timerId\n 20: optional string cause\n 30: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n 40: optional string identity\n}\n\nstruct WorkflowExecutionCancelRequestedEventAttributes {\n 10: optional string cause\n 20: optional i64 (js.type = \"Long\") externalInitiatedEventId\n 30: optional WorkflowExecution externalWorkflowExecution\n 40: optional string identity\n}\n\nstruct WorkflowExecutionCanceledEventAttributes {\n 10: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n 20: optional binary details\n}\n\nstruct MarkerRecordedEventAttributes {\n 10: optional string markerName\n 20: optional binary details\n 30: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct WorkflowExecutionSignaledEventAttributes {\n 10: optional string signalName\n 20: optional binary input\n 30: optional string identity\n}\n\nstruct WorkflowExecutionTerminatedEventAttributes {\n 10: optional string reason\n 20: optional binary details\n 30: optional string identity\n}\n\nstruct RequestCancelExternalWorkflowExecutionInitiatedEventAttributes {\n 10: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n 20: optional string domain\n 30: optional WorkflowExecution workflowExecution\n 40: optional binary control\n}\n\nstruct RequestCancelExternalWorkflowExecutionFailedEventAttributes {\n 10: optional CancelExternalWorkflowExecutionFailedCause cause\n 20: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n 30: optional string domain\n 40: optional WorkflowExecution workflowExecution\n 50: optional i64 (js.type = \"Long\") initiatedEventId\n 60: optional binary control\n}\n\nstruct ExternalWorkflowExecutionCancelRequestedEventAttributes {\n 10: optional i64 (js.type = \"Long\") initiatedEventId\n 20: optional string domain\n 30: optional WorkflowExecution workflowExecution\n}\n\nstruct SignalExternalWorkflowExecutionInitiatedEventAttributes {\n 10: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n 20: optional string domain\n 30: optional WorkflowExecution workflowExecution\n 40: optional string signalName\n 50: optional binary input\n 60: optional binary control\n}\n\nstruct SignalExternalWorkflowExecutionFailedEventAttributes {\n 10: optional SignalExternalWorkflowExecutionFailedCause cause\n 20: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n 30: optional string domain\n 40: optional WorkflowExecution workflowExecution\n 50: optional i64 (js.type = \"Long\") initiatedEventId\n 60: optional binary control\n}\n\nstruct ExternalWorkflowExecutionSignaledEventAttributes {\n 10: optional i64 (js.type = \"Long\") initiatedEventId\n 20: optional string domain\n 30: optional WorkflowExecution workflowExecution\n 40: optional binary control\n}\n\nstruct StartChildWorkflowExecutionInitiatedEventAttributes {\n 10: optional string domain\n 20: optional string workflowId\n 30: optional WorkflowType workflowType\n 40: optional TaskList taskList\n 50: optional binary input\n 60: optional i32 executionStartToCloseTimeoutSeconds\n 70: optional i32 taskStartToCloseTimeoutSeconds\n 80: optional ChildPolicy childPolicy\n 90: optional binary control\n 100: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n 110: optional WorkflowIdReusePolicy workflowIdReusePolicy\n}\n\nstruct StartChildWorkflowExecutionFailedEventAttributes {\n 10: optional string domain\n 20: optional string workflowId\n 30: optional WorkflowType workflowType\n 40: optional ChildWorkflowExecutionFailedCause cause\n 50: optional binary control\n 60: optional i64 (js.type = \"Long\") initiatedEventId\n 70: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct ChildWorkflowExecutionStartedEventAttributes {\n 10: optional string domain\n 20: optional i64 (js.type = \"Long\") initiatedEventId\n 30: optional WorkflowExecution workflowExecution\n 40: optional WorkflowType workflowType\n}\n\nstruct ChildWorkflowExecutionCompletedEventAttributes {\n 10: optional binary result\n 20: optional string domain\n 30: optional WorkflowExecution workflowExecution\n 40: optional WorkflowType workflowType\n 50: optional i64 (js.type = \"Long\") initiatedEventId\n 60: optional i64 (js.type = \"Long\") startedEventId\n}\n\nstruct ChildWorkflowExecutionFailedEventAttributes {\n 10: optional string reason\n 20: optional binary details\n 30: optional string domain\n 40: optional WorkflowExecution workflowExecution\n 50: optional WorkflowType workflowType\n 60: optional i64 (js.type = \"Long\") initiatedEventId\n 70: optional i64 (js.type = \"Long\") startedEventId\n}\n\nstruct ChildWorkflowExecutionCanceledEventAttributes {\n 10: optional binary details\n 20: optional string domain\n 30: optional WorkflowExecution workflowExecution\n 40: optional WorkflowType workflowType\n 50: optional i64 (js.type = \"Long\") initiatedEventId\n 60: optional i64 (js.type = \"Long\") startedEventId\n}\n\nstruct ChildWorkflowExecutionTimedOutEventAttributes {\n 10: optional TimeoutType timeoutType\n 20: optional string domain\n 30: optional WorkflowExecution workflowExecution\n 40: optional WorkflowType workflowType\n 50: optional i64 (js.type = \"Long\") initiatedEventId\n 60: optional i64 (js.type = \"Long\") startedEventId\n}\n\nstruct ChildWorkflowExecutionTerminatedEventAttributes {\n 10: optional string domain\n 20: optional WorkflowExecution workflowExecution\n 30: optional WorkflowType workflowType\n 40: optional i64 (js.type = \"Long\") initiatedEventId\n 50: optional i64 (js.type = \"Long\") startedEventId\n}\n\nstruct HistoryEvent {\n 10: optional i64 (js.type = \"Long\") eventId\n 20: optional i64 (js.type = \"Long\") timestamp\n 30: optional EventType eventType\n 40: optional WorkflowExecutionStartedEventAttributes workflowExecutionStartedEventAttributes\n 50: optional WorkflowExecutionCompletedEventAttributes workflowExecutionCompletedEventAttributes\n 60: optional WorkflowExecutionFailedEventAttributes workflowExecutionFailedEventAttributes\n 70: optional WorkflowExecutionTimedOutEventAttributes workflowExecutionTimedOutEventAttributes\n 80: optional DecisionTaskScheduledEventAttributes decisionTaskScheduledEventAttributes\n 90: optional DecisionTaskStartedEventAttributes decisionTaskStartedEventAttributes\n 100: optional DecisionTaskCompletedEventAttributes decisionTaskCompletedEventAttributes\n 110: optional DecisionTaskTimedOutEventAttributes decisionTaskTimedOutEventAttributes\n 120: optional DecisionTaskFailedEventAttributes decisionTaskFailedEventAttributes\n 130: optional ActivityTaskScheduledEventAttributes activityTaskScheduledEventAttributes\n 140: optional ActivityTaskStartedEventAttributes activityTaskStartedEventAttributes\n 150: optional ActivityTaskCompletedEventAttributes activityTaskCompletedEventAttributes\n 160: optional ActivityTaskFailedEventAttributes activityTaskFailedEventAttributes\n 170: optional ActivityTaskTimedOutEventAttributes activityTaskTimedOutEventAttributes\n 180: optional TimerStartedEventAttributes timerStartedEventAttributes\n 190: optional TimerFiredEventAttributes timerFiredEventAttributes\n 200: optional ActivityTaskCancelRequestedEventAttributes activityTaskCancelRequestedEventAttributes\n 210: optional RequestCancelActivityTaskFailedEventAttributes requestCancelActivityTaskFailedEventAttributes\n 220: optional ActivityTaskCanceledEventAttributes activityTaskCanceledEventAttributes\n 230: optional TimerCanceledEventAttributes timerCanceledEventAttributes\n 240: optional CancelTimerFailedEventAttributes cancelTimerFailedEventAttributes\n 250: optional MarkerRecordedEventAttributes markerRecordedEventAttributes\n 260: optional WorkflowExecutionSignaledEventAttributes workflowExecutionSignaledEventAttributes\n 270: optional WorkflowExecutionTerminatedEventAttributes workflowExecutionTerminatedEventAttributes\n 280: optional WorkflowExecutionCancelRequestedEventAttributes workflowExecutionCancelRequestedEventAttributes\n 290: optional WorkflowExecutionCanceledEventAttributes workflowExecutionCanceledEventAttributes\n 300: optional RequestCancelExternalWorkflowExecutionInitiatedEventAttributes requestCancelExternalWorkflowExecutionInitiatedEventAttributes\n 310: optional RequestCancelExternalWorkflowExecutionFailedEventAttributes requestCancelExternalWorkflowExecutionFailedEventAttributes\n 320: optional ExternalWorkflowExecutionCancelRequestedEventAttributes externalWorkflowExecutionCancelRequestedEventAttributes\n 330: optional WorkflowExecutionContinuedAsNewEventAttributes workflowExecutionContinuedAsNewEventAttributes\n 340: optional StartChildWorkflowExecutionInitiatedEventAttributes startChildWorkflowExecutionInitiatedEventAttributes\n 350: optional StartChildWorkflowExecutionFailedEventAttributes startChildWorkflowExecutionFailedEventAttributes\n 360: optional ChildWorkflowExecutionStartedEventAttributes childWorkflowExecutionStartedEventAttributes\n 370: optional ChildWorkflowExecutionCompletedEventAttributes childWorkflowExecutionCompletedEventAttributes\n 380: optional ChildWorkflowExecutionFailedEventAttributes childWorkflowExecutionFailedEventAttributes\n 390: optional ChildWorkflowExecutionCanceledEventAttributes childWorkflowExecutionCanceledEventAttributes\n 400: optional ChildWorkflowExecutionTimedOutEventAttributes childWorkflowExecutionTimedOutEventAttributes\n 410: optional ChildWorkflowExecutionTerminatedEventAttributes childWorkflowExecutionTerminatedEventAttributes\n 420: optional SignalExternalWorkflowExecutionInitiatedEventAttributes signalExternalWorkflowExecutionInitiatedEventAttributes\n 430: optional SignalExternalWorkflowExecutionFailedEventAttributes signalExternalWorkflowExecutionFailedEventAttributes\n 440: optional ExternalWorkflowExecutionSignaledEventAttributes externalWorkflowExecutionSignaledEventAttributes\n}\n\nstruct History {\n 10: optional list events\n}\n\nstruct WorkflowExecutionFilter {\n 10: optional string workflowId\n}\n\nstruct WorkflowTypeFilter {\n 10: optional string name\n}\n\nstruct StartTimeFilter {\n 10: optional i64 (js.type = \"Long\") earliestTime\n 20: optional i64 (js.type = \"Long\") latestTime\n}\n\nstruct DomainInfo {\n 10: optional string name\n 20: optional DomainStatus status\n 30: optional string description\n 40: optional string ownerEmail\n}\n\nstruct DomainConfiguration {\n 10: optional i32 workflowExecutionRetentionPeriodInDays\n 20: optional bool emitMetric\n}\n\nstruct UpdateDomainInfo {\n 10: optional string description\n 20: optional string ownerEmail\n}\n\nstruct RegisterDomainRequest {\n 10: optional string name\n 20: optional string description\n 30: optional string ownerEmail\n 40: optional i32 workflowExecutionRetentionPeriodInDays\n 50: optional bool emitMetric\n}\n\nstruct DescribeDomainRequest {\n 10: optional string name\n}\n\nstruct DescribeDomainResponse {\n 10: optional DomainInfo domainInfo\n 20: optional DomainConfiguration configuration\n}\n\nstruct UpdateDomainRequest {\n 10: optional string name\n 20: optional UpdateDomainInfo updatedInfo\n 30: optional DomainConfiguration configuration\n}\n\nstruct UpdateDomainResponse {\n 10: optional DomainInfo domainInfo\n 20: optional DomainConfiguration configuration\n}\n\nstruct DeprecateDomainRequest {\n 10: optional string name\n}\n\nstruct StartWorkflowExecutionRequest {\n 10: optional string domain\n 20: optional string workflowId\n 30: optional WorkflowType workflowType\n 40: optional TaskList taskList\n 50: optional binary input\n 60: optional i32 executionStartToCloseTimeoutSeconds\n 70: optional i32 taskStartToCloseTimeoutSeconds\n 80: optional string identity\n 90: optional string requestId\n 100: optional WorkflowIdReusePolicy workflowIdReusePolicy\n}\n\nstruct StartWorkflowExecutionResponse {\n 10: optional string runId\n}\n\nstruct PollForDecisionTaskRequest {\n 10: optional string domain\n 20: optional TaskList taskList\n 30: optional string identity\n}\n\nstruct PollForDecisionTaskResponse {\n 10: optional binary taskToken\n 20: optional WorkflowExecution workflowExecution\n 30: optional WorkflowType workflowType\n 40: optional i64 (js.type = \"Long\") previousStartedEventId\n 50: optional i64 (js.type = \"Long\") startedEventId\n 51: optional i64 (js.type = 'Long') attempt\n 54: optional i64 (js.type = \"Long\") backlogCountHint\n 60: optional History history\n 70: optional binary nextPageToken\n 80: optional WorkflowQuery query\n}\n\nstruct StickyExecutionAttributes {\n 10: optional TaskList workerTaskList\n 20: optional i32 scheduleToStartTimeoutSeconds\n}\n\nstruct RespondDecisionTaskCompletedRequest {\n 10: optional binary taskToken\n 20: optional list decisions\n 30: optional binary executionContext\n 40: optional string identity\n 50: optional StickyExecutionAttributes stickyAttributes\n}\n\nstruct RespondDecisionTaskFailedRequest {\n 10: optional binary taskToken\n 20: optional DecisionTaskFailedCause cause\n 30: optional binary details\n 40: optional string identity\n}\n\nstruct PollForActivityTaskRequest {\n 10: optional string domain\n 20: optional TaskList taskList\n 30: optional string identity\n 40: optional TaskListMetadata taskListMetadata\n}\n\nstruct PollForActivityTaskResponse {\n 10: optional binary taskToken\n 20: optional WorkflowExecution workflowExecution\n 30: optional string activityId\n 40: optional ActivityType activityType\n 50: optional binary input\n 70: optional i64 (js.type = \"Long\") scheduledTimestamp\n 80: optional i32 scheduleToCloseTimeoutSeconds\n 90: optional i64 (js.type = \"Long\") startedTimestamp\n 100: optional i32 startToCloseTimeoutSeconds\n 110: optional i32 heartbeatTimeoutSeconds\n}\n\nstruct RecordActivityTaskHeartbeatRequest {\n 10: optional binary taskToken\n 20: optional binary details\n 30: optional string identity\n}\n\nstruct RecordActivityTaskHeartbeatResponse {\n 10: optional bool cancelRequested\n}\n\nstruct RespondActivityTaskCompletedRequest {\n 10: optional binary taskToken\n 20: optional binary result\n 30: optional string identity\n}\n\nstruct RespondActivityTaskFailedRequest {\n 10: optional binary taskToken\n 20: optional string reason\n 30: optional binary details\n 40: optional string identity\n}\n\nstruct RespondActivityTaskCanceledRequest {\n 10: optional binary taskToken\n 20: optional binary details\n 30: optional string identity\n}\n\nstruct RespondActivityTaskCompletedByIDRequest {\n 10: optional string domain\n 20: optional string workflowID\n 30: optional string runID\n 40: optional string activityID\n 50: optional binary result\n 60: optional string identity\n}\n\nstruct RespondActivityTaskFailedByIDRequest {\n 10: optional string domain\n 20: optional string workflowID\n 30: optional string runID\n 40: optional string activityID\n 50: optional string reason\n 60: optional binary details\n 70: optional string identity\n}\n\nstruct RespondActivityTaskCanceledByIDRequest {\n 10: optional string domain\n 20: optional string workflowID\n 30: optional string runID\n 40: optional string activityID\n 50: optional binary details\n 60: optional string identity\n}\n\nstruct RequestCancelWorkflowExecutionRequest {\n 10: optional string domain\n 20: optional WorkflowExecution workflowExecution\n 30: optional string identity\n 40: optional string requestId\n}\n\nstruct GetWorkflowExecutionHistoryRequest {\n 10: optional string domain\n 20: optional WorkflowExecution execution\n 30: optional i32 maximumPageSize\n 40: optional binary nextPageToken\n 50: optional bool waitForNewEvent\n 60: optional HistoryEventFilterType HistoryEventFilterType\n}\n\nstruct GetWorkflowExecutionHistoryResponse {\n 10: optional History history\n 20: optional binary nextPageToken\n}\n\nstruct SignalWorkflowExecutionRequest {\n 10: optional string domain\n 20: optional WorkflowExecution workflowExecution\n 30: optional string signalName\n 40: optional binary input\n 50: optional string identity\n 60: optional string requestId\n 70: optional binary control\n}\n\nstruct TerminateWorkflowExecutionRequest {\n 10: optional string domain\n 20: optional WorkflowExecution workflowExecution\n 30: optional string reason\n 40: optional binary details\n 50: optional string identity\n}\n\nstruct ListOpenWorkflowExecutionsRequest {\n 10: optional string domain\n 20: optional i32 maximumPageSize\n 30: optional binary nextPageToken\n 40: optional StartTimeFilter StartTimeFilter\n 50: optional WorkflowExecutionFilter executionFilter\n 60: optional WorkflowTypeFilter typeFilter\n}\n\nstruct ListOpenWorkflowExecutionsResponse {\n 10: optional list executions\n 20: optional binary nextPageToken\n}\n\nstruct ListClosedWorkflowExecutionsRequest {\n 10: optional string domain\n 20: optional i32 maximumPageSize\n 30: optional binary nextPageToken\n 40: optional StartTimeFilter StartTimeFilter\n 50: optional WorkflowExecutionFilter executionFilter\n 60: optional WorkflowTypeFilter typeFilter\n 70: optional WorkflowExecutionCloseStatus statusFilter\n}\n\nstruct ListClosedWorkflowExecutionsResponse {\n 10: optional list executions\n 20: optional binary nextPageToken\n}\n\nstruct QueryWorkflowRequest {\n 10: optional string domain\n 20: optional WorkflowExecution execution\n 30: optional WorkflowQuery query\n}\n\nstruct QueryWorkflowResponse {\n 10: optional binary queryResult\n}\n\nstruct WorkflowQuery {\n 10: optional string queryType\n 20: optional binary queryArgs\n}\n\nstruct RespondQueryTaskCompletedRequest {\n 10: optional binary taskToken\n 20: optional QueryTaskCompletedType completedType\n 30: optional binary queryResult\n 40: optional string errorMessage\n}\n\nstruct DescribeWorkflowExecutionRequest {\n 10: optional string domain\n 20: optional WorkflowExecution execution\n}\n\nstruct PendingActivityInfo {\n 10: optional string activityID\n 20: optional ActivityType activityType\n 30: optional PendingActivityState state\n 40: optional binary heartbeatDetails\n 50: optional i64 (js.type = \"Long\") lastHeartbeatTimestamp\n}\n\nstruct DescribeWorkflowExecutionResponse {\n 10: optional WorkflowExecutionConfiguration executionConfiguration\n 20: optional WorkflowExecutionInfo workflowExecutionInfo\n 30: optional list pendingActivities\n}\n\nstruct DescribeTaskListRequest {\n 10: optional string domain\n 20: optional TaskList taskList\n 30: optional TaskListType taskListType\n}\n\nstruct DescribeTaskListResponse {\n 10: optional list pollers\n}\n\nenum TaskListType {\n /*\n * Decision type of tasklist\n */\n Decision,\n /*\n * Activity type of tasklist\n */\n Activity,\n}\n\nstruct PollerInfo {\n // Unix Nano\n 10: optional i64 (js.type = \"Long\") lastAccessTime\n 20: optional string identity\n}\n" +const rawIDL = "// Copyright (c) 2017 Uber Technologies, Inc.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nnamespace java com.uber.cadence\n\nexception BadRequestError {\n 1: required string message\n}\n\nexception InternalServiceError {\n 1: required string message\n}\n\nexception DomainAlreadyExistsError {\n 1: required string message\n}\n\nexception WorkflowExecutionAlreadyStartedError {\n 10: optional string message\n 20: optional string startRequestId\n 30: optional string runId\n}\n\nexception EntityNotExistsError {\n 1: required string message\n}\n\nexception ServiceBusyError {\n 1: required string message\n}\n\nexception CancellationAlreadyRequestedError {\n 1: required string message\n}\n\nexception QueryFailedError {\n 1: required string message\n}\n\nenum WorkflowIdReusePolicy {\n /*\n * allow start a workflow execution using the same workflow ID,\n * when workflow not running, and the last execution close state is in\n * [terminated, cancelled, timeouted, failed].\n */\n AllowDuplicateFailedOnly,\n /*\n * allow start a workflow execution using the same workflow ID,\n * when workflow not running.\n */\n AllowDuplicate,\n /*\n * do not allow start a workflow execution using the same workflow ID at all\n */\n RejectDuplicate,\n}\n\nenum DomainStatus {\n REGISTERED,\n DEPRECATED,\n DELETED,\n}\n\nenum TimeoutType {\n START_TO_CLOSE,\n SCHEDULE_TO_START,\n SCHEDULE_TO_CLOSE,\n HEARTBEAT,\n}\n\nenum DecisionType {\n ScheduleActivityTask,\n RequestCancelActivityTask,\n StartTimer,\n CompleteWorkflowExecution,\n FailWorkflowExecution,\n CancelTimer,\n CancelWorkflowExecution,\n RequestCancelExternalWorkflowExecution,\n RecordMarker,\n ContinueAsNewWorkflowExecution,\n StartChildWorkflowExecution,\n SignalExternalWorkflowExecution,\n}\n\nenum EventType {\n WorkflowExecutionStarted,\n WorkflowExecutionCompleted,\n WorkflowExecutionFailed,\n WorkflowExecutionTimedOut,\n DecisionTaskScheduled,\n DecisionTaskStarted,\n DecisionTaskCompleted,\n DecisionTaskTimedOut\n DecisionTaskFailed,\n ActivityTaskScheduled,\n ActivityTaskStarted,\n ActivityTaskCompleted,\n ActivityTaskFailed,\n ActivityTaskTimedOut,\n ActivityTaskCancelRequested,\n RequestCancelActivityTaskFailed,\n ActivityTaskCanceled,\n TimerStarted,\n TimerFired,\n CancelTimerFailed,\n TimerCanceled,\n WorkflowExecutionCancelRequested,\n WorkflowExecutionCanceled,\n RequestCancelExternalWorkflowExecutionInitiated,\n RequestCancelExternalWorkflowExecutionFailed,\n ExternalWorkflowExecutionCancelRequested,\n MarkerRecorded,\n WorkflowExecutionSignaled,\n WorkflowExecutionTerminated,\n WorkflowExecutionContinuedAsNew,\n StartChildWorkflowExecutionInitiated,\n StartChildWorkflowExecutionFailed,\n ChildWorkflowExecutionStarted,\n ChildWorkflowExecutionCompleted,\n ChildWorkflowExecutionFailed,\n ChildWorkflowExecutionCanceled,\n ChildWorkflowExecutionTimedOut,\n ChildWorkflowExecutionTerminated,\n SignalExternalWorkflowExecutionInitiated,\n SignalExternalWorkflowExecutionFailed,\n ExternalWorkflowExecutionSignaled,\n}\n\nenum DecisionTaskFailedCause {\n UNHANDLED_DECISION,\n BAD_SCHEDULE_ACTIVITY_ATTRIBUTES,\n BAD_REQUEST_CANCEL_ACTIVITY_ATTRIBUTES,\n BAD_START_TIMER_ATTRIBUTES,\n BAD_CANCEL_TIMER_ATTRIBUTES,\n BAD_RECORD_MARKER_ATTRIBUTES,\n BAD_COMPLETE_WORKFLOW_EXECUTION_ATTRIBUTES,\n BAD_FAIL_WORKFLOW_EXECUTION_ATTRIBUTES,\n BAD_CANCEL_WORKFLOW_EXECUTION_ATTRIBUTES,\n BAD_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_ATTRIBUTES,\n BAD_CONTINUE_AS_NEW_ATTRIBUTES,\n START_TIMER_DUPLICATE_ID,\n RESET_STICKY_TASKLIST,\n WORKFLOW_WORKER_UNHANDLED_FAILURE,\n BAD_SIGNAL_WORKFLOW_EXECUTION_ATTRIBUTES,\n}\n\nenum CancelExternalWorkflowExecutionFailedCause {\n UNKNOWN_EXTERNAL_WORKFLOW_EXECUTION,\n}\n\nenum SignalExternalWorkflowExecutionFailedCause {\n UNKNOWN_EXTERNAL_WORKFLOW_EXECUTION,\n}\n\nenum ChildWorkflowExecutionFailedCause {\n WORKFLOW_ALREADY_RUNNING,\n}\n\nenum WorkflowExecutionCloseStatus {\n COMPLETED,\n FAILED,\n CANCELED,\n TERMINATED,\n CONTINUED_AS_NEW,\n TIMED_OUT,\n}\n\nenum ChildPolicy {\n TERMINATE,\n REQUEST_CANCEL,\n ABANDON,\n}\n\nenum QueryTaskCompletedType {\n COMPLETED,\n FAILED,\n}\n\nenum PendingActivityState {\n SCHEDULED,\n STARTED,\n CANCEL_REQUESTED,\n}\n\nenum HistoryEventFilterType {\n ALL_EVENT,\n CLOSE_EVENT,\n}\n\nenum TaskListKind {\n NORMAL,\n STICKY,\n}\n\nstruct WorkflowType {\n 10: optional string name\n}\n\nstruct ActivityType {\n 10: optional string name\n}\n\nstruct TaskList {\n 10: optional string name\n 20: optional TaskListKind kind\n}\n\nstruct TaskListMetadata {\n 10: optional double maxTasksPerSecond\n}\n\nstruct WorkflowExecution {\n 10: optional string workflowId\n 20: optional string runId\n}\n\nstruct WorkflowExecutionInfo {\n 10: optional WorkflowExecution execution\n 20: optional WorkflowType type\n 30: optional i64 (js.type = \"Long\") startTime\n 40: optional i64 (js.type = \"Long\") closeTime\n 50: optional WorkflowExecutionCloseStatus closeStatus\n 60: optional i64 (js.type = \"Long\") historyLength\n}\n\nstruct WorkflowExecutionConfiguration {\n 10: optional TaskList taskList\n 20: optional i32 executionStartToCloseTimeoutSeconds\n 30: optional i32 taskStartToCloseTimeoutSeconds\n 40: optional ChildPolicy childPolicy\n}\n\nstruct TransientDecisionInfo {\n 10: optional HistoryEvent scheduledEvent\n 20: optional HistoryEvent startedEvent\n}\n\nstruct ScheduleActivityTaskDecisionAttributes {\n 10: optional string activityId\n 20: optional ActivityType activityType\n 25: optional string domain\n 30: optional TaskList taskList\n 40: optional binary input\n 45: optional i32 scheduleToCloseTimeoutSeconds\n 50: optional i32 scheduleToStartTimeoutSeconds\n 55: optional i32 startToCloseTimeoutSeconds\n 60: optional i32 heartbeatTimeoutSeconds\n}\n\nstruct RequestCancelActivityTaskDecisionAttributes {\n 10: optional string activityId\n}\n\nstruct StartTimerDecisionAttributes {\n 10: optional string timerId\n 20: optional i64 (js.type = \"Long\") startToFireTimeoutSeconds\n}\n\nstruct CompleteWorkflowExecutionDecisionAttributes {\n 10: optional binary result\n}\n\nstruct FailWorkflowExecutionDecisionAttributes {\n 10: optional string reason\n 20: optional binary details\n}\n\nstruct CancelTimerDecisionAttributes {\n 10: optional string timerId\n}\n\nstruct CancelWorkflowExecutionDecisionAttributes {\n 10: optional binary details\n}\n\nstruct RequestCancelExternalWorkflowExecutionDecisionAttributes {\n 10: optional string domain\n 20: optional string workflowId\n 30: optional string runId\n 40: optional binary control\n}\n\nstruct SignalExternalWorkflowExecutionDecisionAttributes {\n 10: optional string domain\n 20: optional WorkflowExecution execution\n 30: optional string signalName\n 40: optional binary input\n 50: optional binary control\n}\n\nstruct RecordMarkerDecisionAttributes {\n 10: optional string markerName\n 20: optional binary details\n}\n\nstruct ContinueAsNewWorkflowExecutionDecisionAttributes {\n 10: optional WorkflowType workflowType\n 20: optional TaskList taskList\n 30: optional binary input\n 40: optional i32 executionStartToCloseTimeoutSeconds\n 50: optional i32 taskStartToCloseTimeoutSeconds\n}\n\nstruct StartChildWorkflowExecutionDecisionAttributes {\n 10: optional string domain\n 20: optional string workflowId\n 30: optional WorkflowType workflowType\n 40: optional TaskList taskList\n 50: optional binary input\n 60: optional i32 executionStartToCloseTimeoutSeconds\n 70: optional i32 taskStartToCloseTimeoutSeconds\n 80: optional ChildPolicy childPolicy\n 90: optional binary control\n 100: optional WorkflowIdReusePolicy workflowIdReusePolicy\n}\n\nstruct Decision {\n 10: optional DecisionType decisionType\n 20: optional ScheduleActivityTaskDecisionAttributes scheduleActivityTaskDecisionAttributes\n 25: optional StartTimerDecisionAttributes startTimerDecisionAttributes\n 30: optional CompleteWorkflowExecutionDecisionAttributes completeWorkflowExecutionDecisionAttributes\n 35: optional FailWorkflowExecutionDecisionAttributes failWorkflowExecutionDecisionAttributes\n 40: optional RequestCancelActivityTaskDecisionAttributes requestCancelActivityTaskDecisionAttributes\n 50: optional CancelTimerDecisionAttributes cancelTimerDecisionAttributes\n 60: optional CancelWorkflowExecutionDecisionAttributes cancelWorkflowExecutionDecisionAttributes\n 70: optional RequestCancelExternalWorkflowExecutionDecisionAttributes requestCancelExternalWorkflowExecutionDecisionAttributes\n 80: optional RecordMarkerDecisionAttributes recordMarkerDecisionAttributes\n 90: optional ContinueAsNewWorkflowExecutionDecisionAttributes continueAsNewWorkflowExecutionDecisionAttributes\n 100: optional StartChildWorkflowExecutionDecisionAttributes startChildWorkflowExecutionDecisionAttributes\n 110: optional SignalExternalWorkflowExecutionDecisionAttributes signalExternalWorkflowExecutionDecisionAttributes\n}\n\nstruct WorkflowExecutionStartedEventAttributes {\n 10: optional WorkflowType workflowType\n 20: optional TaskList taskList\n 30: optional binary input\n 40: optional i32 executionStartToCloseTimeoutSeconds\n 50: optional i32 taskStartToCloseTimeoutSeconds\n 60: optional string identity\n}\n\nstruct WorkflowExecutionCompletedEventAttributes {\n 10: optional binary result\n 20: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct WorkflowExecutionFailedEventAttributes {\n 10: optional string reason\n 20: optional binary details\n 30: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct WorkflowExecutionTimedOutEventAttributes {\n 10: optional TimeoutType timeoutType\n}\n\nstruct WorkflowExecutionContinuedAsNewEventAttributes {\n 10: optional string newExecutionRunId\n 20: optional WorkflowType workflowType\n 30: optional TaskList taskList\n 40: optional binary input\n 50: optional i32 executionStartToCloseTimeoutSeconds\n 60: optional i32 taskStartToCloseTimeoutSeconds\n 70: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct DecisionTaskScheduledEventAttributes {\n 10: optional TaskList taskList\n 20: optional i32 startToCloseTimeoutSeconds\n 30: optional i64 (js.type = \"Long\") attempt\n}\n\nstruct DecisionTaskStartedEventAttributes {\n 10: optional i64 (js.type = \"Long\") scheduledEventId\n 20: optional string identity\n 30: optional string requestId\n}\n\nstruct DecisionTaskCompletedEventAttributes {\n 10: optional binary executionContext\n 20: optional i64 (js.type = \"Long\") scheduledEventId\n 30: optional i64 (js.type = \"Long\") startedEventId\n 40: optional string identity\n}\n\nstruct DecisionTaskTimedOutEventAttributes {\n 10: optional i64 (js.type = \"Long\") scheduledEventId\n 20: optional i64 (js.type = \"Long\") startedEventId\n 30: optional TimeoutType timeoutType\n}\n\nstruct DecisionTaskFailedEventAttributes {\n 10: optional i64 (js.type = \"Long\") scheduledEventId\n 20: optional i64 (js.type = \"Long\") startedEventId\n 30: optional DecisionTaskFailedCause cause\n 35: optional binary details\n 40: optional string identity\n}\n\nstruct ActivityTaskScheduledEventAttributes {\n 10: optional string activityId\n 20: optional ActivityType activityType\n 25: optional string domain\n 30: optional TaskList taskList\n 40: optional binary input\n 45: optional i32 scheduleToCloseTimeoutSeconds\n 50: optional i32 scheduleToStartTimeoutSeconds\n 55: optional i32 startToCloseTimeoutSeconds\n 60: optional i32 heartbeatTimeoutSeconds\n 90: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct ActivityTaskStartedEventAttributes {\n 10: optional i64 (js.type = \"Long\") scheduledEventId\n 20: optional string identity\n 30: optional string requestId\n}\n\nstruct ActivityTaskCompletedEventAttributes {\n 10: optional binary result\n 20: optional i64 (js.type = \"Long\") scheduledEventId\n 30: optional i64 (js.type = \"Long\") startedEventId\n 40: optional string identity\n}\n\nstruct ActivityTaskFailedEventAttributes {\n 10: optional string reason\n 20: optional binary details\n 30: optional i64 (js.type = \"Long\") scheduledEventId\n 40: optional i64 (js.type = \"Long\") startedEventId\n 50: optional string identity\n}\n\nstruct ActivityTaskTimedOutEventAttributes {\n 05: optional binary details\n 10: optional i64 (js.type = \"Long\") scheduledEventId\n 20: optional i64 (js.type = \"Long\") startedEventId\n 30: optional TimeoutType timeoutType\n}\n\nstruct ActivityTaskCancelRequestedEventAttributes {\n 10: optional string activityId\n 20: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct RequestCancelActivityTaskFailedEventAttributes{\n 10: optional string activityId\n 20: optional string cause\n 30: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct ActivityTaskCanceledEventAttributes {\n 10: optional binary details\n 20: optional i64 (js.type = \"Long\") latestCancelRequestedEventId\n 30: optional i64 (js.type = \"Long\") scheduledEventId\n 40: optional i64 (js.type = \"Long\") startedEventId\n 50: optional string identity\n}\n\nstruct TimerStartedEventAttributes {\n 10: optional string timerId\n 20: optional i64 (js.type = \"Long\") startToFireTimeoutSeconds\n 30: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct TimerFiredEventAttributes {\n 10: optional string timerId\n 20: optional i64 (js.type = \"Long\") startedEventId\n}\n\nstruct TimerCanceledEventAttributes {\n 10: optional string timerId\n 20: optional i64 (js.type = \"Long\") startedEventId\n 30: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n 40: optional string identity\n}\n\nstruct CancelTimerFailedEventAttributes {\n 10: optional string timerId\n 20: optional string cause\n 30: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n 40: optional string identity\n}\n\nstruct WorkflowExecutionCancelRequestedEventAttributes {\n 10: optional string cause\n 20: optional i64 (js.type = \"Long\") externalInitiatedEventId\n 30: optional WorkflowExecution externalWorkflowExecution\n 40: optional string identity\n}\n\nstruct WorkflowExecutionCanceledEventAttributes {\n 10: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n 20: optional binary details\n}\n\nstruct MarkerRecordedEventAttributes {\n 10: optional string markerName\n 20: optional binary details\n 30: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct WorkflowExecutionSignaledEventAttributes {\n 10: optional string signalName\n 20: optional binary input\n 30: optional string identity\n}\n\nstruct WorkflowExecutionTerminatedEventAttributes {\n 10: optional string reason\n 20: optional binary details\n 30: optional string identity\n}\n\nstruct RequestCancelExternalWorkflowExecutionInitiatedEventAttributes {\n 10: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n 20: optional string domain\n 30: optional WorkflowExecution workflowExecution\n 40: optional binary control\n}\n\nstruct RequestCancelExternalWorkflowExecutionFailedEventAttributes {\n 10: optional CancelExternalWorkflowExecutionFailedCause cause\n 20: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n 30: optional string domain\n 40: optional WorkflowExecution workflowExecution\n 50: optional i64 (js.type = \"Long\") initiatedEventId\n 60: optional binary control\n}\n\nstruct ExternalWorkflowExecutionCancelRequestedEventAttributes {\n 10: optional i64 (js.type = \"Long\") initiatedEventId\n 20: optional string domain\n 30: optional WorkflowExecution workflowExecution\n}\n\nstruct SignalExternalWorkflowExecutionInitiatedEventAttributes {\n 10: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n 20: optional string domain\n 30: optional WorkflowExecution workflowExecution\n 40: optional string signalName\n 50: optional binary input\n 60: optional binary control\n}\n\nstruct SignalExternalWorkflowExecutionFailedEventAttributes {\n 10: optional SignalExternalWorkflowExecutionFailedCause cause\n 20: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n 30: optional string domain\n 40: optional WorkflowExecution workflowExecution\n 50: optional i64 (js.type = \"Long\") initiatedEventId\n 60: optional binary control\n}\n\nstruct ExternalWorkflowExecutionSignaledEventAttributes {\n 10: optional i64 (js.type = \"Long\") initiatedEventId\n 20: optional string domain\n 30: optional WorkflowExecution workflowExecution\n 40: optional binary control\n}\n\nstruct StartChildWorkflowExecutionInitiatedEventAttributes {\n 10: optional string domain\n 20: optional string workflowId\n 30: optional WorkflowType workflowType\n 40: optional TaskList taskList\n 50: optional binary input\n 60: optional i32 executionStartToCloseTimeoutSeconds\n 70: optional i32 taskStartToCloseTimeoutSeconds\n 80: optional ChildPolicy childPolicy\n 90: optional binary control\n 100: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n 110: optional WorkflowIdReusePolicy workflowIdReusePolicy\n}\n\nstruct StartChildWorkflowExecutionFailedEventAttributes {\n 10: optional string domain\n 20: optional string workflowId\n 30: optional WorkflowType workflowType\n 40: optional ChildWorkflowExecutionFailedCause cause\n 50: optional binary control\n 60: optional i64 (js.type = \"Long\") initiatedEventId\n 70: optional i64 (js.type = \"Long\") decisionTaskCompletedEventId\n}\n\nstruct ChildWorkflowExecutionStartedEventAttributes {\n 10: optional string domain\n 20: optional i64 (js.type = \"Long\") initiatedEventId\n 30: optional WorkflowExecution workflowExecution\n 40: optional WorkflowType workflowType\n}\n\nstruct ChildWorkflowExecutionCompletedEventAttributes {\n 10: optional binary result\n 20: optional string domain\n 30: optional WorkflowExecution workflowExecution\n 40: optional WorkflowType workflowType\n 50: optional i64 (js.type = \"Long\") initiatedEventId\n 60: optional i64 (js.type = \"Long\") startedEventId\n}\n\nstruct ChildWorkflowExecutionFailedEventAttributes {\n 10: optional string reason\n 20: optional binary details\n 30: optional string domain\n 40: optional WorkflowExecution workflowExecution\n 50: optional WorkflowType workflowType\n 60: optional i64 (js.type = \"Long\") initiatedEventId\n 70: optional i64 (js.type = \"Long\") startedEventId\n}\n\nstruct ChildWorkflowExecutionCanceledEventAttributes {\n 10: optional binary details\n 20: optional string domain\n 30: optional WorkflowExecution workflowExecution\n 40: optional WorkflowType workflowType\n 50: optional i64 (js.type = \"Long\") initiatedEventId\n 60: optional i64 (js.type = \"Long\") startedEventId\n}\n\nstruct ChildWorkflowExecutionTimedOutEventAttributes {\n 10: optional TimeoutType timeoutType\n 20: optional string domain\n 30: optional WorkflowExecution workflowExecution\n 40: optional WorkflowType workflowType\n 50: optional i64 (js.type = \"Long\") initiatedEventId\n 60: optional i64 (js.type = \"Long\") startedEventId\n}\n\nstruct ChildWorkflowExecutionTerminatedEventAttributes {\n 10: optional string domain\n 20: optional WorkflowExecution workflowExecution\n 30: optional WorkflowType workflowType\n 40: optional i64 (js.type = \"Long\") initiatedEventId\n 50: optional i64 (js.type = \"Long\") startedEventId\n}\n\nstruct HistoryEvent {\n 10: optional i64 (js.type = \"Long\") eventId\n 20: optional i64 (js.type = \"Long\") timestamp\n 30: optional EventType eventType\n 40: optional WorkflowExecutionStartedEventAttributes workflowExecutionStartedEventAttributes\n 50: optional WorkflowExecutionCompletedEventAttributes workflowExecutionCompletedEventAttributes\n 60: optional WorkflowExecutionFailedEventAttributes workflowExecutionFailedEventAttributes\n 70: optional WorkflowExecutionTimedOutEventAttributes workflowExecutionTimedOutEventAttributes\n 80: optional DecisionTaskScheduledEventAttributes decisionTaskScheduledEventAttributes\n 90: optional DecisionTaskStartedEventAttributes decisionTaskStartedEventAttributes\n 100: optional DecisionTaskCompletedEventAttributes decisionTaskCompletedEventAttributes\n 110: optional DecisionTaskTimedOutEventAttributes decisionTaskTimedOutEventAttributes\n 120: optional DecisionTaskFailedEventAttributes decisionTaskFailedEventAttributes\n 130: optional ActivityTaskScheduledEventAttributes activityTaskScheduledEventAttributes\n 140: optional ActivityTaskStartedEventAttributes activityTaskStartedEventAttributes\n 150: optional ActivityTaskCompletedEventAttributes activityTaskCompletedEventAttributes\n 160: optional ActivityTaskFailedEventAttributes activityTaskFailedEventAttributes\n 170: optional ActivityTaskTimedOutEventAttributes activityTaskTimedOutEventAttributes\n 180: optional TimerStartedEventAttributes timerStartedEventAttributes\n 190: optional TimerFiredEventAttributes timerFiredEventAttributes\n 200: optional ActivityTaskCancelRequestedEventAttributes activityTaskCancelRequestedEventAttributes\n 210: optional RequestCancelActivityTaskFailedEventAttributes requestCancelActivityTaskFailedEventAttributes\n 220: optional ActivityTaskCanceledEventAttributes activityTaskCanceledEventAttributes\n 230: optional TimerCanceledEventAttributes timerCanceledEventAttributes\n 240: optional CancelTimerFailedEventAttributes cancelTimerFailedEventAttributes\n 250: optional MarkerRecordedEventAttributes markerRecordedEventAttributes\n 260: optional WorkflowExecutionSignaledEventAttributes workflowExecutionSignaledEventAttributes\n 270: optional WorkflowExecutionTerminatedEventAttributes workflowExecutionTerminatedEventAttributes\n 280: optional WorkflowExecutionCancelRequestedEventAttributes workflowExecutionCancelRequestedEventAttributes\n 290: optional WorkflowExecutionCanceledEventAttributes workflowExecutionCanceledEventAttributes\n 300: optional RequestCancelExternalWorkflowExecutionInitiatedEventAttributes requestCancelExternalWorkflowExecutionInitiatedEventAttributes\n 310: optional RequestCancelExternalWorkflowExecutionFailedEventAttributes requestCancelExternalWorkflowExecutionFailedEventAttributes\n 320: optional ExternalWorkflowExecutionCancelRequestedEventAttributes externalWorkflowExecutionCancelRequestedEventAttributes\n 330: optional WorkflowExecutionContinuedAsNewEventAttributes workflowExecutionContinuedAsNewEventAttributes\n 340: optional StartChildWorkflowExecutionInitiatedEventAttributes startChildWorkflowExecutionInitiatedEventAttributes\n 350: optional StartChildWorkflowExecutionFailedEventAttributes startChildWorkflowExecutionFailedEventAttributes\n 360: optional ChildWorkflowExecutionStartedEventAttributes childWorkflowExecutionStartedEventAttributes\n 370: optional ChildWorkflowExecutionCompletedEventAttributes childWorkflowExecutionCompletedEventAttributes\n 380: optional ChildWorkflowExecutionFailedEventAttributes childWorkflowExecutionFailedEventAttributes\n 390: optional ChildWorkflowExecutionCanceledEventAttributes childWorkflowExecutionCanceledEventAttributes\n 400: optional ChildWorkflowExecutionTimedOutEventAttributes childWorkflowExecutionTimedOutEventAttributes\n 410: optional ChildWorkflowExecutionTerminatedEventAttributes childWorkflowExecutionTerminatedEventAttributes\n 420: optional SignalExternalWorkflowExecutionInitiatedEventAttributes signalExternalWorkflowExecutionInitiatedEventAttributes\n 430: optional SignalExternalWorkflowExecutionFailedEventAttributes signalExternalWorkflowExecutionFailedEventAttributes\n 440: optional ExternalWorkflowExecutionSignaledEventAttributes externalWorkflowExecutionSignaledEventAttributes\n}\n\nstruct History {\n 10: optional list events\n}\n\nstruct WorkflowExecutionFilter {\n 10: optional string workflowId\n}\n\nstruct WorkflowTypeFilter {\n 10: optional string name\n}\n\nstruct StartTimeFilter {\n 10: optional i64 (js.type = \"Long\") earliestTime\n 20: optional i64 (js.type = \"Long\") latestTime\n}\n\nstruct DomainInfo {\n 10: optional string name\n 20: optional DomainStatus status\n 30: optional string description\n 40: optional string ownerEmail\n}\n\nstruct DomainConfiguration {\n 10: optional i32 workflowExecutionRetentionPeriodInDays\n 20: optional bool emitMetric\n}\n\nstruct UpdateDomainInfo {\n 10: optional string description\n 20: optional string ownerEmail\n}\n\nstruct ClusterReplicationConfiguration {\n 10: optional string clusterName\n}\n\nstruct DomainReplicationConfiguration {\n 10: optional string activeClusterName\n 20: optional list clusters\n}\n\nstruct RegisterDomainRequest {\n 10: optional string name\n 20: optional string description\n 30: optional string ownerEmail\n 40: optional i32 workflowExecutionRetentionPeriodInDays\n 50: optional bool emitMetric\n 60: optional list clusters\n}\n\nstruct DescribeDomainRequest {\n 10: optional string name\n}\n\nstruct DescribeDomainResponse {\n 10: optional DomainInfo domainInfo\n 20: optional DomainConfiguration configuration\n 30: optional DomainReplicationConfiguration replicationConfiguration\n 40: optional i64 (js.type = \"Long\") failoverVersion\n}\n\nstruct UpdateDomainRequest {\n 10: optional string name\n 20: optional UpdateDomainInfo updatedInfo\n 30: optional DomainConfiguration configuration\n 40: optional DomainReplicationConfiguration replicationConfiguration\n}\n\nstruct UpdateDomainResponse {\n 10: optional DomainInfo domainInfo\n 20: optional DomainConfiguration configuration\n 30: optional DomainReplicationConfiguration replicationConfiguration\n 40: optional i64 (js.type = \"Long\") failoverVersion\n}\n\nstruct DeprecateDomainRequest {\n 10: optional string name\n}\n\nstruct StartWorkflowExecutionRequest {\n 10: optional string domain\n 20: optional string workflowId\n 30: optional WorkflowType workflowType\n 40: optional TaskList taskList\n 50: optional binary input\n 60: optional i32 executionStartToCloseTimeoutSeconds\n 70: optional i32 taskStartToCloseTimeoutSeconds\n 80: optional string identity\n 90: optional string requestId\n 100: optional WorkflowIdReusePolicy workflowIdReusePolicy\n}\n\nstruct StartWorkflowExecutionResponse {\n 10: optional string runId\n}\n\nstruct PollForDecisionTaskRequest {\n 10: optional string domain\n 20: optional TaskList taskList\n 30: optional string identity\n}\n\nstruct PollForDecisionTaskResponse {\n 10: optional binary taskToken\n 20: optional WorkflowExecution workflowExecution\n 30: optional WorkflowType workflowType\n 40: optional i64 (js.type = \"Long\") previousStartedEventId\n 50: optional i64 (js.type = \"Long\") startedEventId\n 51: optional i64 (js.type = 'Long') attempt\n 54: optional i64 (js.type = \"Long\") backlogCountHint\n 60: optional History history\n 70: optional binary nextPageToken\n 80: optional WorkflowQuery query\n}\n\nstruct StickyExecutionAttributes {\n 10: optional TaskList workerTaskList\n 20: optional i32 scheduleToStartTimeoutSeconds\n}\n\nstruct RespondDecisionTaskCompletedRequest {\n 10: optional binary taskToken\n 20: optional list decisions\n 30: optional binary executionContext\n 40: optional string identity\n 50: optional StickyExecutionAttributes stickyAttributes\n}\n\nstruct RespondDecisionTaskFailedRequest {\n 10: optional binary taskToken\n 20: optional DecisionTaskFailedCause cause\n 30: optional binary details\n 40: optional string identity\n}\n\nstruct PollForActivityTaskRequest {\n 10: optional string domain\n 20: optional TaskList taskList\n 30: optional string identity\n 40: optional TaskListMetadata taskListMetadata\n}\n\nstruct PollForActivityTaskResponse {\n 10: optional binary taskToken\n 20: optional WorkflowExecution workflowExecution\n 30: optional string activityId\n 40: optional ActivityType activityType\n 50: optional binary input\n 70: optional i64 (js.type = \"Long\") scheduledTimestamp\n 80: optional i32 scheduleToCloseTimeoutSeconds\n 90: optional i64 (js.type = \"Long\") startedTimestamp\n 100: optional i32 startToCloseTimeoutSeconds\n 110: optional i32 heartbeatTimeoutSeconds\n}\n\nstruct RecordActivityTaskHeartbeatRequest {\n 10: optional binary taskToken\n 20: optional binary details\n 30: optional string identity\n}\n\nstruct RecordActivityTaskHeartbeatResponse {\n 10: optional bool cancelRequested\n}\n\nstruct RespondActivityTaskCompletedRequest {\n 10: optional binary taskToken\n 20: optional binary result\n 30: optional string identity\n}\n\nstruct RespondActivityTaskFailedRequest {\n 10: optional binary taskToken\n 20: optional string reason\n 30: optional binary details\n 40: optional string identity\n}\n\nstruct RespondActivityTaskCanceledRequest {\n 10: optional binary taskToken\n 20: optional binary details\n 30: optional string identity\n}\n\nstruct RespondActivityTaskCompletedByIDRequest {\n 10: optional string domain\n 20: optional string workflowID\n 30: optional string runID\n 40: optional string activityID\n 50: optional binary result\n 60: optional string identity\n}\n\nstruct RespondActivityTaskFailedByIDRequest {\n 10: optional string domain\n 20: optional string workflowID\n 30: optional string runID\n 40: optional string activityID\n 50: optional string reason\n 60: optional binary details\n 70: optional string identity\n}\n\nstruct RespondActivityTaskCanceledByIDRequest {\n 10: optional string domain\n 20: optional string workflowID\n 30: optional string runID\n 40: optional string activityID\n 50: optional binary details\n 60: optional string identity\n}\n\nstruct RequestCancelWorkflowExecutionRequest {\n 10: optional string domain\n 20: optional WorkflowExecution workflowExecution\n 30: optional string identity\n 40: optional string requestId\n}\n\nstruct GetWorkflowExecutionHistoryRequest {\n 10: optional string domain\n 20: optional WorkflowExecution execution\n 30: optional i32 maximumPageSize\n 40: optional binary nextPageToken\n 50: optional bool waitForNewEvent\n 60: optional HistoryEventFilterType HistoryEventFilterType\n}\n\nstruct GetWorkflowExecutionHistoryResponse {\n 10: optional History history\n 20: optional binary nextPageToken\n}\n\nstruct SignalWorkflowExecutionRequest {\n 10: optional string domain\n 20: optional WorkflowExecution workflowExecution\n 30: optional string signalName\n 40: optional binary input\n 50: optional string identity\n 60: optional string requestId\n 70: optional binary control\n}\n\nstruct TerminateWorkflowExecutionRequest {\n 10: optional string domain\n 20: optional WorkflowExecution workflowExecution\n 30: optional string reason\n 40: optional binary details\n 50: optional string identity\n}\n\nstruct ListOpenWorkflowExecutionsRequest {\n 10: optional string domain\n 20: optional i32 maximumPageSize\n 30: optional binary nextPageToken\n 40: optional StartTimeFilter StartTimeFilter\n 50: optional WorkflowExecutionFilter executionFilter\n 60: optional WorkflowTypeFilter typeFilter\n}\n\nstruct ListOpenWorkflowExecutionsResponse {\n 10: optional list executions\n 20: optional binary nextPageToken\n}\n\nstruct ListClosedWorkflowExecutionsRequest {\n 10: optional string domain\n 20: optional i32 maximumPageSize\n 30: optional binary nextPageToken\n 40: optional StartTimeFilter StartTimeFilter\n 50: optional WorkflowExecutionFilter executionFilter\n 60: optional WorkflowTypeFilter typeFilter\n 70: optional WorkflowExecutionCloseStatus statusFilter\n}\n\nstruct ListClosedWorkflowExecutionsResponse {\n 10: optional list executions\n 20: optional binary nextPageToken\n}\n\nstruct QueryWorkflowRequest {\n 10: optional string domain\n 20: optional WorkflowExecution execution\n 30: optional WorkflowQuery query\n}\n\nstruct QueryWorkflowResponse {\n 10: optional binary queryResult\n}\n\nstruct WorkflowQuery {\n 10: optional string queryType\n 20: optional binary queryArgs\n}\n\nstruct RespondQueryTaskCompletedRequest {\n 10: optional binary taskToken\n 20: optional QueryTaskCompletedType completedType\n 30: optional binary queryResult\n 40: optional string errorMessage\n}\n\nstruct DescribeWorkflowExecutionRequest {\n 10: optional string domain\n 20: optional WorkflowExecution execution\n}\n\nstruct PendingActivityInfo {\n 10: optional string activityID\n 20: optional ActivityType activityType\n 30: optional PendingActivityState state\n 40: optional binary heartbeatDetails\n 50: optional i64 (js.type = \"Long\") lastHeartbeatTimestamp\n}\n\nstruct DescribeWorkflowExecutionResponse {\n 10: optional WorkflowExecutionConfiguration executionConfiguration\n 20: optional WorkflowExecutionInfo workflowExecutionInfo\n 30: optional list pendingActivities\n}\n\nstruct DescribeTaskListRequest {\n 10: optional string domain\n 20: optional TaskList taskList\n 30: optional TaskListType taskListType\n}\n\nstruct DescribeTaskListResponse {\n 10: optional list pollers\n}\n\nenum TaskListType {\n /*\n * Decision type of tasklist\n */\n Decision,\n /*\n * Activity type of tasklist\n */\n Activity,\n}\n\nstruct PollerInfo {\n // Unix Nano\n 10: optional i64 (js.type = \"Long\") lastAccessTime\n 20: optional string identity\n}\n" diff --git a/.gen/go/shared/types.go b/.gen/go/shared/types.go index c605116ae4e..419ec56653e 100644 --- a/.gen/go/shared/types.go +++ b/.gen/go/shared/types.go @@ -4453,6 +4453,122 @@ func (v *ChildWorkflowExecutionTimedOutEventAttributes) GetStartedEventId() (o i return } +type ClusterReplicationConfiguration struct { + ClusterName *string `json:"clusterName,omitempty"` +} + +// ToWire translates a ClusterReplicationConfiguration struct into a Thrift-level intermediate +// representation. This intermediate representation may be serialized +// into bytes using a ThriftRW protocol implementation. +// +// An error is returned if the struct or any of its fields failed to +// validate. +// +// x, err := v.ToWire() +// if err != nil { +// return err +// } +// +// if err := binaryProtocol.Encode(x, writer); err != nil { +// return err +// } +func (v *ClusterReplicationConfiguration) ToWire() (wire.Value, error) { + var ( + fields [1]wire.Field + i int = 0 + w wire.Value + err error + ) + + if v.ClusterName != nil { + w, err = wire.NewValueString(*(v.ClusterName)), error(nil) + if err != nil { + return w, err + } + fields[i] = wire.Field{ID: 10, Value: w} + i++ + } + + return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil +} + +// FromWire deserializes a ClusterReplicationConfiguration struct from its Thrift-level +// representation. The Thrift-level representation may be obtained +// from a ThriftRW protocol implementation. +// +// An error is returned if we were unable to build a ClusterReplicationConfiguration struct +// from the provided intermediate representation. +// +// x, err := binaryProtocol.Decode(reader, wire.TStruct) +// if err != nil { +// return nil, err +// } +// +// var v ClusterReplicationConfiguration +// if err := v.FromWire(x); err != nil { +// return nil, err +// } +// return &v, nil +func (v *ClusterReplicationConfiguration) FromWire(w wire.Value) error { + var err error + + for _, field := range w.GetStruct().Fields { + switch field.ID { + case 10: + if field.Value.Type() == wire.TBinary { + var x string + x, err = field.Value.GetString(), error(nil) + v.ClusterName = &x + if err != nil { + return err + } + + } + } + } + + return nil +} + +// String returns a readable string representation of a ClusterReplicationConfiguration +// struct. +func (v *ClusterReplicationConfiguration) String() string { + if v == nil { + return "" + } + + var fields [1]string + i := 0 + if v.ClusterName != nil { + fields[i] = fmt.Sprintf("ClusterName: %v", *(v.ClusterName)) + i++ + } + + return fmt.Sprintf("ClusterReplicationConfiguration{%v}", strings.Join(fields[:i], ", ")) +} + +// Equals returns true if all the fields of this ClusterReplicationConfiguration match the +// provided ClusterReplicationConfiguration. +// +// This function performs a deep comparison. +func (v *ClusterReplicationConfiguration) Equals(rhs *ClusterReplicationConfiguration) bool { + if !_String_EqualsPtr(v.ClusterName, rhs.ClusterName) { + return false + } + + return true +} + +// GetClusterName returns the value of ClusterName if it is set or its +// zero value if it is unset. +func (v *ClusterReplicationConfiguration) GetClusterName() (o string) { + if v.ClusterName != nil { + return *v.ClusterName + } + + return +} + type CompleteWorkflowExecutionDecisionAttributes struct { Result []byte `json:"result,omitempty"` } @@ -7001,8 +7117,10 @@ func (v *DescribeDomainRequest) GetName() (o string) { } type DescribeDomainResponse struct { - DomainInfo *DomainInfo `json:"domainInfo,omitempty"` - Configuration *DomainConfiguration `json:"configuration,omitempty"` + DomainInfo *DomainInfo `json:"domainInfo,omitempty"` + Configuration *DomainConfiguration `json:"configuration,omitempty"` + ReplicationConfiguration *DomainReplicationConfiguration `json:"replicationConfiguration,omitempty"` + FailoverVersion *int64 `json:"failoverVersion,omitempty"` } // ToWire translates a DescribeDomainResponse struct into a Thrift-level intermediate @@ -7022,7 +7140,7 @@ type DescribeDomainResponse struct { // } func (v *DescribeDomainResponse) ToWire() (wire.Value, error) { var ( - fields [2]wire.Field + fields [4]wire.Field i int = 0 w wire.Value err error @@ -7044,6 +7162,22 @@ func (v *DescribeDomainResponse) ToWire() (wire.Value, error) { fields[i] = wire.Field{ID: 20, Value: w} i++ } + if v.ReplicationConfiguration != nil { + w, err = v.ReplicationConfiguration.ToWire() + if err != nil { + return w, err + } + fields[i] = wire.Field{ID: 30, Value: w} + i++ + } + if v.FailoverVersion != nil { + w, err = wire.NewValueI64(*(v.FailoverVersion)), error(nil) + if err != nil { + return w, err + } + fields[i] = wire.Field{ID: 40, Value: w} + i++ + } return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil } @@ -7060,6 +7194,12 @@ func _DomainConfiguration_Read(w wire.Value) (*DomainConfiguration, error) { return &v, err } +func _DomainReplicationConfiguration_Read(w wire.Value) (*DomainReplicationConfiguration, error) { + var v DomainReplicationConfiguration + err := v.FromWire(w) + return &v, err +} + // FromWire deserializes a DescribeDomainResponse struct from its Thrift-level // representation. The Thrift-level representation may be obtained // from a ThriftRW protocol implementation. @@ -7097,6 +7237,24 @@ func (v *DescribeDomainResponse) FromWire(w wire.Value) error { return err } + } + case 30: + if field.Value.Type() == wire.TStruct { + v.ReplicationConfiguration, err = _DomainReplicationConfiguration_Read(field.Value) + if err != nil { + return err + } + + } + case 40: + if field.Value.Type() == wire.TI64 { + var x int64 + x, err = field.Value.GetI64(), error(nil) + v.FailoverVersion = &x + if err != nil { + return err + } + } } } @@ -7111,7 +7269,7 @@ func (v *DescribeDomainResponse) String() string { return "" } - var fields [2]string + var fields [4]string i := 0 if v.DomainInfo != nil { fields[i] = fmt.Sprintf("DomainInfo: %v", v.DomainInfo) @@ -7121,6 +7279,14 @@ func (v *DescribeDomainResponse) String() string { fields[i] = fmt.Sprintf("Configuration: %v", v.Configuration) i++ } + if v.ReplicationConfiguration != nil { + fields[i] = fmt.Sprintf("ReplicationConfiguration: %v", v.ReplicationConfiguration) + i++ + } + if v.FailoverVersion != nil { + fields[i] = fmt.Sprintf("FailoverVersion: %v", *(v.FailoverVersion)) + i++ + } return fmt.Sprintf("DescribeDomainResponse{%v}", strings.Join(fields[:i], ", ")) } @@ -7136,10 +7302,26 @@ func (v *DescribeDomainResponse) Equals(rhs *DescribeDomainResponse) bool { if !((v.Configuration == nil && rhs.Configuration == nil) || (v.Configuration != nil && rhs.Configuration != nil && v.Configuration.Equals(rhs.Configuration))) { return false } + if !((v.ReplicationConfiguration == nil && rhs.ReplicationConfiguration == nil) || (v.ReplicationConfiguration != nil && rhs.ReplicationConfiguration != nil && v.ReplicationConfiguration.Equals(rhs.ReplicationConfiguration))) { + return false + } + if !_I64_EqualsPtr(v.FailoverVersion, rhs.FailoverVersion) { + return false + } return true } +// GetFailoverVersion returns the value of FailoverVersion if it is set or its +// zero value if it is unset. +func (v *DescribeDomainResponse) GetFailoverVersion() (o int64) { + if v.FailoverVersion != nil { + return *v.FailoverVersion + } + + return +} + type DescribeTaskListRequest struct { Domain *string `json:"domain,omitempty"` TaskList *TaskList `json:"taskList,omitempty"` @@ -8388,6 +8570,214 @@ func (v *DomainInfo) GetOwnerEmail() (o string) { return } +type DomainReplicationConfiguration struct { + ActiveClusterName *string `json:"activeClusterName,omitempty"` + Clusters []*ClusterReplicationConfiguration `json:"clusters,omitempty"` +} + +type _List_ClusterReplicationConfiguration_ValueList []*ClusterReplicationConfiguration + +func (v _List_ClusterReplicationConfiguration_ValueList) ForEach(f func(wire.Value) error) error { + for i, x := range v { + if x == nil { + return fmt.Errorf("invalid [%v]: value is nil", i) + } + w, err := x.ToWire() + if err != nil { + return err + } + err = f(w) + if err != nil { + return err + } + } + return nil +} + +func (v _List_ClusterReplicationConfiguration_ValueList) Size() int { + return len(v) +} + +func (_List_ClusterReplicationConfiguration_ValueList) ValueType() wire.Type { + return wire.TStruct +} + +func (_List_ClusterReplicationConfiguration_ValueList) Close() {} + +// ToWire translates a DomainReplicationConfiguration struct into a Thrift-level intermediate +// representation. This intermediate representation may be serialized +// into bytes using a ThriftRW protocol implementation. +// +// An error is returned if the struct or any of its fields failed to +// validate. +// +// x, err := v.ToWire() +// if err != nil { +// return err +// } +// +// if err := binaryProtocol.Encode(x, writer); err != nil { +// return err +// } +func (v *DomainReplicationConfiguration) ToWire() (wire.Value, error) { + var ( + fields [2]wire.Field + i int = 0 + w wire.Value + err error + ) + + if v.ActiveClusterName != nil { + w, err = wire.NewValueString(*(v.ActiveClusterName)), error(nil) + if err != nil { + return w, err + } + fields[i] = wire.Field{ID: 10, Value: w} + i++ + } + if v.Clusters != nil { + w, err = wire.NewValueList(_List_ClusterReplicationConfiguration_ValueList(v.Clusters)), error(nil) + if err != nil { + return w, err + } + fields[i] = wire.Field{ID: 20, Value: w} + i++ + } + + return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil +} + +func _ClusterReplicationConfiguration_Read(w wire.Value) (*ClusterReplicationConfiguration, error) { + var v ClusterReplicationConfiguration + err := v.FromWire(w) + return &v, err +} + +func _List_ClusterReplicationConfiguration_Read(l wire.ValueList) ([]*ClusterReplicationConfiguration, error) { + if l.ValueType() != wire.TStruct { + return nil, nil + } + + o := make([]*ClusterReplicationConfiguration, 0, l.Size()) + err := l.ForEach(func(x wire.Value) error { + i, err := _ClusterReplicationConfiguration_Read(x) + if err != nil { + return err + } + o = append(o, i) + return nil + }) + l.Close() + return o, err +} + +// FromWire deserializes a DomainReplicationConfiguration struct from its Thrift-level +// representation. The Thrift-level representation may be obtained +// from a ThriftRW protocol implementation. +// +// An error is returned if we were unable to build a DomainReplicationConfiguration struct +// from the provided intermediate representation. +// +// x, err := binaryProtocol.Decode(reader, wire.TStruct) +// if err != nil { +// return nil, err +// } +// +// var v DomainReplicationConfiguration +// if err := v.FromWire(x); err != nil { +// return nil, err +// } +// return &v, nil +func (v *DomainReplicationConfiguration) FromWire(w wire.Value) error { + var err error + + for _, field := range w.GetStruct().Fields { + switch field.ID { + case 10: + if field.Value.Type() == wire.TBinary { + var x string + x, err = field.Value.GetString(), error(nil) + v.ActiveClusterName = &x + if err != nil { + return err + } + + } + case 20: + if field.Value.Type() == wire.TList { + v.Clusters, err = _List_ClusterReplicationConfiguration_Read(field.Value.GetList()) + if err != nil { + return err + } + + } + } + } + + return nil +} + +// String returns a readable string representation of a DomainReplicationConfiguration +// struct. +func (v *DomainReplicationConfiguration) String() string { + if v == nil { + return "" + } + + var fields [2]string + i := 0 + if v.ActiveClusterName != nil { + fields[i] = fmt.Sprintf("ActiveClusterName: %v", *(v.ActiveClusterName)) + i++ + } + if v.Clusters != nil { + fields[i] = fmt.Sprintf("Clusters: %v", v.Clusters) + i++ + } + + return fmt.Sprintf("DomainReplicationConfiguration{%v}", strings.Join(fields[:i], ", ")) +} + +func _List_ClusterReplicationConfiguration_Equals(lhs, rhs []*ClusterReplicationConfiguration) bool { + if len(lhs) != len(rhs) { + return false + } + + for i, lv := range lhs { + rv := rhs[i] + if !lv.Equals(rv) { + return false + } + } + + return true +} + +// Equals returns true if all the fields of this DomainReplicationConfiguration match the +// provided DomainReplicationConfiguration. +// +// This function performs a deep comparison. +func (v *DomainReplicationConfiguration) Equals(rhs *DomainReplicationConfiguration) bool { + if !_String_EqualsPtr(v.ActiveClusterName, rhs.ActiveClusterName) { + return false + } + if !((v.Clusters == nil && rhs.Clusters == nil) || (v.Clusters != nil && rhs.Clusters != nil && _List_ClusterReplicationConfiguration_Equals(v.Clusters, rhs.Clusters))) { + return false + } + + return true +} + +// GetActiveClusterName returns the value of ActiveClusterName if it is set or its +// zero value if it is unset. +func (v *DomainReplicationConfiguration) GetActiveClusterName() (o string) { + if v.ActiveClusterName != nil { + return *v.ActiveClusterName + } + + return +} + type DomainStatus int32 const ( @@ -15582,11 +15972,12 @@ func (v *RecordMarkerDecisionAttributes) GetMarkerName() (o string) { } type RegisterDomainRequest struct { - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - OwnerEmail *string `json:"ownerEmail,omitempty"` - WorkflowExecutionRetentionPeriodInDays *int32 `json:"workflowExecutionRetentionPeriodInDays,omitempty"` - EmitMetric *bool `json:"emitMetric,omitempty"` + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + OwnerEmail *string `json:"ownerEmail,omitempty"` + WorkflowExecutionRetentionPeriodInDays *int32 `json:"workflowExecutionRetentionPeriodInDays,omitempty"` + EmitMetric *bool `json:"emitMetric,omitempty"` + Clusters []*ClusterReplicationConfiguration `json:"clusters,omitempty"` } // ToWire translates a RegisterDomainRequest struct into a Thrift-level intermediate @@ -15606,7 +15997,7 @@ type RegisterDomainRequest struct { // } func (v *RegisterDomainRequest) ToWire() (wire.Value, error) { var ( - fields [5]wire.Field + fields [6]wire.Field i int = 0 w wire.Value err error @@ -15652,6 +16043,14 @@ func (v *RegisterDomainRequest) ToWire() (wire.Value, error) { fields[i] = wire.Field{ID: 50, Value: w} i++ } + if v.Clusters != nil { + w, err = wire.NewValueList(_List_ClusterReplicationConfiguration_ValueList(v.Clusters)), error(nil) + if err != nil { + return w, err + } + fields[i] = wire.Field{ID: 60, Value: w} + i++ + } return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil } @@ -15727,6 +16126,14 @@ func (v *RegisterDomainRequest) FromWire(w wire.Value) error { return err } + } + case 60: + if field.Value.Type() == wire.TList { + v.Clusters, err = _List_ClusterReplicationConfiguration_Read(field.Value.GetList()) + if err != nil { + return err + } + } } } @@ -15741,7 +16148,7 @@ func (v *RegisterDomainRequest) String() string { return "" } - var fields [5]string + var fields [6]string i := 0 if v.Name != nil { fields[i] = fmt.Sprintf("Name: %v", *(v.Name)) @@ -15763,6 +16170,10 @@ func (v *RegisterDomainRequest) String() string { fields[i] = fmt.Sprintf("EmitMetric: %v", *(v.EmitMetric)) i++ } + if v.Clusters != nil { + fields[i] = fmt.Sprintf("Clusters: %v", v.Clusters) + i++ + } return fmt.Sprintf("RegisterDomainRequest{%v}", strings.Join(fields[:i], ", ")) } @@ -15787,6 +16198,9 @@ func (v *RegisterDomainRequest) Equals(rhs *RegisterDomainRequest) bool { if !_Bool_EqualsPtr(v.EmitMetric, rhs.EmitMetric) { return false } + if !((v.Clusters == nil && rhs.Clusters == nil) || (v.Clusters != nil && rhs.Clusters != nil && _List_ClusterReplicationConfiguration_Equals(v.Clusters, rhs.Clusters))) { + return false + } return true } @@ -24765,9 +25179,10 @@ func (v *UpdateDomainInfo) GetOwnerEmail() (o string) { } type UpdateDomainRequest struct { - Name *string `json:"name,omitempty"` - UpdatedInfo *UpdateDomainInfo `json:"updatedInfo,omitempty"` - Configuration *DomainConfiguration `json:"configuration,omitempty"` + Name *string `json:"name,omitempty"` + UpdatedInfo *UpdateDomainInfo `json:"updatedInfo,omitempty"` + Configuration *DomainConfiguration `json:"configuration,omitempty"` + ReplicationConfiguration *DomainReplicationConfiguration `json:"replicationConfiguration,omitempty"` } // ToWire translates a UpdateDomainRequest struct into a Thrift-level intermediate @@ -24787,7 +25202,7 @@ type UpdateDomainRequest struct { // } func (v *UpdateDomainRequest) ToWire() (wire.Value, error) { var ( - fields [3]wire.Field + fields [4]wire.Field i int = 0 w wire.Value err error @@ -24817,6 +25232,14 @@ func (v *UpdateDomainRequest) ToWire() (wire.Value, error) { fields[i] = wire.Field{ID: 30, Value: w} i++ } + if v.ReplicationConfiguration != nil { + w, err = v.ReplicationConfiguration.ToWire() + if err != nil { + return w, err + } + fields[i] = wire.Field{ID: 40, Value: w} + i++ + } return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil } @@ -24874,6 +25297,14 @@ func (v *UpdateDomainRequest) FromWire(w wire.Value) error { return err } + } + case 40: + if field.Value.Type() == wire.TStruct { + v.ReplicationConfiguration, err = _DomainReplicationConfiguration_Read(field.Value) + if err != nil { + return err + } + } } } @@ -24888,7 +25319,7 @@ func (v *UpdateDomainRequest) String() string { return "" } - var fields [3]string + var fields [4]string i := 0 if v.Name != nil { fields[i] = fmt.Sprintf("Name: %v", *(v.Name)) @@ -24902,6 +25333,10 @@ func (v *UpdateDomainRequest) String() string { fields[i] = fmt.Sprintf("Configuration: %v", v.Configuration) i++ } + if v.ReplicationConfiguration != nil { + fields[i] = fmt.Sprintf("ReplicationConfiguration: %v", v.ReplicationConfiguration) + i++ + } return fmt.Sprintf("UpdateDomainRequest{%v}", strings.Join(fields[:i], ", ")) } @@ -24920,6 +25355,9 @@ func (v *UpdateDomainRequest) Equals(rhs *UpdateDomainRequest) bool { if !((v.Configuration == nil && rhs.Configuration == nil) || (v.Configuration != nil && rhs.Configuration != nil && v.Configuration.Equals(rhs.Configuration))) { return false } + if !((v.ReplicationConfiguration == nil && rhs.ReplicationConfiguration == nil) || (v.ReplicationConfiguration != nil && rhs.ReplicationConfiguration != nil && v.ReplicationConfiguration.Equals(rhs.ReplicationConfiguration))) { + return false + } return true } @@ -24935,8 +25373,10 @@ func (v *UpdateDomainRequest) GetName() (o string) { } type UpdateDomainResponse struct { - DomainInfo *DomainInfo `json:"domainInfo,omitempty"` - Configuration *DomainConfiguration `json:"configuration,omitempty"` + DomainInfo *DomainInfo `json:"domainInfo,omitempty"` + Configuration *DomainConfiguration `json:"configuration,omitempty"` + ReplicationConfiguration *DomainReplicationConfiguration `json:"replicationConfiguration,omitempty"` + FailoverVersion *int64 `json:"failoverVersion,omitempty"` } // ToWire translates a UpdateDomainResponse struct into a Thrift-level intermediate @@ -24956,7 +25396,7 @@ type UpdateDomainResponse struct { // } func (v *UpdateDomainResponse) ToWire() (wire.Value, error) { var ( - fields [2]wire.Field + fields [4]wire.Field i int = 0 w wire.Value err error @@ -24978,6 +25418,22 @@ func (v *UpdateDomainResponse) ToWire() (wire.Value, error) { fields[i] = wire.Field{ID: 20, Value: w} i++ } + if v.ReplicationConfiguration != nil { + w, err = v.ReplicationConfiguration.ToWire() + if err != nil { + return w, err + } + fields[i] = wire.Field{ID: 30, Value: w} + i++ + } + if v.FailoverVersion != nil { + w, err = wire.NewValueI64(*(v.FailoverVersion)), error(nil) + if err != nil { + return w, err + } + fields[i] = wire.Field{ID: 40, Value: w} + i++ + } return wire.NewValueStruct(wire.Struct{Fields: fields[:i]}), nil } @@ -25019,6 +25475,24 @@ func (v *UpdateDomainResponse) FromWire(w wire.Value) error { return err } + } + case 30: + if field.Value.Type() == wire.TStruct { + v.ReplicationConfiguration, err = _DomainReplicationConfiguration_Read(field.Value) + if err != nil { + return err + } + + } + case 40: + if field.Value.Type() == wire.TI64 { + var x int64 + x, err = field.Value.GetI64(), error(nil) + v.FailoverVersion = &x + if err != nil { + return err + } + } } } @@ -25033,7 +25507,7 @@ func (v *UpdateDomainResponse) String() string { return "" } - var fields [2]string + var fields [4]string i := 0 if v.DomainInfo != nil { fields[i] = fmt.Sprintf("DomainInfo: %v", v.DomainInfo) @@ -25043,6 +25517,14 @@ func (v *UpdateDomainResponse) String() string { fields[i] = fmt.Sprintf("Configuration: %v", v.Configuration) i++ } + if v.ReplicationConfiguration != nil { + fields[i] = fmt.Sprintf("ReplicationConfiguration: %v", v.ReplicationConfiguration) + i++ + } + if v.FailoverVersion != nil { + fields[i] = fmt.Sprintf("FailoverVersion: %v", *(v.FailoverVersion)) + i++ + } return fmt.Sprintf("UpdateDomainResponse{%v}", strings.Join(fields[:i], ", ")) } @@ -25058,10 +25540,26 @@ func (v *UpdateDomainResponse) Equals(rhs *UpdateDomainResponse) bool { if !((v.Configuration == nil && rhs.Configuration == nil) || (v.Configuration != nil && rhs.Configuration != nil && v.Configuration.Equals(rhs.Configuration))) { return false } + if !((v.ReplicationConfiguration == nil && rhs.ReplicationConfiguration == nil) || (v.ReplicationConfiguration != nil && rhs.ReplicationConfiguration != nil && v.ReplicationConfiguration.Equals(rhs.ReplicationConfiguration))) { + return false + } + if !_I64_EqualsPtr(v.FailoverVersion, rhs.FailoverVersion) { + return false + } return true } +// GetFailoverVersion returns the value of FailoverVersion if it is set or its +// zero value if it is unset. +func (v *UpdateDomainResponse) GetFailoverVersion() (o int64) { + if v.FailoverVersion != nil { + return *v.FailoverVersion + } + + return +} + type WorkflowExecution struct { WorkflowId *string `json:"workflowId,omitempty"` RunId *string `json:"runId,omitempty"` diff --git a/cmd/server/server.go b/cmd/server/server.go index e35ea605626..821a45477cf 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -25,6 +25,7 @@ import ( "time" "github.com/uber/cadence/common" + "github.com/uber/cadence/common/cluster" "github.com/uber/cadence/common/service" "github.com/uber/cadence/common/service/config" "github.com/uber/cadence/service/frontend" @@ -100,10 +101,15 @@ func (s *server) startService() common.Daemon { } svcCfg := s.cfg.Services[s.name] - params.MetricScope = svcCfg.Metrics.NewScope() params.RPCFactory = svcCfg.RPC.NewFactory(params.Name, params.Logger) params.PProfInitializer = svcCfg.PProf.NewInitializer(params.Logger) + params.ClusterMetadata = cluster.NewMetadata( + s.cfg.ClustersInfo.InitialFailoverVersion, + s.cfg.ClustersInfo.FailoverVersionIncrement, + s.cfg.ClustersInfo.CurrentClusterName, + s.cfg.ClustersInfo.ClusterNames, + ) var daemon common.Daemon diff --git a/common/cache/domainCache.go b/common/cache/domainCache.go index 67bfb907a6e..7c2db772c42 100644 --- a/common/cache/domainCache.go +++ b/common/cache/domainCache.go @@ -34,7 +34,7 @@ const ( domainCacheInitialSize = 1024 domainCacheMaxSize = 16 * 1024 domainCacheTTL = time.Hour - domainEntryRefreshInterval = int64(10 * time.Second) + domainEntryRefreshInterval = 10 * time.Second ) type ( @@ -44,8 +44,8 @@ type ( // in updating the domain entry every 10 seconds but in the case of a cassandra failure we can still keep on serving // requests using the stale entry from cache upto an hour DomainCache interface { - GetDomain(name string) (*persistence.DomainInfo, *persistence.DomainConfig, error) - GetDomainByID(id string) (*persistence.DomainInfo, *persistence.DomainConfig, error) + GetDomain(name string) (*domainCacheEntry, error) + GetDomainByID(id string) (*domainCacheEntry, error) GetDomainID(name string) (string, error) } @@ -58,9 +58,10 @@ type ( } domainCacheEntry struct { - info *persistence.DomainInfo - config *persistence.DomainConfig - expiry int64 + Info *persistence.DomainInfo + Config *persistence.DomainConfig + ReplicationConfig *persistence.DomainReplicationConfig + expiry time.Time sync.RWMutex } ) @@ -86,50 +87,44 @@ func newDomainCacheEntry() *domainCacheEntry { // GetDomain retrieves the information from the cache if it exists, otherwise retrieves the information from metadata // store and writes it to the cache with an expiry before returning back -func (c *domainCache) GetDomain(name string) (*persistence.DomainInfo, *persistence.DomainConfig, error) { +func (c *domainCache) GetDomain(name string) (*domainCacheEntry, error) { return c.getDomain(name, "", name, c.cacheByName) } // GetDomainByID retrieves the information from the cache if it exists, otherwise retrieves the information from metadata // store and writes it to the cache with an expiry before returning back -func (c *domainCache) GetDomainByID(id string) (*persistence.DomainInfo, *persistence.DomainConfig, error) { +func (c *domainCache) GetDomainByID(id string) (*domainCacheEntry, error) { return c.getDomain(id, id, "", c.cacheByID) } // GetDomainID retrieves domainID by using GetDomain func (c *domainCache) GetDomainID(name string) (string, error) { - info, _, err := c.GetDomain(name) + entry, err := c.GetDomain(name) if err != nil { return "", err } - return info.ID, nil + return entry.Info.ID, nil } // GetDomain retrieves the information from the cache if it exists, otherwise retrieves the information from metadata // store and writes it to the cache with an expiry before returning back -func (c *domainCache) getDomain(key, id, name string, cache Cache) (*persistence.DomainInfo, *persistence.DomainConfig, error) { - now := c.timeSource.Now().UnixNano() - refreshCache := false - var info *persistence.DomainInfo - var config *persistence.DomainConfig +func (c *domainCache) getDomain(key, id, name string, cache Cache) (*domainCacheEntry, error) { + now := c.timeSource.Now() + var result *domainCacheEntry + entry, cacheHit := cache.Get(key).(*domainCacheEntry) if cacheHit { // Found the information in the cache, lets check if it needs to be refreshed before returning back entry.RLock() - info = entry.info - config = entry.config - - if entry.expiry == 0 || now >= entry.expiry { - refreshCache = true + if !entry.isExpired(now) { + result = entry.duplicate() + entry.RUnlock() + return result, nil } + // cache expired, need to refresh entry.RUnlock() } - // Found a cache entry and no need to refresh. Return immediately - if cacheHit && !refreshCache { - return info, config, nil - } - // Cache entry not found, Let's create an entry and add it to cache if !cacheHit { elem, _ := cache.PutIfNotExist(key, newDomainCacheEntry()) @@ -141,7 +136,7 @@ func (c *domainCache) getDomain(key, id, name string, cache Cache) (*persistence defer entry.Unlock() // Check again under the lock to make sure someone else did not update the entry - if entry.expiry == 0 || now >= entry.expiry { + if entry.isExpired(now) { response, err := c.metadataMgr.GetDomain(&persistence.GetDomainRequest{ Name: name, ID: id, @@ -149,17 +144,30 @@ func (c *domainCache) getDomain(key, id, name string, cache Cache) (*persistence // Failed to get domain. Return stale entry if we have one, otherwise just return error if err != nil { - if entry.expiry > 0 { - return entry.info, entry.config, nil + if !entry.expiry.IsZero() { + return entry, nil } - return nil, nil, err + return nil, err } - entry.info = response.Info - entry.config = response.Config - entry.expiry = now + domainEntryRefreshInterval + entry.Info = response.Info + entry.Config = response.Config + entry.ReplicationConfig = response.ReplicationConfig + entry.expiry = now.Add(domainEntryRefreshInterval) } - return entry.info, entry.config, nil + return entry.duplicate(), nil +} + +func (entry *domainCacheEntry) duplicate() *domainCacheEntry { + result := newDomainCacheEntry() + result.Info = entry.Info + result.Config = entry.Config + result.ReplicationConfig = entry.ReplicationConfig + return result +} + +func (entry *domainCacheEntry) isExpired(now time.Time) bool { + return entry.expiry.IsZero() || now.After(entry.expiry) } diff --git a/common/cache/lru.go b/common/cache/lru.go index cf2caa21221..63c333762e6 100644 --- a/common/cache/lru.go +++ b/common/cache/lru.go @@ -243,19 +243,24 @@ func (c *lru) putInternal(key interface{}, value interface{}, allowUpdate bool) elt := c.byKey[key] if elt != nil { entry := elt.Value.(*entryImpl) - existing := entry.value - if allowUpdate { - entry.value = value - if c.ttl != 0 { - entry.createTime = time.Now() + if c.isEntryExpired(entry, time.Now()) { + // Entry has expired + c.deleteInternal(elt) + } else { + existing := entry.value + if allowUpdate { + entry.value = value + if c.ttl != 0 { + entry.createTime = time.Now() + } } - } - c.byAccess.MoveToFront(elt) - if c.pin { - entry.refCount++ + c.byAccess.MoveToFront(elt) + if c.pin { + entry.refCount++ + } + return existing, nil } - return existing, nil } entry := &entryImpl{ diff --git a/common/cluster/metadata.go b/common/cluster/metadata.go new file mode 100644 index 00000000000..f4c2a7c2efd --- /dev/null +++ b/common/cluster/metadata.go @@ -0,0 +1,95 @@ +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package cluster + +type ( + // Metadata provides information about clusters + Metadata interface { + GetNextFailoverVersion(int64) int64 + // GetCurrentClusterName return the current cluster name + GetCurrentClusterName() string + // GetAllClusterNames return the all cluster names, as a set + GetAllClusterNames() map[string]bool + } + + MetadataImpl struct { + // initialFailoverVersion is the initial failover version + initialFailoverVersion int64 + // failoverVersionIncrement is the increment of each cluster failover version + failoverVersionIncrement int64 + // currentClusterName is the name of the current cluster + currentClusterName string + // clusterNames contains all cluster names, as a set + clusterNames map[string]bool + } +) + +// NewMetadata create a new instance of Metadata +func NewMetadata(initialFailoverVersion int64, failoverVersionIncrement int64, + currentClusterName string, clusterNames []string) Metadata { + + if initialFailoverVersion < 0 { + panic("Bad initial failover version") + } else if failoverVersionIncrement <= initialFailoverVersion { + panic("Bad failover version increment") + } else if len(currentClusterName) == 0 { + panic("Current cluster name is empty") + } else if len(clusterNames) == 0 { + panic("Total number of all cluster names is 0") + } + + clusters := make(map[string]bool) + for _, clusterName := range clusterNames { + if len(clusterName) == 0 { + panic("Cluster name in all cluster names is empty") + } + clusters[clusterName] = true + } + if _, ok := clusters[currentClusterName]; !ok { + panic("Current cluster is not specified in all cluster names") + } + + return &MetadataImpl{ + initialFailoverVersion: initialFailoverVersion, + failoverVersionIncrement: failoverVersionIncrement, + currentClusterName: currentClusterName, + clusterNames: clusters, + } +} + +// GetNextFailoverVersion return the next failover version based on input +func (metadata *MetadataImpl) GetNextFailoverVersion(currentFailoverVersion int64) int64 { + failoverVersion := currentFailoverVersion/metadata.failoverVersionIncrement + metadata.initialFailoverVersion + if failoverVersion < currentFailoverVersion { + return failoverVersion + metadata.failoverVersionIncrement + } + return failoverVersion +} + +// GetCurrentClusterName return the current cluster name +func (metadata *MetadataImpl) GetCurrentClusterName() string { + return metadata.currentClusterName +} + +// GetAllClusterNames return the all cluster names +func (metadata *MetadataImpl) GetAllClusterNames() map[string]bool { + return metadata.clusterNames +} diff --git a/common/persistence/cassandraMetadataPersistence.go b/common/persistence/cassandraMetadataPersistence.go index 18479c26fe5..e3fec52bcee 100644 --- a/common/persistence/cassandraMetadataPersistence.go +++ b/common/persistence/cassandraMetadataPersistence.go @@ -37,7 +37,7 @@ const ( `name: ?, ` + `status: ?, ` + `description: ?, ` + - `owner_email: ?` + + `owner_email: ? ` + `}` templateDomainConfigType = `{` + @@ -45,33 +45,38 @@ const ( `emit_metric: ?` + `}` + templateDomainReplicationConfigType = `{` + + `active_cluster_name: ?, ` + + `failover_version: ?, ` + + `clusters: ? ` + + `}` + templateCreateDomainQuery = `INSERT INTO domains (` + - `id, domain, config) ` + - `VALUES(?, ` + templateDomainType + `, ` + templateDomainConfigType + `)` + `id, domain) ` + + `VALUES(?, {name: ?}) IF NOT EXISTS` templateCreateDomainByNameQuery = `INSERT INTO domains_by_name (` + - `name, domain, config) ` + - `VALUES(?, ` + templateDomainType + `, ` + templateDomainConfigType + `) IF NOT EXISTS` + `name, domain, config, replication_config) ` + + `VALUES(?, ` + templateDomainType + `, ` + templateDomainConfigType + `, ` + templateDomainReplicationConfigType + `) IF NOT EXISTS` - templateGetDomainQuery = `SELECT domain.id, domain.name, domain.status, domain.description, domain.owner_email, ` + - `config.retention, config.emit_metric ` + + templateGetDomainQuery = `SELECT domain.name ` + `FROM domains ` + `WHERE id = ?` templateGetDomainByNameQuery = `SELECT domain.id, domain.name, domain.status, domain.description, ` + - `domain.owner_email, config.retention, config.emit_metric ` + + `domain.owner_email, config.retention, config.emit_metric, ` + + `replication_config.active_cluster_name, replication_config.failover_version, replication_config.clusters, ` + + `version ` + `FROM domains_by_name ` + `WHERE name = ?` - templateUpdateDomainQuery = `UPDATE domains ` + - `SET domain = ` + templateDomainType + `, ` + - `config = ` + templateDomainConfigType + ` ` + - `WHERE id = ?` - templateUpdateDomainByNameQuery = `UPDATE domains_by_name ` + `SET domain = ` + templateDomainType + `, ` + - `config = ` + templateDomainConfigType + ` ` + - `WHERE name = ?` + `config = ` + templateDomainConfigType + `, ` + + `replication_config = ` + templateDomainReplicationConfigType + `, ` + + `version = ? ` + + `WHERE name = ? ` + + `IF version = ? ` templateDeleteDomainQuery = `DELETE FROM domains ` + `WHERE id = ?` @@ -82,13 +87,15 @@ const ( type ( cassandraMetadataPersistence struct { - session *gocql.Session - logger bark.Logger + session *gocql.Session + currentClusterName string + logger bark.Logger } ) // NewCassandraMetadataPersistence is used to create an instance of HistoryManager implementation -func NewCassandraMetadataPersistence(hosts string, port int, user, password, dc string, keyspace string, logger bark.Logger) (MetadataManager, +func NewCassandraMetadataPersistence(hosts string, port int, user, password, dc string, keyspace string, + currentClusterName string, logger bark.Logger) (MetadataManager, error) { cluster := common.NewCassandraCluster(hosts, port, user, password, dc) cluster.Keyspace = keyspace @@ -102,7 +109,11 @@ func NewCassandraMetadataPersistence(hosts string, port int, user, password, dc return nil, err } - return &cassandraMetadataPersistence{session: session, logger: logger}, nil + return &cassandraMetadataPersistence{ + session: session, + currentClusterName: currentClusterName, + logger: logger, + }, nil } // Close releases the resources held by this object @@ -118,15 +129,7 @@ func (m *cassandraMetadataPersistence) Close() { // orphaned entry from domains table. We might need a background job to delete those orphaned record. func (m *cassandraMetadataPersistence) CreateDomain(request *CreateDomainRequest) (*CreateDomainResponse, error) { domainUUID := uuid.New() - if err := m.session.Query(templateCreateDomainQuery, - domainUUID, - domainUUID, - request.Name, - request.Status, - request.Description, - request.OwnerEmail, - request.Retention, - request.EmitMetric).Exec(); err != nil { + if err := m.session.Query(templateCreateDomainQuery, domainUUID, request.Name).Exec(); err != nil { return nil, &workflow.InternalServiceError{ Message: fmt.Sprintf("CreateDomain operation failed. Inserting into domains table. Error: %v", err), } @@ -139,11 +142,16 @@ func (m *cassandraMetadataPersistence) CreateDomain(request *CreateDomainRequest request.Status, request.Description, request.OwnerEmail, - request.Retention, - request.EmitMetric) + request.Config.Retention, + request.Config.EmitMetric, + request.ReplicationConfig.ActiveClusterName, + request.ReplicationConfig.FailoverVersion, + serializeClusterConfigs(request.ReplicationConfig.Clusters), + ) previous := make(map[string]interface{}) applied, err := query.MapScanCAS(previous) + if err != nil { return nil, &workflow.InternalServiceError{ Message: fmt.Sprintf("CreateDomain operation failed. Inserting into domains_by_name table. Error: %v", err), @@ -152,8 +160,8 @@ func (m *cassandraMetadataPersistence) CreateDomain(request *CreateDomainRequest if !applied { // Domain already exist. Delete orphan domain record before returning back to user - if err = m.session.Query(templateDeleteDomainQuery, domainUUID).Exec(); err != nil { - m.logger.Warnf("Unable to delete orphan domain record. Error: %v", err) + if errDelete := m.session.Query(templateDeleteDomainQuery, domainUUID).Exec(); errDelete != nil { + m.logger.Warnf("Unable to delete orphan domain record. Error: %v", errDelete) } if domain, ok := previous["domain"].(map[string]interface{}); ok { @@ -176,69 +184,83 @@ func (m *cassandraMetadataPersistence) GetDomain(request *GetDomainRequest) (*Ge var err error info := &DomainInfo{} config := &DomainConfig{} - if len(request.ID) > 0 { - if len(request.Name) > 0 { - return nil, &workflow.BadRequestError{ - Message: "GetDomain operation failed. Both ID and Name specified in request.", - } - } + replicationConfig := &DomainReplicationConfig{} + var replicationClusters []map[string]interface{} + var version int64 - query = m.session.Query(templateGetDomainQuery, - request.ID) - err = query.Scan( - &info.ID, - &info.Name, - &info.Status, - &info.Description, - &info.OwnerEmail, - &config.Retention, - &config.EmitMetric) - } else if len(request.Name) > 0 { - query = m.session.Query(templateGetDomainByNameQuery, - request.Name) - err = query.Scan( - &info.ID, - &info.Name, - &info.Status, - &info.Description, - &info.OwnerEmail, - &config.Retention, - &config.EmitMetric) - } else { + if len(request.ID) > 0 && len(request.Name) > 0 { + return nil, &workflow.BadRequestError{ + Message: "GetDomain operation failed. Both ID and Name specified in request.", + } + } else if len(request.ID) == 0 && len(request.Name) == 0 { return nil, &workflow.BadRequestError{ Message: "GetDomain operation failed. Both ID and Name are empty.", } } - if err != nil { + handleError := func(name, ID string, err error) error { + identity := name + if len(ID) > 0 { + identity = ID + } if err == gocql.ErrNotFound { - var d string - if len(request.ID) > 0 { - d = request.ID - } else { - d = request.Name - } - - return nil, &workflow.EntityNotExistsError{ - Message: fmt.Sprintf("Domain %s does not exist.", d), + return &workflow.EntityNotExistsError{ + Message: fmt.Sprintf("Domain %s does not exist.", identity), } } - - return nil, &workflow.InternalServiceError{ + return &workflow.InternalServiceError{ Message: fmt.Sprintf("GetDomain operation failed. Error %v", err), } } + domainName := request.Name + if len(request.ID) > 0 { + query = m.session.Query(templateGetDomainQuery, request.ID) + err = query.Scan(&domainName) + if err != nil { + return nil, handleError(request.Name, request.ID, err) + } + } + + query = m.session.Query(templateGetDomainByNameQuery, domainName) + err = query.Scan( + &info.ID, + &info.Name, + &info.Status, + &info.Description, + &info.OwnerEmail, + &config.Retention, + &config.EmitMetric, + &replicationConfig.ActiveClusterName, + &replicationConfig.FailoverVersion, + &replicationClusters, + &version, + ) + + if err != nil { + return nil, handleError(request.Name, request.ID, err) + } + + replicationConfig.ActiveClusterName = GetOrUseDefaultActiveCluster(m.currentClusterName, replicationConfig.ActiveClusterName) + replicationConfig.Clusters = deserializeClusterConfigs(replicationClusters) + replicationConfig.Clusters = GetOrUseDefaultClusters(m.currentClusterName, replicationConfig.Clusters) + return &GetDomainResponse{ - Info: info, - Config: config, + Info: info, + Config: config, + ReplicationConfig: replicationConfig, + Version: version, }, nil } func (m *cassandraMetadataPersistence) UpdateDomain(request *UpdateDomainRequest) error { - batch := m.session.NewBatch(gocql.LoggedBatch) - - batch.Query(templateUpdateDomainQuery, + var nextVersion int64 = 1 + var currentVersion *int64 + if request.Version > 0 { + nextVersion = request.Version + 1 + currentVersion = &request.Version + } + query := m.session.Query(templateUpdateDomainByNameQuery, request.Info.ID, request.Info.Name, request.Info.Status, @@ -246,19 +268,15 @@ func (m *cassandraMetadataPersistence) UpdateDomain(request *UpdateDomainRequest request.Info.OwnerEmail, request.Config.Retention, request.Config.EmitMetric, - request.Info.ID) - - batch.Query(templateUpdateDomainByNameQuery, - request.Info.ID, + request.ReplicationConfig.ActiveClusterName, + request.ReplicationConfig.FailoverVersion, + serializeClusterConfigs(request.ReplicationConfig.Clusters), + nextVersion, request.Info.Name, - request.Info.Status, - request.Info.Description, - request.Info.OwnerEmail, - request.Config.Retention, - request.Config.EmitMetric, - request.Info.Name) + currentVersion, + ) - if err := m.session.ExecuteBatch(batch); err != nil { + if err := query.Exec(); err != nil { return &workflow.InternalServiceError{ Message: fmt.Sprintf("UpdateDomain operation failed. Error %v", err), } @@ -268,27 +286,64 @@ func (m *cassandraMetadataPersistence) UpdateDomain(request *UpdateDomainRequest } func (m *cassandraMetadataPersistence) DeleteDomain(request *DeleteDomainRequest) error { - query := m.session.Query(templateDeleteDomainQuery, - request.ID) - - if err := query.Exec(); err != nil { - return &workflow.InternalServiceError{ - Message: fmt.Sprintf("DeleteDomain operation failed. Error %v", err), + var name string + query := m.session.Query(templateGetDomainQuery, request.ID) + err := query.Scan(&name) + if err != nil { + if err == gocql.ErrNotFound { + return nil } + return err } - return nil + return m.deleteDomain(name, request.ID) } func (m *cassandraMetadataPersistence) DeleteDomainByName(request *DeleteDomainByNameRequest) error { - query := m.session.Query(templateDeleteDomainByNameQuery, - request.Name) + var ID string + query := m.session.Query(templateGetDomainByNameQuery, request.Name) + err := query.Scan(&ID, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + if err != nil { + if err == gocql.ErrNotFound { + return nil + } + return err + } + return m.deleteDomain(request.Name, ID) +} +func (m *cassandraMetadataPersistence) deleteDomain(name, ID string) error { + query := m.session.Query(templateDeleteDomainByNameQuery, name) if err := query.Exec(); err != nil { return &workflow.InternalServiceError{ Message: fmt.Sprintf("DeleteDomainByName operation failed. Error %v", err), } } + query = m.session.Query(templateDeleteDomainQuery, ID) + if err := query.Exec(); err != nil { + return &workflow.InternalServiceError{ + Message: fmt.Sprintf("DeleteDomain operation failed. Error %v", err), + } + } + return nil } + +func serializeClusterConfigs(replicationConfigs []*ClusterReplicationConfig) []map[string]interface{} { + seriaizedReplicationConfigs := []map[string]interface{}{} + for index := range replicationConfigs { + seriaizedReplicationConfigs = append(seriaizedReplicationConfigs, replicationConfigs[index].serialize()) + } + return seriaizedReplicationConfigs +} + +func deserializeClusterConfigs(replicationConfigs []map[string]interface{}) []*ClusterReplicationConfig { + deseriaizedReplicationConfigs := []*ClusterReplicationConfig{} + for index := range replicationConfigs { + deseriaizedReplicationConfig := &ClusterReplicationConfig{} + deseriaizedReplicationConfig.deserialize(replicationConfigs[index]) + deseriaizedReplicationConfigs = append(deseriaizedReplicationConfigs, deseriaizedReplicationConfig) + } + return deseriaizedReplicationConfigs +} diff --git a/common/persistence/cassandraMetadataPersistence_test.go b/common/persistence/cassandraMetadataPersistence_test.go index 302952273f0..b2233c82855 100644 --- a/common/persistence/cassandraMetadataPersistence_test.go +++ b/common/persistence/cassandraMetadataPersistence_test.go @@ -29,7 +29,6 @@ import ( "github.com/stretchr/testify/suite" gen "github.com/uber/cadence/.gen/go/shared" - //"github.com/uber/cadence/common" ) type ( @@ -82,14 +81,35 @@ func (m *metadataPersistenceSuite) TestCreateDomain() { &DomainConfig{ Retention: retention, EmitMetric: emitMetric, - }) + }, + &DomainReplicationConfig{}, + ) + m.Nil(err0) m.NotNil(resp0) id := resp0.ID m.True(len(id) > 0) - resp1, err1 := m.CreateDomain( + // for domain which do not have replication config set, will default to + // use current cluster as active, with current cluster as all clusters + resp1, err1 := m.GetDomain(id, "") + m.Nil(err1) + m.NotNil(resp1) + m.Equal(id, resp1.Info.ID) + m.Equal(name, resp1.Info.Name) + m.Equal(status, resp1.Info.Status) + m.Equal(description, resp1.Info.Description) + m.Equal(owner, resp1.Info.OwnerEmail) + m.Equal(retention, resp1.Config.Retention) + m.Equal(emitMetric, resp1.Config.EmitMetric) + m.Equal(testCurrentClusterName, resp1.ReplicationConfig.ActiveClusterName) + m.Equal(int64(0), resp1.ReplicationConfig.FailoverVersion) + m.Equal(1, len(resp1.ReplicationConfig.Clusters)) + m.True(resp1.ReplicationConfig.Clusters[0].ClusterName == testCurrentClusterName) + m.Equal(int64(0), resp1.Version) + + resp2, err2 := m.CreateDomain( &DomainInfo{ Name: name, Status: status, @@ -99,10 +119,12 @@ func (m *metadataPersistenceSuite) TestCreateDomain() { &DomainConfig{ Retention: 100, EmitMetric: false, - }) - m.NotNil(err1) - m.IsType(&gen.DomainAlreadyExistsError{}, err1) - m.Nil(resp1) + }, + &DomainReplicationConfig{}, + ) + m.NotNil(err2) + m.IsType(&gen.DomainAlreadyExistsError{}, err2) + m.Nil(resp2) } func (m *metadataPersistenceSuite) TestGetDomain() { @@ -113,6 +135,18 @@ func (m *metadataPersistenceSuite) TestGetDomain() { retention := int32(10) emitMetric := true + clusterActive := "some random active cluster name" + clusterStandby := "some random standby cluster name" + failoverVersion := int64(59) + clusters := []*ClusterReplicationConfig{ + &ClusterReplicationConfig{ + ClusterName: clusterActive, + }, + &ClusterReplicationConfig{ + ClusterName: clusterStandby, + }, + } + resp0, err0 := m.GetDomain("", "does-not-exist") m.Nil(resp0) m.NotNil(err0) @@ -128,7 +162,13 @@ func (m *metadataPersistenceSuite) TestGetDomain() { &DomainConfig{ Retention: retention, EmitMetric: emitMetric, - }) + }, + &DomainReplicationConfig{ + ActiveClusterName: clusterActive, + FailoverVersion: failoverVersion, + Clusters: clusters, + }, + ) m.Nil(err1) m.NotNil(resp1) @@ -145,6 +185,13 @@ func (m *metadataPersistenceSuite) TestGetDomain() { m.Equal(owner, resp2.Info.OwnerEmail) m.Equal(retention, resp2.Config.Retention) m.Equal(emitMetric, resp2.Config.EmitMetric) + m.Equal(clusterActive, resp2.ReplicationConfig.ActiveClusterName) + m.Equal(failoverVersion, resp2.ReplicationConfig.FailoverVersion) + m.Equal(len(clusters), len(resp2.ReplicationConfig.Clusters)) + for index := range clusters { + m.Equal(clusters[index], resp2.ReplicationConfig.Clusters[index]) + } + m.Equal(int64(0), resp2.Version) resp3, err3 := m.GetDomain("", name) m.Nil(err3) @@ -156,6 +203,13 @@ func (m *metadataPersistenceSuite) TestGetDomain() { m.Equal(owner, resp3.Info.OwnerEmail) m.Equal(retention, resp3.Config.Retention) m.Equal(emitMetric, resp3.Config.EmitMetric) + m.Equal(clusterActive, resp3.ReplicationConfig.ActiveClusterName) + m.Equal(failoverVersion, resp3.ReplicationConfig.FailoverVersion) + m.Equal(len(clusters), len(resp3.ReplicationConfig.Clusters)) + for index := range clusters { + m.Equal(clusters[index], resp3.ReplicationConfig.Clusters[index]) + } + m.Equal(int64(0), resp3.Version) resp4, err4 := m.GetDomain(id, name) m.NotNil(err4) @@ -171,6 +225,18 @@ func (m *metadataPersistenceSuite) TestUpdateDomain() { retention := int32(10) emitMetric := true + clusterActive := "some random active cluster name" + clusterStandby := "some random standby cluster name" + failoverVersion := int64(59) + clusters := []*ClusterReplicationConfig{ + &ClusterReplicationConfig{ + ClusterName: clusterActive, + }, + &ClusterReplicationConfig{ + ClusterName: clusterStandby, + }, + } + resp1, err1 := m.CreateDomain( &DomainInfo{ Name: name, @@ -181,7 +247,13 @@ func (m *metadataPersistenceSuite) TestUpdateDomain() { &DomainConfig{ Retention: retention, EmitMetric: emitMetric, - }) + }, + &DomainReplicationConfig{ + ActiveClusterName: clusterActive, + FailoverVersion: failoverVersion, + Clusters: clusters, + }, + ) m.Nil(err1) id := resp1.ID @@ -195,6 +267,18 @@ func (m *metadataPersistenceSuite) TestUpdateDomain() { updatedRetention := int32(20) updatedEmitMetric := false + updateClusterActive := "other random active cluster name" + updateClusterStandby := "other random standby cluster name" + updateFailoverVersion := int64(28) + updateClusters := []*ClusterReplicationConfig{ + &ClusterReplicationConfig{ + ClusterName: updateClusterActive, + }, + &ClusterReplicationConfig{ + ClusterName: updateClusterStandby, + }, + } + err3 := m.UpdateDomain( &DomainInfo{ ID: resp2.Info.ID, @@ -206,7 +290,14 @@ func (m *metadataPersistenceSuite) TestUpdateDomain() { &DomainConfig{ Retention: updatedRetention, EmitMetric: updatedEmitMetric, - }) + }, + &DomainReplicationConfig{ + ActiveClusterName: updateClusterActive, + FailoverVersion: updateFailoverVersion, + Clusters: updateClusters, + }, + resp2.Version, + ) m.Nil(err3) @@ -220,6 +311,13 @@ func (m *metadataPersistenceSuite) TestUpdateDomain() { m.Equal(updatedOwner, resp4.Info.OwnerEmail) m.Equal(updatedRetention, resp4.Config.Retention) m.Equal(updatedEmitMetric, resp4.Config.EmitMetric) + m.Equal(updateClusterActive, resp4.ReplicationConfig.ActiveClusterName) + m.Equal(updateFailoverVersion, resp4.ReplicationConfig.FailoverVersion) + m.Equal(len(updateClusters), len(resp4.ReplicationConfig.Clusters)) + for index := range clusters { + m.Equal(updateClusters[index], resp4.ReplicationConfig.Clusters[index]) + } + m.Equal(resp2.Version+1, resp4.Version) resp5, err5 := m.GetDomain("", name) m.Nil(err5) @@ -231,6 +329,13 @@ func (m *metadataPersistenceSuite) TestUpdateDomain() { m.Equal(updatedOwner, resp5.Info.OwnerEmail) m.Equal(updatedRetention, resp5.Config.Retention) m.Equal(updatedEmitMetric, resp5.Config.EmitMetric) + m.Equal(updateClusterActive, resp5.ReplicationConfig.ActiveClusterName) + m.Equal(updateFailoverVersion, resp5.ReplicationConfig.FailoverVersion) + m.Equal(len(updateClusters), len(resp5.ReplicationConfig.Clusters)) + for index := range clusters { + m.Equal(updateClusters[index], resp5.ReplicationConfig.Clusters[index]) + } + m.Equal(resp2.Version+1, resp5.Version) } func (m *metadataPersistenceSuite) TestDeleteDomain() { @@ -241,6 +346,18 @@ func (m *metadataPersistenceSuite) TestDeleteDomain() { retention := 10 emitMetric := true + clusterActive := "some random active cluster name" + clusterStandby := "some random standby cluster name" + failoverVersion := int64(59) + clusters := []*ClusterReplicationConfig{ + &ClusterReplicationConfig{ + ClusterName: clusterActive, + }, + &ClusterReplicationConfig{ + ClusterName: clusterStandby, + }, + } + resp1, err1 := m.CreateDomain( &DomainInfo{ Name: name, @@ -251,9 +368,14 @@ func (m *metadataPersistenceSuite) TestDeleteDomain() { &DomainConfig{ Retention: int32(retention), EmitMetric: emitMetric, - }) + }, + &DomainReplicationConfig{ + ActiveClusterName: clusterActive, + FailoverVersion: failoverVersion, + Clusters: clusters, + }, + ) m.Nil(err1) - id := resp1.ID m.True(len(id) > 0) @@ -270,26 +392,53 @@ func (m *metadataPersistenceSuite) TestDeleteDomain() { m.Nil(resp4) resp5, err5 := m.GetDomain(id, "") - m.Nil(err5) - m.NotNil(resp5) + m.NotNil(err5) + m.IsType(&gen.EntityNotExistsError{}, err5) + m.Nil(resp5) - err6 := m.DeleteDomain(id, "") + resp6, err6 := m.CreateDomain( + &DomainInfo{ + Name: name, + Status: status, + Description: description, + OwnerEmail: owner, + }, + &DomainConfig{ + Retention: int32(retention), + EmitMetric: emitMetric, + }, + &DomainReplicationConfig{ + ActiveClusterName: clusterActive, + FailoverVersion: failoverVersion, + Clusters: clusters, + }, + ) m.Nil(err6) + id = resp6.ID + m.True(len(id) > 0) + + err7 := m.DeleteDomain(id, "") + m.Nil(err7) + + resp8, err8 := m.GetDomain("", name) + m.NotNil(err8) + m.IsType(&gen.EntityNotExistsError{}, err8) + m.Nil(resp8) - resp7, err7 := m.GetDomain(id, "") - m.NotNil(err7) - m.IsType(&gen.EntityNotExistsError{}, err7) - m.Nil(resp7) + resp9, err9 := m.GetDomain(id, "") + m.NotNil(err9) + m.IsType(&gen.EntityNotExistsError{}, err9) + m.Nil(resp9) } -func (m *metadataPersistenceSuite) CreateDomain(info *DomainInfo, config *DomainConfig) (*CreateDomainResponse, error) { +func (m *metadataPersistenceSuite) CreateDomain(info *DomainInfo, config *DomainConfig, replicationConfig *DomainReplicationConfig) (*CreateDomainResponse, error) { return m.MetadataManager.CreateDomain(&CreateDomainRequest{ - Name: info.Name, - Status: info.Status, - Description: info.Description, - OwnerEmail: info.OwnerEmail, - Retention: config.Retention, - EmitMetric: config.EmitMetric, + Name: info.Name, + Status: info.Status, + Description: info.Description, + OwnerEmail: info.OwnerEmail, + Config: config, + ReplicationConfig: replicationConfig, }) } @@ -300,10 +449,12 @@ func (m *metadataPersistenceSuite) GetDomain(id, name string) (*GetDomainRespons }) } -func (m *metadataPersistenceSuite) UpdateDomain(info *DomainInfo, config *DomainConfig) error { +func (m *metadataPersistenceSuite) UpdateDomain(info *DomainInfo, config *DomainConfig, replicationConfig *DomainReplicationConfig, version int64) error { return m.MetadataManager.UpdateDomain(&UpdateDomainRequest{ - Info: info, - Config: config, + Info: info, + Config: config, + ReplicationConfig: replicationConfig, + Version: version, }) } diff --git a/common/persistence/clusterMetadata.go b/common/persistence/clusterMetadata.go new file mode 100644 index 00000000000..e5c14cc9479 --- /dev/null +++ b/common/persistence/clusterMetadata.go @@ -0,0 +1,41 @@ +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package persistence + +// GetOrUseDefaultActiveCluster return the current cluster name or use the input if valid +func GetOrUseDefaultActiveCluster(currentClusterName string, activeClusterName string) string { + if len(activeClusterName) == 0 { + return currentClusterName + } + return activeClusterName +} + +// GetOrUseDefaultClusters return the current cluster or use the input if valid +func GetOrUseDefaultClusters(currentClusterName string, clusters []*ClusterReplicationConfig) []*ClusterReplicationConfig { + if len(clusters) == 0 { + return []*ClusterReplicationConfig{ + &ClusterReplicationConfig{ + ClusterName: currentClusterName, + }, + } + } + return clusters +} diff --git a/common/persistence/dataInterfaces.go b/common/persistence/dataInterfaces.go index 7d3b2e6a398..714fcd6a515 100644 --- a/common/persistence/dataInterfaces.go +++ b/common/persistence/dataInterfaces.go @@ -645,14 +645,26 @@ type ( EmitMetric bool } + // DomainReplicationConfig describes the cross DC domain replication configuration + DomainReplicationConfig struct { + ActiveClusterName string + FailoverVersion int64 + Clusters []*ClusterReplicationConfig + } + + // ClusterReplicationConfig describes the cross DC cluster replication configuration + ClusterReplicationConfig struct { + ClusterName string + } + // CreateDomainRequest is used to create the domain CreateDomainRequest struct { - Name string - Status int - Description string - OwnerEmail string - Retention int32 - EmitMetric bool + Name string + Status int + Description string + OwnerEmail string + Config *DomainConfig + ReplicationConfig *DomainReplicationConfig } // CreateDomainResponse is the response for CreateDomain @@ -668,14 +680,18 @@ type ( // GetDomainResponse is the response for GetDomain GetDomainResponse struct { - Info *DomainInfo - Config *DomainConfig + Info *DomainInfo + Config *DomainConfig + ReplicationConfig *DomainReplicationConfig + Version int64 } // UpdateDomainRequest is used to update domain UpdateDomainRequest struct { - Info *DomainInfo - Config *DomainConfig + Info *DomainInfo + Config *DomainConfig + ReplicationConfig *DomainReplicationConfig + Version int64 } // DeleteDomainRequest is used to delete domain entry from domains table @@ -1004,3 +1020,13 @@ func (h *SerializedHistoryEventBatch) String() string { return fmt.Sprintf("[encodingType:%v,historyVersion:%v,history:%v]", h.EncodingType, h.Version, string(h.Data)) } + +func (config *ClusterReplicationConfig) serialize() map[string]interface{} { + output := make(map[string]interface{}) + output["cluster_name"] = config.ClusterName + return output +} + +func (config *ClusterReplicationConfig) deserialize(input map[string]interface{}) { + config.ClusterName = input["cluster_name"].(string) +} diff --git a/common/persistence/persistenceTestBase.go b/common/persistence/persistenceTestBase.go index 90fdd84a5c5..603313cabaf 100644 --- a/common/persistence/persistenceTestBase.go +++ b/common/persistence/persistenceTestBase.go @@ -34,16 +34,25 @@ import ( workflow "github.com/uber/cadence/.gen/go/shared" "github.com/uber/cadence/common" + "github.com/uber/cadence/common/cluster" "github.com/uber/cadence/common/logging" ) const ( - testWorkflowClusterHosts = "127.0.0.1" - testPort = 0 - testUser = "" - testPassword = "" - testDatacenter = "" - testSchemaDir = "../.." + testWorkflowClusterHosts = "127.0.0.1" + testPort = 0 + testUser = "" + testPassword = "" + testDatacenter = "" + testSchemaDir = "../.." + testInitialFailoverVersion = int64(0) + testFailoverVersionIncrement = int64(10) + testCurrentClusterName = "current-cluster" + testAlternativeClusterName = "alternative-cluster" +) + +var ( + testAllClusterNames = []string{testCurrentClusterName, testAlternativeClusterName} ) type ( @@ -54,14 +63,16 @@ type ( // TestBaseOptions options to configure workflow test base. TestBaseOptions struct { - ClusterHost string - ClusterPort int - ClusterUser string - ClusterPassword string - KeySpace string - Datacenter string - DropKeySpace bool - SchemaDir string + ClusterHost string + ClusterPort int + ClusterUser string + ClusterPassword string + KeySpace string + Datacenter string + DropKeySpace bool + SchemaDir string + CurrentClusterName string + AllClusterNames []string } // TestBase wraps the base setup needed to create workflows over persistence layer. @@ -75,6 +86,7 @@ type ( VisibilityMgr VisibilityManager ShardInfo *ShardInfo TaskIDGenerator TransferTaskIDGenerator + ClusterMetadata cluster.Metadata readLevel int64 CassandraTestCluster } @@ -104,6 +116,12 @@ func (g *testTransferTaskIDGenerator) GetNextTransferTaskID() (int64, error) { // SetupWorkflowStoreWithOptions to setup workflow test base func (s *TestBase) SetupWorkflowStoreWithOptions(options TestBaseOptions) { log := bark.NewLoggerFromLogrus(log.New()) + s.ClusterMetadata = cluster.NewMetadata( + testInitialFailoverVersion, + testFailoverVersionIncrement, + testCurrentClusterName, + testAllClusterNames, + ) // Setup Workflow keyspace and deploy schema for tests s.CassandraTestCluster.setupTestCluster(options.KeySpace, options.DropKeySpace, options.SchemaDir) shardID := 0 @@ -137,7 +155,7 @@ func (s *TestBase) SetupWorkflowStoreWithOptions(options TestBaseOptions) { } s.MetadataManager, err = NewCassandraMetadataPersistence(options.ClusterHost, options.ClusterPort, options.ClusterUser, - options.ClusterPassword, options.Datacenter, s.CassandraTestCluster.keyspace, log) + options.ClusterPassword, options.Datacenter, s.CassandraTestCluster.keyspace, s.ClusterMetadata.GetCurrentClusterName(), log) if err != nil { log.Fatal(err) } @@ -778,12 +796,14 @@ func (s *TestBase) CompleteTask(domainID, taskList string, taskType int, taskID // SetupWorkflowStore to setup workflow test base func (s *TestBase) SetupWorkflowStore() { s.SetupWorkflowStoreWithOptions(TestBaseOptions{ - SchemaDir: testSchemaDir, - ClusterHost: testWorkflowClusterHosts, - ClusterPort: testPort, - ClusterUser: testUser, - ClusterPassword: testPassword, - DropKeySpace: true, + SchemaDir: testSchemaDir, + ClusterHost: testWorkflowClusterHosts, + ClusterPort: testPort, + ClusterUser: testUser, + ClusterPassword: testPassword, + DropKeySpace: true, + CurrentClusterName: testCurrentClusterName, + AllClusterNames: testAllClusterNames, }) } diff --git a/common/service/config/config.go b/common/service/config/config.go index de7130154a6..211980c78b8 100644 --- a/common/service/config/config.go +++ b/common/service/config/config.go @@ -37,6 +37,8 @@ type ( Cassandra Cassandra `yaml:"cassandra"` // Log is the logging config Log Logger `yaml:"log"` + // ClustersInfo is the config containing all valid clusters and active acluster + ClustersInfo ClustersInfo `yaml:"clustersInfo"` // Services is a map of service name to service config items Services map[string]Service `yaml:"services"` } @@ -117,6 +119,18 @@ type ( OutputFile string `yaml:"outputFile"` } + // ClustersInfo contains the all cluster names and active cluster + ClustersInfo struct { + // InitialFailoverVersion is the initial failover version + InitialFailoverVersion int64 `yaml:"initialFailoverVersion"` + // FailoverVersionIncrement is the increment of each cluster failover version + FailoverVersionIncrement int64 `yaml:"failoverVersionIncrement"` + // CurrentClusterName is the name of the current cluster + CurrentClusterName string `yaml:"currentClusterName"` + // ClusterNames contains all cluster names + ClusterNames []string `yaml:"clusterNames"` + } + // Metrics contains the config items for metrics subsystem Metrics struct { // M3 is the configuration for m3 metrics reporter diff --git a/common/service/service.go b/common/service/service.go index e44c409c8b1..f73b43cd1f5 100644 --- a/common/service/service.go +++ b/common/service/service.go @@ -27,6 +27,7 @@ import ( "github.com/uber/cadence/client" "github.com/uber/cadence/common" + "github.com/uber/cadence/common/cluster" "github.com/uber/cadence/common/logging" "github.com/uber/cadence/common/membership" "github.com/uber/cadence/common/metrics" @@ -51,6 +52,7 @@ type ( RPCFactory common.RPCFactory PProfInitializer common.PProfInitializer CassandraConfig config.Cassandra + ClusterMetadata cluster.Metadata } // RingpopFactory provides a bootstrapped ringpop @@ -76,6 +78,7 @@ type ( metricsScope tally.Scope runtimeMetricsReporter *metrics.RuntimeMetricsReporter metricsClient metrics.Client + clusterMetadata cluster.Metadata } ) @@ -90,6 +93,7 @@ func New(params *BootstrapParams) Service { pprofInitializer: params.PProfInitializer, metricsScope: params.MetricScope, numberOfHistoryShards: params.CassandraConfig.NumHistoryShards, + clusterMetadata: params.ClusterMetadata, } sVice.runtimeMetricsReporter = metrics.NewRuntimeMetricsReporter(params.MetricScope, time.Minute, sVice.logger) sVice.metricsClient = metrics.NewClient(params.MetricScope, getMetricsServiceIdx(params.Name, params.Logger)) @@ -206,6 +210,11 @@ func (h *serviceImpl) GetDispatcher() *yarpc.Dispatcher { return h.dispatcher } +// GetClusterMetadata returns the service cluster metadata +func (h *serviceImpl) GetClusterMetadata() cluster.Metadata { + return h.clusterMetadata +} + func getMetricsServiceIdx(serviceName string, logger bark.Logger) metrics.ServiceIdx { switch serviceName { case common.FrontendServiceName: diff --git a/common/service/serviceinterfaces.go b/common/service/serviceinterfaces.go index 04d13c22ea4..237f8a1b9ce 100644 --- a/common/service/serviceinterfaces.go +++ b/common/service/serviceinterfaces.go @@ -23,6 +23,7 @@ package service import ( "github.com/uber-common/bark" "github.com/uber/cadence/client" + "github.com/uber/cadence/common/cluster" "github.com/uber/cadence/common/membership" "github.com/uber/cadence/common/metrics" "go.uber.org/yarpc" @@ -51,5 +52,8 @@ type ( GetMembershipMonitor() membership.Monitor GetHostInfo() *membership.HostInfo + + // GetClusterMetadata returns the service cluster metadata + GetClusterMetadata() cluster.Metadata } ) diff --git a/config/development.yaml b/config/development.yaml index 7ccc86413cd..42a832ed0ed 100644 --- a/config/development.yaml +++ b/config/development.yaml @@ -43,4 +43,12 @@ services: hostPort: "127.0.0.1:8125" prefix: "cadence" pprof: - port: 7937 \ No newline at end of file + port: 7937 + +clustersInfo: + initialFailoverVersion: 0 + failoverVersionIncrement: 10 + currentClusterName: "sjc1" + clusterNames: + - "dca1" + - "sjc1" \ No newline at end of file diff --git a/host/integration_test.go b/host/integration_test.go index 8855cd8196d..b33db74355e 100644 --- a/host/integration_test.go +++ b/host/integration_test.go @@ -130,7 +130,7 @@ func (s *integrationSuite) SetupTest() { s.setupShards() - s.host = NewCadence(s.MetadataManager, s.ShardMgr, s.HistoryMgr, s.ExecutionMgrFactory, s.TaskMgr, + s.host = NewCadence(s.ClusterMetadata, s.MetadataManager, s.ShardMgr, s.HistoryMgr, s.ExecutionMgrFactory, s.TaskMgr, s.VisibilityMgr, testNumberOfHistoryShards, testNumberOfHistoryHosts, s.logger) s.host.Start() @@ -141,16 +141,22 @@ func (s *integrationSuite) SetupTest() { Name: s.domainName, Status: persistence.DomainStatusRegistered, Description: "Test domain for integration test", - Retention: 1, - EmitMetric: false, + Config: &persistence.DomainConfig{ + Retention: 1, + EmitMetric: false, + }, + ReplicationConfig: &persistence.DomainReplicationConfig{}, }) s.foreignDomainName = "integration-foreign-test-domain" s.MetadataManager.CreateDomain(&persistence.CreateDomainRequest{ Name: s.foreignDomainName, Status: persistence.DomainStatusRegistered, Description: "Test foreign domain for integration test", - Retention: 1, - EmitMetric: false, + Config: &persistence.DomainConfig{ + Retention: 1, + EmitMetric: false, + }, + ReplicationConfig: &persistence.DomainReplicationConfig{}, }) } @@ -160,6 +166,267 @@ func (s *integrationSuite) TearDownTest() { s.TearDownWorkflowStore() } +func (s *integrationSuite) TestIntegrationRegisterGetDomain_AllDefault() { + domainName := "some random domain name" + clusters := []*workflow.ClusterReplicationConfiguration{} + for _, replicationConfig := range persistence.GetOrUseDefaultClusters(s.ClusterMetadata.GetCurrentClusterName(), nil) { + clusters = append(clusters, &workflow.ClusterReplicationConfiguration{ + ClusterName: common.StringPtr(replicationConfig.ClusterName), + }) + } + + err := s.engine.RegisterDomain(createContext(), &workflow.RegisterDomainRequest{ + Name: common.StringPtr(domainName), + }) + s.Nil(err) + + resp, err := s.engine.DescribeDomain(createContext(), &workflow.DescribeDomainRequest{ + Name: common.StringPtr(domainName), + }) + s.Nil(err) + s.Equal(domainName, resp.DomainInfo.GetName()) + s.Equal(workflow.DomainStatusRegistered, *resp.DomainInfo.Status) + s.Empty(resp.DomainInfo.GetDescription()) + s.Empty(resp.DomainInfo.GetOwnerEmail()) + s.Equal(int32(0), resp.Configuration.GetWorkflowExecutionRetentionPeriodInDays()) + s.Equal(false, resp.Configuration.GetEmitMetric()) + s.Equal(s.ClusterMetadata.GetCurrentClusterName(), resp.ReplicationConfiguration.GetActiveClusterName()) + s.Equal(clusters, resp.ReplicationConfiguration.Clusters) +} + +func (s *integrationSuite) TestIntegrationRegisterGetDomain_NoDefault() { + domainName := "some random domain name" + description := "some random description" + email := "some random email" + retention := int32(7) + emitMetric := true + clusters := []*workflow.ClusterReplicationConfiguration{} + for clusterName := range s.ClusterMetadata.GetAllClusterNames() { + clusters = append(clusters, &workflow.ClusterReplicationConfiguration{ + ClusterName: common.StringPtr(clusterName), + }) + } + + err := s.engine.RegisterDomain(createContext(), &workflow.RegisterDomainRequest{ + Name: common.StringPtr(domainName), + Description: common.StringPtr(description), + OwnerEmail: common.StringPtr(email), + WorkflowExecutionRetentionPeriodInDays: common.Int32Ptr(retention), + EmitMetric: common.BoolPtr(emitMetric), + Clusters: clusters, + }) + s.Nil(err) + + resp, err := s.engine.DescribeDomain(createContext(), &workflow.DescribeDomainRequest{ + Name: common.StringPtr(domainName), + }) + s.Nil(err) + s.Equal(domainName, resp.DomainInfo.GetName()) + s.Equal(workflow.DomainStatusRegistered, *resp.DomainInfo.Status) + s.Equal(description, resp.DomainInfo.GetDescription()) + s.Equal(email, resp.DomainInfo.GetOwnerEmail()) + s.Equal(retention, resp.Configuration.GetWorkflowExecutionRetentionPeriodInDays()) + s.Equal(emitMetric, resp.Configuration.GetEmitMetric()) + s.Equal(s.ClusterMetadata.GetCurrentClusterName(), resp.ReplicationConfiguration.GetActiveClusterName()) + s.Equal(clusters, resp.ReplicationConfiguration.Clusters) +} + +func (s *integrationSuite) TestIntegrationUpdateGetDomain_AllSet() { + domainName := "some random domain name" + err := s.engine.RegisterDomain(createContext(), &workflow.RegisterDomainRequest{ + Name: common.StringPtr(domainName), + }) + s.Nil(err) + + description := "some random description" + email := "some random email" + retention := int32(7) + emitMetric := true + clusters := []*workflow.ClusterReplicationConfiguration{} + for clusterName := range s.ClusterMetadata.GetAllClusterNames() { + clusters = append(clusters, &workflow.ClusterReplicationConfiguration{ + ClusterName: common.StringPtr(clusterName), + }) + } + + updateResp, err := s.engine.UpdateDomain(createContext(), &workflow.UpdateDomainRequest{ + Name: common.StringPtr(domainName), + UpdatedInfo: &workflow.UpdateDomainInfo{ + Description: common.StringPtr(description), + OwnerEmail: common.StringPtr(email), + }, + Configuration: &workflow.DomainConfiguration{ + WorkflowExecutionRetentionPeriodInDays: common.Int32Ptr(retention), + EmitMetric: common.BoolPtr(emitMetric), + }, + ReplicationConfiguration: &workflow.DomainReplicationConfiguration{ + Clusters: clusters, + }, + }) + s.Nil(err) + s.Equal(domainName, updateResp.DomainInfo.GetName()) + s.Equal(workflow.DomainStatusRegistered, *updateResp.DomainInfo.Status) + s.Equal(description, updateResp.DomainInfo.GetDescription()) + s.Equal(email, updateResp.DomainInfo.GetOwnerEmail()) + s.Equal(retention, updateResp.Configuration.GetWorkflowExecutionRetentionPeriodInDays()) + s.Equal(emitMetric, updateResp.Configuration.GetEmitMetric()) + s.Equal(s.ClusterMetadata.GetCurrentClusterName(), updateResp.ReplicationConfiguration.GetActiveClusterName()) + s.Equal(clusters, updateResp.ReplicationConfiguration.Clusters) + + describeResp, err := s.engine.DescribeDomain(createContext(), &workflow.DescribeDomainRequest{ + Name: common.StringPtr(domainName), + }) + s.Nil(err) + s.Equal(domainName, describeResp.DomainInfo.GetName()) + s.Equal(workflow.DomainStatusRegistered, *describeResp.DomainInfo.Status) + s.Equal(description, describeResp.DomainInfo.GetDescription()) + s.Equal(email, describeResp.DomainInfo.GetOwnerEmail()) + s.Equal(retention, describeResp.Configuration.GetWorkflowExecutionRetentionPeriodInDays()) + s.Equal(emitMetric, describeResp.Configuration.GetEmitMetric()) + s.Equal(s.ClusterMetadata.GetCurrentClusterName(), describeResp.ReplicationConfiguration.GetActiveClusterName()) + s.Equal(clusters, describeResp.ReplicationConfiguration.Clusters) +} + +func (s *integrationSuite) TestIntegrationUpdateGetDomain_NoSet() { + domainName := "some random domain name" + description := "some random description" + email := "some random email" + retention := int32(7) + emitMetric := true + clusters := []*workflow.ClusterReplicationConfiguration{} + for clusterName := range s.ClusterMetadata.GetAllClusterNames() { + clusters = append(clusters, &workflow.ClusterReplicationConfiguration{ + ClusterName: common.StringPtr(clusterName), + }) + } + + err := s.engine.RegisterDomain(createContext(), &workflow.RegisterDomainRequest{ + Name: common.StringPtr(domainName), + Description: common.StringPtr(description), + OwnerEmail: common.StringPtr(email), + WorkflowExecutionRetentionPeriodInDays: common.Int32Ptr(retention), + EmitMetric: common.BoolPtr(emitMetric), + Clusters: clusters, + }) + s.Nil(err) + + updateResp, err := s.engine.UpdateDomain(createContext(), &workflow.UpdateDomainRequest{ + Name: common.StringPtr(domainName), + }) + s.Nil(err) + s.Equal(domainName, updateResp.DomainInfo.GetName()) + s.Equal(workflow.DomainStatusRegistered, *updateResp.DomainInfo.Status) + s.Equal(description, updateResp.DomainInfo.GetDescription()) + s.Equal(email, updateResp.DomainInfo.GetOwnerEmail()) + s.Equal(retention, updateResp.Configuration.GetWorkflowExecutionRetentionPeriodInDays()) + s.Equal(emitMetric, updateResp.Configuration.GetEmitMetric()) + s.Equal(s.ClusterMetadata.GetCurrentClusterName(), updateResp.ReplicationConfiguration.GetActiveClusterName()) + s.Equal(clusters, updateResp.ReplicationConfiguration.Clusters) + + describeResp, err := s.engine.DescribeDomain(createContext(), &workflow.DescribeDomainRequest{ + Name: common.StringPtr(domainName), + }) + s.Nil(err) + s.Equal(domainName, describeResp.DomainInfo.GetName()) + s.Equal(workflow.DomainStatusRegistered, *describeResp.DomainInfo.Status) + s.Equal(description, describeResp.DomainInfo.GetDescription()) + s.Equal(email, describeResp.DomainInfo.GetOwnerEmail()) + s.Equal(retention, describeResp.Configuration.GetWorkflowExecutionRetentionPeriodInDays()) + s.Equal(emitMetric, describeResp.Configuration.GetEmitMetric()) + s.Equal(s.ClusterMetadata.GetCurrentClusterName(), describeResp.ReplicationConfiguration.GetActiveClusterName()) + s.Equal(clusters, describeResp.ReplicationConfiguration.Clusters) +} + +func (s *integrationSuite) TestIntegrationUpdateGetDomain_Failover() { + domainName := "some random domain name" + description := "some random description" + email := "some random email" + retention := int32(7) + emitMetric := true + clusters := []*workflow.ClusterReplicationConfiguration{} + + activeClusterName := "" + failoverVersion := int64(59) + persistenceClusters := []*persistence.ClusterReplicationConfig{} + for clusterName := range s.ClusterMetadata.GetAllClusterNames() { + clusters = append(clusters, &workflow.ClusterReplicationConfiguration{ + ClusterName: common.StringPtr(clusterName), + }) + + persistenceClusters = append(persistenceClusters, &persistence.ClusterReplicationConfig{ + ClusterName: clusterName, + }) + if clusterName != s.ClusterMetadata.GetCurrentClusterName() { + activeClusterName = clusterName + } + } + + // create a domain which is not currently active + s.MetadataManager.CreateDomain(&persistence.CreateDomainRequest{ + Name: domainName, + Status: persistence.DomainStatusRegistered, + Description: description, + OwnerEmail: email, + Config: &persistence.DomainConfig{ + Retention: retention, + EmitMetric: emitMetric, + }, + ReplicationConfig: &persistence.DomainReplicationConfig{ + ActiveClusterName: activeClusterName, + FailoverVersion: failoverVersion, + Clusters: persistenceClusters, + }, + }) + + // when doing the failover, the only thing can be updated is the active cluster + updateResp, err := s.engine.UpdateDomain(createContext(), &workflow.UpdateDomainRequest{ + Name: common.StringPtr(domainName), + UpdatedInfo: &workflow.UpdateDomainInfo{ + Description: common.StringPtr(description), + OwnerEmail: common.StringPtr(email), + }, + Configuration: &workflow.DomainConfiguration{ + WorkflowExecutionRetentionPeriodInDays: common.Int32Ptr(retention), + EmitMetric: common.BoolPtr(emitMetric), + }, + ReplicationConfiguration: &workflow.DomainReplicationConfiguration{ + ActiveClusterName: common.StringPtr(s.ClusterMetadata.GetCurrentClusterName()), + Clusters: clusters, + }, + }) + s.Nil(updateResp) + s.NotNil(err) + + updateResp, err = s.engine.UpdateDomain(createContext(), &workflow.UpdateDomainRequest{ + Name: common.StringPtr(domainName), + ReplicationConfiguration: &workflow.DomainReplicationConfiguration{ + ActiveClusterName: common.StringPtr(s.ClusterMetadata.GetCurrentClusterName()), + }, + }) + s.Nil(err) + s.Equal(domainName, updateResp.DomainInfo.GetName()) + s.Equal(workflow.DomainStatusRegistered, *updateResp.DomainInfo.Status) + s.Equal(description, updateResp.DomainInfo.GetDescription()) + s.Equal(email, updateResp.DomainInfo.GetOwnerEmail()) + s.Equal(retention, updateResp.Configuration.GetWorkflowExecutionRetentionPeriodInDays()) + s.Equal(emitMetric, updateResp.Configuration.GetEmitMetric()) + s.Equal(s.ClusterMetadata.GetCurrentClusterName(), updateResp.ReplicationConfiguration.GetActiveClusterName()) + s.Equal(clusters, updateResp.ReplicationConfiguration.Clusters) + + describeResp, err := s.engine.DescribeDomain(createContext(), &workflow.DescribeDomainRequest{ + Name: common.StringPtr(domainName), + }) + s.Nil(err) + s.Equal(domainName, describeResp.DomainInfo.GetName()) + s.Equal(workflow.DomainStatusRegistered, *describeResp.DomainInfo.Status) + s.Equal(description, describeResp.DomainInfo.GetDescription()) + s.Equal(email, describeResp.DomainInfo.GetOwnerEmail()) + s.Equal(retention, describeResp.Configuration.GetWorkflowExecutionRetentionPeriodInDays()) + s.Equal(emitMetric, describeResp.Configuration.GetEmitMetric()) + s.Equal(s.ClusterMetadata.GetCurrentClusterName(), describeResp.ReplicationConfiguration.GetActiveClusterName()) + s.Equal(clusters, describeResp.ReplicationConfiguration.Clusters) +} + func (s *integrationSuite) TestIntegrationStartWorkflowExecution() { id := "integration-start-workflow-test" wt := "integration-start-workflow-test-type" diff --git a/host/onebox.go b/host/onebox.go index dba2c572ecb..c04ed77705c 100644 --- a/host/onebox.go +++ b/host/onebox.go @@ -33,6 +33,7 @@ import ( "github.com/uber/cadence/.gen/go/cadence/workflowserviceclient" fecli "github.com/uber/cadence/client/frontend" "github.com/uber/cadence/common" + "github.com/uber/cadence/common/cluster" "github.com/uber/cadence/common/persistence" "github.com/uber/cadence/common/service" "github.com/uber/cadence/common/service/config" @@ -67,6 +68,7 @@ type ( numberOfHistoryShards int numberOfHistoryHosts int logger bark.Logger + clusterMetadata cluster.Metadata metadataMgr persistence.MetadataManager shardMgr persistence.ShardManager historyMgr persistence.HistoryManager @@ -85,7 +87,7 @@ type ( ) // NewCadence returns an instance that hosts full cadence in one process -func NewCadence(metadataMgr persistence.MetadataManager, shardMgr persistence.ShardManager, +func NewCadence(clusterMetadata cluster.Metadata, metadataMgr persistence.MetadataManager, shardMgr persistence.ShardManager, historyMgr persistence.HistoryManager, executionMgrFactory persistence.ExecutionManagerFactory, taskMgr persistence.TaskManager, visibilityMgr persistence.VisibilityManager, numberOfHistoryShards, numberOfHistoryHosts int, logger bark.Logger) Cadence { @@ -93,6 +95,7 @@ func NewCadence(metadataMgr persistence.MetadataManager, shardMgr persistence.Sh numberOfHistoryShards: numberOfHistoryShards, numberOfHistoryHosts: numberOfHistoryHosts, logger: logger, + clusterMetadata: clusterMetadata, metadataMgr: metadataMgr, visibilityMgr: visibilityMgr, shardMgr: shardMgr, @@ -189,6 +192,7 @@ func (c *cadenceImpl) startFrontend(logger bark.Logger, rpHosts []string, startW params.RPCFactory = newRPCFactoryImpl(common.FrontendServiceName, c.FrontendAddress(), logger) params.MetricScope = tally.NewTestScope(common.FrontendServiceName, make(map[string]string)) params.RingpopFactory = newRingpopFactory(common.FrontendServiceName, rpHosts) + params.ClusterMetadata = c.clusterMetadata params.CassandraConfig.NumHistoryShards = c.numberOfHistoryShards params.CassandraConfig.Hosts = "127.0.0.1" @@ -217,6 +221,7 @@ func (c *cadenceImpl) startHistory(logger bark.Logger, shardMgr persistence.Shar params.RPCFactory = newRPCFactoryImpl(common.HistoryServiceName, hostport, logger) params.MetricScope = tally.NewTestScope(common.HistoryServiceName, make(map[string]string)) params.RingpopFactory = newRingpopFactory(common.FrontendServiceName, rpHosts) + params.ClusterMetadata = c.clusterMetadata params.CassandraConfig.NumHistoryShards = c.numberOfHistoryShards service := service.New(params) historyConfig := history.NewConfig(c.numberOfHistoryShards) @@ -242,6 +247,7 @@ func (c *cadenceImpl) startMatching(logger bark.Logger, taskMgr persistence.Task params.RPCFactory = newRPCFactoryImpl(common.MatchingServiceName, c.MatchingServiceAddress(), logger) params.MetricScope = tally.NewTestScope(common.MatchingServiceName, make(map[string]string)) params.RingpopFactory = newRingpopFactory(common.FrontendServiceName, rpHosts) + params.ClusterMetadata = c.clusterMetadata params.CassandraConfig.NumHistoryShards = c.numberOfHistoryShards service := service.New(params) c.matchingHandler = matching.NewHandler(service, matching.NewConfig(), taskMgr) diff --git a/idl/github.com/uber/cadence/shared.thrift b/idl/github.com/uber/cadence/shared.thrift index d5ee4b02b56..d8f01d64949 100644 --- a/idl/github.com/uber/cadence/shared.thrift +++ b/idl/github.com/uber/cadence/shared.thrift @@ -734,12 +734,22 @@ struct UpdateDomainInfo { 20: optional string ownerEmail } +struct ClusterReplicationConfiguration { + 10: optional string clusterName +} + +struct DomainReplicationConfiguration { + 10: optional string activeClusterName + 20: optional list clusters +} + struct RegisterDomainRequest { 10: optional string name 20: optional string description 30: optional string ownerEmail 40: optional i32 workflowExecutionRetentionPeriodInDays 50: optional bool emitMetric + 60: optional list clusters } struct DescribeDomainRequest { @@ -749,17 +759,22 @@ struct DescribeDomainRequest { struct DescribeDomainResponse { 10: optional DomainInfo domainInfo 20: optional DomainConfiguration configuration + 30: optional DomainReplicationConfiguration replicationConfiguration + 40: optional i64 (js.type = "Long") failoverVersion } struct UpdateDomainRequest { 10: optional string name 20: optional UpdateDomainInfo updatedInfo 30: optional DomainConfiguration configuration + 40: optional DomainReplicationConfiguration replicationConfiguration } struct UpdateDomainResponse { 10: optional DomainInfo domainInfo 20: optional DomainConfiguration configuration + 30: optional DomainReplicationConfiguration replicationConfiguration + 40: optional i64 (js.type = "Long") failoverVersion } struct DeprecateDomainRequest { diff --git a/schema/cadence/schema.cql b/schema/cadence/schema.cql index fae7c3aa245..ce7dfb44d67 100644 --- a/schema/cadence/schema.cql +++ b/schema/cadence/schema.cql @@ -153,10 +153,20 @@ CREATE TYPE domain ( ); CREATE TYPE domain_config ( - retention int, + retention int, emit_metric boolean ); +CREATE TYPE cluster_replication_config ( + cluster_name text, +); + +CREATE TYPE domain_replication_config ( + active_cluster_name text, + failover_version bigint, + clusters list> +); + CREATE TYPE serialized_event_batch ( encoding_type text, version int, @@ -222,6 +232,7 @@ CREATE TABLE tasks ( 'class': 'org.apache.cassandra.db.compaction.LeveledCompactionStrategy' }; +-- this table is only used for storage of mapping of domain uuid to domain name CREATE TABLE domains ( id uuid, domain frozen, @@ -232,9 +243,11 @@ CREATE TABLE domains ( }; CREATE TABLE domains_by_name ( - name text, - domain frozen, - config frozen, + name text, + domain frozen, + config frozen, + replication_config frozen, -- indicating active cluster and standby cluster used for replication + version bigint, --indicate the version of the record, used for update PRIMARY KEY (name) ) WITH COMPACTION = { 'class': 'org.apache.cassandra.db.compaction.LeveledCompactionStrategy' diff --git a/schema/cadence/versioned/v0.4/add_replication_config.cql b/schema/cadence/versioned/v0.4/add_replication_config.cql new file mode 100644 index 00000000000..4c6e883d1c8 --- /dev/null +++ b/schema/cadence/versioned/v0.4/add_replication_config.cql @@ -0,0 +1,12 @@ +CREATE TYPE cluster_replication_config ( + cluster_name text, +); + +CREATE TYPE domain_replication_config ( + active_cluster_name text, + failover_version bigint, + clusters list> +); + +ALTER TABLE domains_by_name ADD replication_config frozen; +ALTER TABLE domains_by_name ADD version bigint; \ No newline at end of file diff --git a/schema/cadence/versioned/v0.4/manifest.json b/schema/cadence/versioned/v0.4/manifest.json index 2be817a9d85..3e9354eb35d 100644 --- a/schema/cadence/versioned/v0.4/manifest.json +++ b/schema/cadence/versioned/v0.4/manifest.json @@ -4,6 +4,7 @@ "Description": "add signal_decision to mutable state, add kind to taskList", "SchemaUpdateCqlFiles": [ "add_signal_decision.cql", - "add_tasklist_kind.cql" + "add_tasklist_kind.cql", + "add_replication_config.cql" ] } diff --git a/service/frontend/handler.go b/service/frontend/handler.go index 2f64daa678b..d131d2072c2 100644 --- a/service/frontend/handler.go +++ b/service/frontend/handler.go @@ -23,6 +23,7 @@ package frontend import ( "context" "encoding/json" + "fmt" "sync" "github.com/pborman/uuid" @@ -158,17 +159,50 @@ func (wh *WorkflowHandler) RegisterDomain(ctx context.Context, registerRequest * sw := wh.startRequestProfile(scope) defer sw.Stop() - if registerRequest.Name == nil || *registerRequest.Name == "" { + if len(registerRequest.GetName()) == 0 { return wh.error(errDomainNotSet, scope) } + // input validation on cluster names + clusterMetadata := wh.GetClusterMetadata() + activeClusterName := clusterMetadata.GetCurrentClusterName() + clusters := []*persistence.ClusterReplicationConfig{} + for _, cluster := range registerRequest.Clusters { + clusterName := cluster.GetClusterName() + if err := wh.validateClusterName(clusterName); err != nil { + return wh.error(err, scope) + } + clusters = append(clusters, &persistence.ClusterReplicationConfig{ClusterName: clusterName}) + } + clusters = persistence.GetOrUseDefaultClusters(activeClusterName, clusters) + + // validate active cluster is also specified in all clusters + activeClusterInClusters := false + for _, cluster := range clusters { + if cluster.ClusterName == activeClusterName { + activeClusterInClusters = true + break + } + } + if !activeClusterInClusters { + errMsg := "Active cluster is not contained in all clusters" + err := &gen.BadRequestError{Message: errMsg} + return wh.error(err, scope) + } + response, err := wh.metadataMgr.CreateDomain(&persistence.CreateDomainRequest{ Name: *registerRequest.Name, Status: persistence.DomainStatusRegistered, OwnerEmail: common.StringDefault(registerRequest.OwnerEmail), Description: common.StringDefault(registerRequest.Description), - Retention: common.Int32Default(registerRequest.WorkflowExecutionRetentionPeriodInDays), - EmitMetric: common.BoolDefault(registerRequest.EmitMetric), + Config: &persistence.DomainConfig{ + Retention: common.Int32Default(registerRequest.WorkflowExecutionRetentionPeriodInDays), + EmitMetric: common.BoolDefault(registerRequest.EmitMetric), + }, + ReplicationConfig: &persistence.DomainReplicationConfig{ + ActiveClusterName: activeClusterName, + Clusters: clusters, + }, }) if err != nil { @@ -200,8 +234,11 @@ func (wh *WorkflowHandler) DescribeDomain(ctx context.Context, return nil, wh.error(err, scope) } - response := &gen.DescribeDomainResponse{} - response.DomainInfo, response.Configuration = createDomainResponse(resp.Info, resp.Config) + response := &gen.DescribeDomainResponse{ + FailoverVersion: common.Int64Ptr(resp.ReplicationConfig.FailoverVersion), + } + response.DomainInfo, response.Configuration, response.ReplicationConfiguration = createDomainResponse( + resp.Info, resp.Config, resp.ReplicationConfig) return response, nil } @@ -228,37 +265,105 @@ func (wh *WorkflowHandler) UpdateDomain(ctx context.Context, info := getResponse.Info config := getResponse.Config - + replicationConfig := getResponse.ReplicationConfig + clusterMetadate := wh.GetClusterMetadata() + currentCluster := clusterMetadate.GetCurrentClusterName() + isCurrentClusterActive := currentCluster == replicationConfig.ActiveClusterName + + // whether active cluster is changed + activeClusterChanged := false + // whether anything other than active cluster is changed + configurationChanged := false if updateRequest.UpdatedInfo != nil { updatedInfo := updateRequest.UpdatedInfo if updatedInfo.Description != nil { - info.Description = *updatedInfo.Description + configurationChanged = true + info.Description = updatedInfo.GetDescription() } if updatedInfo.OwnerEmail != nil { - info.OwnerEmail = *updatedInfo.OwnerEmail + configurationChanged = true + info.OwnerEmail = updatedInfo.GetOwnerEmail() } } - if updateRequest.Configuration != nil { updatedConfig := updateRequest.Configuration if updatedConfig.EmitMetric != nil { - config.EmitMetric = *updatedConfig.EmitMetric + configurationChanged = true + config.EmitMetric = updatedConfig.GetEmitMetric() } if updatedConfig.WorkflowExecutionRetentionPeriodInDays != nil { - config.Retention = *updatedConfig.WorkflowExecutionRetentionPeriodInDays + configurationChanged = true + config.Retention = updatedConfig.GetWorkflowExecutionRetentionPeriodInDays() } } + if updateRequest.ReplicationConfiguration != nil { + updateReplicationConfig := updateRequest.ReplicationConfiguration + if len(updateReplicationConfig.Clusters) != 0 { + configurationChanged = true + clusters := []*persistence.ClusterReplicationConfig{} + for _, cluster := range updateReplicationConfig.Clusters { + clusterName := cluster.GetClusterName() + if err := wh.validateClusterName(clusterName); err != nil { + return nil, wh.error(err, scope) + } + clusters = append(clusters, &persistence.ClusterReplicationConfig{ClusterName: clusterName}) + } + replicationConfig.Clusters = clusters + } - err := wh.metadataMgr.UpdateDomain(&persistence.UpdateDomainRequest{ - Info: info, - Config: config, - }) - if err != nil { + if updateReplicationConfig.ActiveClusterName != nil { + activeClusterChanged = true + if updateReplicationConfig.GetActiveClusterName() != currentCluster { + errMsg := fmt.Sprintf("Can only set active cluster to current cluster: %s", currentCluster) + err := &gen.BadRequestError{Message: errMsg} + return nil, wh.error(err, scope) + } + replicationConfig.ActiveClusterName = currentCluster + replicationConfig.FailoverVersion = clusterMetadate.GetNextFailoverVersion(replicationConfig.FailoverVersion) + } + } + + if configurationChanged && activeClusterChanged { + errMsg := "Cannot set active cluster to current cluster when other paramaters are set" + err := &gen.BadRequestError{Message: errMsg} return nil, wh.error(err, scope) + } else if configurationChanged || activeClusterChanged { + if configurationChanged && !isCurrentClusterActive { + errMsg := "Cannot update domain when current cluster is not active" + err := &gen.BadRequestError{Message: errMsg} + return nil, wh.error(err, scope) + } + + // validate active cluster is also specified in all clusters + activeClusterInClusters := false + for _, cluster := range replicationConfig.Clusters { + if cluster.ClusterName == currentCluster { + activeClusterInClusters = true + break + } + } + if !activeClusterInClusters { + errMsg := "Active cluster is not contained in all clusters" + err := &gen.BadRequestError{Message: errMsg} + return nil, wh.error(err, scope) + } + + err := wh.metadataMgr.UpdateDomain(&persistence.UpdateDomainRequest{ + Info: info, + Config: config, + ReplicationConfig: replicationConfig, + Version: getResponse.Version, + }) + if err != nil { + return nil, wh.error(err, scope) + } } - response := &gen.UpdateDomainResponse{} - response.DomainInfo, response.Configuration = createDomainResponse(info, config) + response := &gen.UpdateDomainResponse{ + FailoverVersion: common.Int64Ptr(replicationConfig.FailoverVersion), + } + response.DomainInfo, response.Configuration, response.ReplicationConfiguration = createDomainResponse( + info, config, replicationConfig) return response, nil } @@ -283,14 +388,21 @@ func (wh *WorkflowHandler) DeprecateDomain(ctx context.Context, deprecateRequest return wh.error(err0, scope) } - info := getResponse.Info - info.Status = persistence.DomainStatusDeprecated - config := getResponse.Config + currentCluster := wh.GetClusterMetadata().GetCurrentClusterName() + if currentCluster != getResponse.ReplicationConfig.ActiveClusterName { + errMsg := "DeprecateDomain cannot depreate domain when active cluster is not current cluster" + err := &gen.BadRequestError{Message: errMsg} + return wh.error(err, scope) + } + getResponse.Info.Status = persistence.DomainStatusDeprecated err := wh.metadataMgr.UpdateDomain(&persistence.UpdateDomainRequest{ - Info: info, - Config: config, + Info: getResponse.Info, + Config: getResponse.Config, + ReplicationConfig: getResponse.ReplicationConfig, + Version: getResponse.Version, }) + if err != nil { return wh.error(errDomainNotSet, scope) } @@ -1638,20 +1750,35 @@ func getDomainStatus(info *persistence.DomainInfo) *gen.DomainStatus { return nil } -func createDomainResponse(info *persistence.DomainInfo, config *persistence.DomainConfig) (*gen.DomainInfo, - *gen.DomainConfiguration) { +func createDomainResponse(info *persistence.DomainInfo, config *persistence.DomainConfig, + replicationConfig *persistence.DomainReplicationConfig) (*gen.DomainInfo, + *gen.DomainConfiguration, *gen.DomainReplicationConfiguration) { + + infoResult := &gen.DomainInfo{ + Name: common.StringPtr(info.Name), + Status: getDomainStatus(info), + Description: common.StringPtr(info.Description), + OwnerEmail: common.StringPtr(info.OwnerEmail), + } + + configResult := &gen.DomainConfiguration{ + EmitMetric: common.BoolPtr(config.EmitMetric), + WorkflowExecutionRetentionPeriodInDays: common.Int32Ptr(config.Retention), + } - i := &gen.DomainInfo{} - i.Name = common.StringPtr(info.Name) - i.Status = getDomainStatus(info) - i.Description = common.StringPtr(info.Description) - i.OwnerEmail = common.StringPtr(info.OwnerEmail) + clusters := []*gen.ClusterReplicationConfiguration{} + for _, cluster := range replicationConfig.Clusters { + clusters = append(clusters, &gen.ClusterReplicationConfiguration{ + ClusterName: common.StringPtr(cluster.ClusterName), + }) + } - c := &gen.DomainConfiguration{} - c.EmitMetric = common.BoolPtr(config.EmitMetric) - c.WorkflowExecutionRetentionPeriodInDays = common.Int32Ptr(config.Retention) + replicationConfigResult := &gen.DomainReplicationConfiguration{ + ActiveClusterName: common.StringPtr(replicationConfig.ActiveClusterName), + Clusters: clusters, + } - return i, c + return infoResult, configResult, replicationConfigResult } func (wh *WorkflowHandler) createPollForDecisionTaskResponse(ctx context.Context, domainID string, @@ -1757,3 +1884,12 @@ func createServiceBusyError() *gen.ServiceBusyError { err.Message = "Too many outstanding requests to the cadence service" return err } + +func (wh *WorkflowHandler) validateClusterName(clusterName string) error { + clusterMetadata := wh.GetClusterMetadata() + if _, ok := clusterMetadata.GetAllClusterNames()[clusterName]; !ok { + errMsg := "Invalid cluster name: %s" + return &gen.BadRequestError{Message: fmt.Sprintf(errMsg, clusterName)} + } + return nil +} diff --git a/service/frontend/service.go b/service/frontend/service.go index 2c4957db4aa..05c1f256ec9 100644 --- a/service/frontend/service.go +++ b/service/frontend/service.go @@ -78,6 +78,7 @@ func (s *Service) Start() { p.CassandraConfig.Password, p.CassandraConfig.Datacenter, p.CassandraConfig.Keyspace, + p.ClusterMetadata.GetCurrentClusterName(), p.Logger) if err != nil { diff --git a/service/history/historyEngine.go b/service/history/historyEngine.go index f88292905fe..aee800c1a3b 100644 --- a/service/history/historyEngine.go +++ b/service/history/historyEngine.go @@ -803,11 +803,11 @@ Update_History_Loop: // First check if we need to use a different target domain to schedule activity if attributes.Domain != nil { // TODO: Error handling for ActivitySchedule failed when domain lookup fails - info, _, err := e.domainCache.GetDomain(*attributes.Domain) + domainEntry, err := e.domainCache.GetDomain(*attributes.Domain) if err != nil { return &workflow.InternalServiceError{Message: "Unable to schedule activity across domain."} } - targetDomainID = info.ID + targetDomainID = domainEntry.Info.ID } if err = validateActivityScheduleAttributes(attributes); err != nil { @@ -978,7 +978,7 @@ Update_History_Loop: break Process_Decision_Loop } - foreignInfo, _, err := e.domainCache.GetDomain(*attributes.Domain) + foreignDomainEntry, err := e.domainCache.GetDomain(*attributes.Domain) if err != nil { return &workflow.InternalServiceError{ Message: fmt.Sprintf("Unable to cancel workflow across domain: %v.", @@ -993,7 +993,7 @@ Update_History_Loop: } transferTasks = append(transferTasks, &persistence.CancelExecutionTask{ - TargetDomainID: foreignInfo.ID, + TargetDomainID: foreignDomainEntry.Info.ID, TargetWorkflowID: *attributes.WorkflowId, TargetRunID: common.StringDefault(attributes.RunId), ScheduleID: *wfCancelReqEvent.EventId, @@ -1010,7 +1010,7 @@ Update_History_Loop: break Process_Decision_Loop } - foreignInfo, _, err := e.domainCache.GetDomain(attributes.GetDomain()) + foreignDomainEntry, err := e.domainCache.GetDomain(attributes.GetDomain()) if err != nil { return &workflow.InternalServiceError{ Message: fmt.Sprintf("Unable to signal workflow across domain: %v.", @@ -1025,7 +1025,7 @@ Update_History_Loop: } transferTasks = append(transferTasks, &persistence.SignalExecutionTask{ - TargetDomainID: foreignInfo.ID, + TargetDomainID: foreignDomainEntry.Info.ID, TargetWorkflowID: attributes.Execution.GetWorkflowId(), TargetRunID: attributes.Execution.GetRunId(), InitiatedID: wfSignalReqEvent.GetEventId(), @@ -1077,11 +1077,11 @@ Update_History_Loop: // First check if we need to use a different target domain to schedule child execution if attributes.Domain == nil { // TODO: Error handling for DecisionType_StartChildWorkflowExecution failed when domain lookup fails - info, _, err := e.domainCache.GetDomain(*attributes.Domain) + domainEntry, err := e.domainCache.GetDomain(*attributes.Domain) if err != nil { return &workflow.InternalServiceError{Message: "Unable to schedule child execution across domain."} } - targetDomainID = info.ID + targetDomainID = domainEntry.Info.ID } requestID := uuid.New() @@ -1728,13 +1728,13 @@ func (e *historyEngineImpl) getDeleteWorkflowTasks( // Generate a timer task to cleanup history events for this workflow execution var retentionInDays int32 - _, domainConfig, err := e.domainCache.GetDomainByID(domainID) + domainEntry, err := e.domainCache.GetDomainByID(domainID) if err != nil { if _, ok := err.(*workflow.EntityNotExistsError); !ok { return nil, nil, err } } else { - retentionInDays = domainConfig.Retention + retentionInDays = domainEntry.Config.Retention } cleanupTask := tBuilder.createDeleteHistoryEventTimerTask(time.Duration(retentionInDays) * time.Hour * 24) diff --git a/service/history/service.go b/service/history/service.go index 3b31fa37d9e..eb4eb643d7f 100644 --- a/service/history/service.go +++ b/service/history/service.go @@ -173,6 +173,7 @@ func (s *Service) Start() { p.CassandraConfig.Password, p.CassandraConfig.Datacenter, p.CassandraConfig.Keyspace, + p.ClusterMetadata.GetCurrentClusterName(), p.Logger) if err != nil { diff --git a/service/history/transferQueueProcessor.go b/service/history/transferQueueProcessor.go index 9e0af7b2f66..6ff8122d1c0 100644 --- a/service/history/transferQueueProcessor.go +++ b/service/history/transferQueueProcessor.go @@ -479,7 +479,7 @@ func (t *transferQueueProcessorImpl) processCloseExecution(task *persistence.Tra // Record closing in visibility store retentionSeconds := int64(0) - _, domainConfig, err := t.domainCache.GetDomainByID(task.DomainID) + domainEntry, err := t.domainCache.GetDomainByID(task.DomainID) if err != nil { if _, ok := err.(*workflow.EntityNotExistsError); !ok { return err @@ -487,7 +487,7 @@ func (t *transferQueueProcessorImpl) processCloseExecution(task *persistence.Tra // it is possible that the domain got deleted. Use default retention. } else { // retention in domain config is in days, convert to seconds - retentionSeconds = int64(domainConfig.Retention) * 24 * 60 * 60 + retentionSeconds = int64(domainEntry.Config.Retention) * 24 * 60 * 60 } return t.visibilityManager.RecordWorkflowExecutionClosed(&persistence.RecordWorkflowExecutionClosedRequest{ diff --git a/service/history/workflowExecutionContext.go b/service/history/workflowExecutionContext.go index b33d3832945..0413e6b735a 100644 --- a/service/history/workflowExecutionContext.go +++ b/service/history/workflowExecutionContext.go @@ -168,12 +168,12 @@ func (c *workflowExecutionContext) updateWorkflowExecution(transferTasks []persi // Also transactionally delete workflow execution representing // current run for the execution using cassandra TTL finishExecution = true - _, domainConfig, err := c.shard.GetDomainCache().GetDomainByID(c.msBuilder.executionInfo.DomainID) + domainEntry, err := c.shard.GetDomainCache().GetDomainByID(c.msBuilder.executionInfo.DomainID) if err != nil { return err } // NOTE: domain retention is in days, so we need to do a conversion - finishExecutionTTL = domainConfig.Retention * secondsInDay + finishExecutionTTL = domainEntry.Config.Retention * secondsInDay } if err1 := c.updateWorkflowExecutionWithRetry(&persistence.UpdateWorkflowExecutionRequest{ ExecutionInfo: c.msBuilder.executionInfo,