diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 997b568b6..94ab1c3d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,3 +24,5 @@ jobs: git diff exit 1 fi + - name: Check for OpenAPI path conflicts + run: go run ./cmd/check-path-conflicts/main.go openapi/openapiv2.json diff --git a/cmd/check-path-conflicts/main.go b/cmd/check-path-conflicts/main.go new file mode 100644 index 000000000..9a5eb346a --- /dev/null +++ b/cmd/check-path-conflicts/main.go @@ -0,0 +1,137 @@ +// check-path-conflicts reads an OpenAPI v2 JSON file and detects HTTP path +// conflicts where a literal path segment and a parameterized segment overlap at +// the same position (e.g. /items/pause vs /items/{id}). +package main + +import ( + "encoding/json" + "fmt" + "os" + "sort" + "strings" +) + +type openAPISpec struct { + Paths map[string]map[string]json.RawMessage `json:"paths"` +} + +// httpMethods are the valid HTTP method keys in an OpenAPI path item. +var httpMethods = map[string]bool{ + "get": true, "put": true, "post": true, "delete": true, + "options": true, "head": true, "patch": true, +} + +// segment represents one piece of a URL path. +type segment struct { + value string + param bool // true when the segment is a path parameter like {id} +} + +func parseSegments(path string) []segment { + parts := strings.Split(strings.Trim(path, "/"), "/") + segs := make([]segment, len(parts)) + for i, p := range parts { + segs[i] = segment{ + value: p, + param: strings.HasPrefix(p, "{") && strings.HasSuffix(p, "}"), + } + } + return segs +} + +// Two paths conflict when they have the same number of segments and at every +// position, they either match literally or at least one of them is a parameter, +// AND there is at least one position where one path has a literal and the other +// has a parameter (otherwise they are the same path or differ only in parameter +// names, which is a different issue). +func conflicts(a, b []segment) bool { + if len(a) != len(b) { + return false + } + hasParamLiteralMismatch := false + for i := range a { + aParam := a[i].param + bParam := b[i].param + if !aParam && !bParam { + // Both literals — must match exactly. + if a[i].value != b[i].value { + return false + } + } else if aParam != bParam { + // One is a param, the other is a literal — potential conflict. + hasParamLiteralMismatch = true + } + // Both params — always compatible at this position, continue. + } + return hasParamLiteralMismatch +} + +func main() { + if len(os.Args) < 2 { + fmt.Fprintf(os.Stderr, "usage: %s \n", os.Args[0]) + os.Exit(2) + } + + data, err := os.ReadFile(os.Args[1]) + if err != nil { + fmt.Fprintf(os.Stderr, "error reading file: %v\n", err) + os.Exit(2) + } + + var spec openAPISpec + if err := json.Unmarshal(data, &spec); err != nil { + fmt.Fprintf(os.Stderr, "error parsing JSON: %v\n", err) + os.Exit(2) + } + + type parsedPath struct { + raw string + methods map[string]bool + segments []segment + } + + var parsed []parsedPath + for p, item := range spec.Paths { + methods := make(map[string]bool) + for key := range item { + if httpMethods[strings.ToLower(key)] { + methods[strings.ToLower(key)] = true + } + } + parsed = append(parsed, parsedPath{raw: p, methods: methods, segments: parseSegments(p)}) + } + sort.Slice(parsed, func(i, j int) bool { return parsed[i].raw < parsed[j].raw }) + + var found []string + for i := 0; i < len(parsed); i++ { + for j := i + 1; j < len(parsed); j++ { + if !conflicts(parsed[i].segments, parsed[j].segments) { + continue + } + // Find overlapping HTTP methods. + var shared []string + for m := range parsed[i].methods { + if parsed[j].methods[m] { + shared = append(shared, strings.ToUpper(m)) + } + } + if len(shared) == 0 { + continue + } + sort.Strings(shared) + found = append(found, fmt.Sprintf(" %s\n %s\n methods: %s", + parsed[i].raw, parsed[j].raw, strings.Join(shared, ", "))) + } + } + + if len(found) > 0 { + fmt.Fprintf(os.Stderr, "found %d path conflict(s):\n\n", len(found)) + for _, f := range found { + fmt.Fprintln(os.Stderr, f) + fmt.Fprintln(os.Stderr) + } + os.Exit(1) + } + + fmt.Println("no path conflicts found") +} diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 3e62531ad..85e36caa2 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -3142,46 +3142,6 @@ ] } }, - "/api/v1/namespaces/{namespace}/workflows/execute-multi-operation": { - "post": { - "summary": "ExecuteMultiOperation executes multiple operations within a single workflow.", - "description": "Operations are started atomically, meaning if *any* operation fails to be started, none are,\nand the request fails. Upon start, the API returns only when *all* operations have a response.\n\nUpon failure, it returns `MultiOperationExecutionFailure` where the status code\nequals the status code of the *first* operation that failed to be started.\n\nNOTE: Experimental API.", - "operationId": "ExecuteMultiOperation2", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ExecuteMultiOperationResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "namespace", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/WorkflowServiceExecuteMultiOperationBody" - } - } - ], - "tags": [ - "WorkflowService" - ] - } - }, "/api/v1/namespaces/{namespace}/workflows/{execution.workflowId}": { "get": { "summary": "DescribeWorkflowExecution returns information about the specified workflow execution.", @@ -7682,46 +7642,6 @@ ] } }, - "/namespaces/{namespace}/workflows/execute-multi-operation": { - "post": { - "summary": "ExecuteMultiOperation executes multiple operations within a single workflow.", - "description": "Operations are started atomically, meaning if *any* operation fails to be started, none are,\nand the request fails. Upon start, the API returns only when *all* operations have a response.\n\nUpon failure, it returns `MultiOperationExecutionFailure` where the status code\nequals the status code of the *first* operation that failed to be started.\n\nNOTE: Experimental API.", - "operationId": "ExecuteMultiOperation", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ExecuteMultiOperationResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "namespace", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/WorkflowServiceExecuteMultiOperationBody" - } - } - ], - "tags": [ - "WorkflowService" - ] - } - }, "/namespaces/{namespace}/workflows/{execution.workflowId}": { "get": { "summary": "DescribeWorkflowExecution returns information about the specified workflow execution.", @@ -8840,30 +8760,6 @@ }, "description": "Target a worker polling on a Nexus task queue in a specific namespace." }, - "ExecuteMultiOperationRequestOperation": { - "type": "object", - "properties": { - "startWorkflow": { - "$ref": "#/definitions/v1StartWorkflowExecutionRequest", - "title": "Additional restrictions:\n- setting `cron_schedule` is invalid\n- setting `request_eager_execution` is invalid\n- setting `workflow_start_delay` is invalid" - }, - "updateWorkflow": { - "$ref": "#/definitions/v1UpdateWorkflowExecutionRequest", - "title": "Additional restrictions:\n- setting `first_execution_run_id` is invalid\n- setting `workflow_execution.run_id` is invalid" - } - } - }, - "ExecuteMultiOperationResponseResponse": { - "type": "object", - "properties": { - "startWorkflow": { - "$ref": "#/definitions/v1StartWorkflowExecutionResponse" - }, - "updateWorkflow": { - "$ref": "#/definitions/v1UpdateWorkflowExecutionResponse" - } - } - }, "LinkBatchJob": { "type": "object", "properties": { @@ -9273,19 +9169,6 @@ } } }, - "WorkflowServiceExecuteMultiOperationBody": { - "type": "object", - "properties": { - "operations": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/ExecuteMultiOperationRequestOperation" - }, - "description": "List of operations to execute within a single workflow.\n\nPreconditions:\n- The list of operations must not be empty.\n- The workflow ids must match across operations.\n- The only valid list of operations at this time is [StartWorkflow, UpdateWorkflow], in this order.\n\nNote that additional operation-specific restrictions have to be considered." - } - } - }, "WorkflowServiceFetchWorkerConfigBody": { "type": "object", "properties": { @@ -12693,19 +12576,6 @@ "description": "- EVENT_TYPE_UNSPECIFIED: Place holder and should never appear in a Workflow execution history\n - EVENT_TYPE_WORKFLOW_EXECUTION_STARTED: Workflow execution has been triggered/started\nIt contains Workflow execution inputs, as well as Workflow timeout configurations\n - EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED: Workflow execution has successfully completed and contains Workflow execution results\n - EVENT_TYPE_WORKFLOW_EXECUTION_FAILED: Workflow execution has unsuccessfully completed and contains the Workflow execution error\n - EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT: Workflow execution has timed out by the Temporal Server\nUsually due to the Workflow having not been completed within timeout settings\n - EVENT_TYPE_WORKFLOW_TASK_SCHEDULED: Workflow Task has been scheduled and the SDK client should now be able to process any new history events\n - EVENT_TYPE_WORKFLOW_TASK_STARTED: Workflow Task has started and the SDK client has picked up the Workflow Task and is processing new history events\n - EVENT_TYPE_WORKFLOW_TASK_COMPLETED: Workflow Task has completed\nThe SDK client picked up the Workflow Task and processed new history events\nSDK client may or may not ask the Temporal Server to do additional work, such as:\nEVENT_TYPE_ACTIVITY_TASK_SCHEDULED\nEVENT_TYPE_TIMER_STARTED\nEVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES\nEVENT_TYPE_MARKER_RECORDED\nEVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED\nEVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED\nEVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED\nEVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED\nEVENT_TYPE_WORKFLOW_EXECUTION_FAILED\nEVENT_TYPE_WORKFLOW_EXECUTION_CANCELED\nEVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW\n - EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT: Workflow Task encountered a timeout\nEither an SDK client with a local cache was not available at the time, or it took too long for the SDK client to process the task\n - EVENT_TYPE_WORKFLOW_TASK_FAILED: Workflow Task encountered a failure\nUsually this means that the Workflow was non-deterministic\nHowever, the Workflow reset functionality also uses this event\n - EVENT_TYPE_ACTIVITY_TASK_SCHEDULED: Activity Task was scheduled\nThe SDK client should pick up this activity task and execute\nThis event type contains activity inputs, as well as activity timeout configurations\n - EVENT_TYPE_ACTIVITY_TASK_STARTED: Activity Task has started executing\nThe SDK client has picked up the Activity Task and is processing the Activity invocation\n - EVENT_TYPE_ACTIVITY_TASK_COMPLETED: Activity Task has finished successfully\nThe SDK client has picked up and successfully completed the Activity Task\nThis event type contains Activity execution results\n - EVENT_TYPE_ACTIVITY_TASK_FAILED: Activity Task has finished unsuccessfully\nThe SDK picked up the Activity Task but unsuccessfully completed it\nThis event type contains Activity execution errors\n - EVENT_TYPE_ACTIVITY_TASK_TIMED_OUT: Activity has timed out according to the Temporal Server\nActivity did not complete within the timeout settings\n - EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED: A request to cancel the Activity has occurred\nThe SDK client will be able to confirm cancellation of an Activity during an Activity heartbeat\n - EVENT_TYPE_ACTIVITY_TASK_CANCELED: Activity has been cancelled\n - EVENT_TYPE_TIMER_STARTED: A timer has started\n - EVENT_TYPE_TIMER_FIRED: A timer has fired\n - EVENT_TYPE_TIMER_CANCELED: A time has been cancelled\n - EVENT_TYPE_WORKFLOW_EXECUTION_CANCEL_REQUESTED: A request has been made to cancel the Workflow execution\n - EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED: SDK client has confirmed the cancellation request and the Workflow execution has been cancelled\n - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED: Workflow has requested that the Temporal Server try to cancel another Workflow\n - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_FAILED: Temporal Server could not cancel the targeted Workflow\nThis is usually because the target Workflow could not be found\n - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_CANCEL_REQUESTED: Temporal Server has successfully requested the cancellation of the target Workflow\n - EVENT_TYPE_MARKER_RECORDED: A marker has been recorded.\nThis event type is transparent to the Temporal Server\nThe Server will only store it and will not try to understand it.\n - EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED: Workflow has received a Signal event\nThe event type contains the Signal name, as well as a Signal payload\n - EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED: Workflow execution has been forcefully terminated\nThis is usually because the terminate Workflow API was called\n - EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW: Workflow has successfully completed and a new Workflow has been started within the same transaction\nContains last Workflow execution results as well as new Workflow execution inputs\n - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED: Temporal Server will try to start a child Workflow\n - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_FAILED: Child Workflow execution cannot be started/triggered\nUsually due to a child Workflow ID collision\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_STARTED: Child Workflow execution has successfully started/triggered\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_COMPLETED: Child Workflow execution has successfully completed\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_FAILED: Child Workflow execution has unsuccessfully completed\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED: Child Workflow execution has been cancelled\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TIMED_OUT: Child Workflow execution has timed out by the Temporal Server\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TERMINATED: Child Workflow execution has been terminated\n - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED: Temporal Server will try to Signal the targeted Workflow\nContains the Signal name, as well as a Signal payload\n - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED: Temporal Server cannot Signal the targeted Workflow\nUsually because the Workflow could not be found\n - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_SIGNALED: Temporal Server has successfully Signaled the targeted Workflow\n - EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES: Workflow search attributes should be updated and synchronized with the visibility store\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ADMITTED: An update was admitted. Note that not all admitted updates result in this\nevent. See UpdateAdmittedEventOrigin for situations in which this event\nis created.\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ACCEPTED: An update was accepted (i.e. passed validation, perhaps because no validator was defined)\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_REJECTED: This event is never written to history.\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_COMPLETED: An update completed\n - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED_EXTERNALLY: Some property or properties of the workflow as a whole have changed by non-workflow code.\nThe distinction of external vs. command-based modification is important so the SDK can\nmaintain determinism when using the command-based approach.\n - EVENT_TYPE_ACTIVITY_PROPERTIES_MODIFIED_EXTERNALLY: Some property or properties of an already-scheduled activity have changed by non-workflow code.\nThe distinction of external vs. command-based modification is important so the SDK can\nmaintain determinism when using the command-based approach.\n - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED: Workflow properties modified by user workflow code\n - EVENT_TYPE_NEXUS_OPERATION_SCHEDULED: A Nexus operation was scheduled using a ScheduleNexusOperation command.\n - EVENT_TYPE_NEXUS_OPERATION_STARTED: An asynchronous Nexus operation was started by a Nexus handler.\n - EVENT_TYPE_NEXUS_OPERATION_COMPLETED: A Nexus operation completed successfully.\n - EVENT_TYPE_NEXUS_OPERATION_FAILED: A Nexus operation failed.\n - EVENT_TYPE_NEXUS_OPERATION_CANCELED: A Nexus operation completed as canceled.\n - EVENT_TYPE_NEXUS_OPERATION_TIMED_OUT: A Nexus operation timed out.\n - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUESTED: A Nexus operation was requested to be canceled using a RequestCancelNexusOperation command.\n - EVENT_TYPE_WORKFLOW_EXECUTION_OPTIONS_UPDATED: Workflow execution options updated by user.\n - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_COMPLETED: A cancellation request for a Nexus operation was successfully delivered to the Nexus handler.\n - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_FAILED: A cancellation request for a Nexus operation resulted in an error.\n - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED: An event that indicates that the workflow execution has been paused.\n - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED: An event that indicates that the previously paused workflow execution has been unpaused.", "title": "Whenever this list of events is changed do change the function shouldBufferEvent in mutableStateBuilder.go to make sure to do the correct event ordering" }, - "v1ExecuteMultiOperationResponse": { - "type": "object", - "properties": { - "responses": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/ExecuteMultiOperationResponseResponse" - } - } - }, - "description": "IMPORTANT: For [StartWorkflow, UpdateWorkflow] combination (\"Update-with-Start\") when both\n 1. the workflow update for the requested update ID has already completed, and\n 2. the workflow for the requested workflow ID has already been closed,\nthen you'll receive\n - an update response containing the update's outcome, and\n - a start response with a `status` field that reflects the workflow's current state." - }, "v1ExternalWorkflowExecutionCancelRequestedEventAttributes": { "type": "object", "properties": { @@ -15962,123 +15832,6 @@ } } }, - "v1StartWorkflowExecutionRequest": { - "type": "object", - "properties": { - "namespace": { - "type": "string" - }, - "workflowId": { - "type": "string" - }, - "workflowType": { - "$ref": "#/definitions/v1WorkflowType" - }, - "taskQueue": { - "$ref": "#/definitions/v1TaskQueue" - }, - "input": { - "$ref": "#/definitions/v1Payloads", - "description": "Serialized arguments to the workflow. These are passed as arguments to the workflow function." - }, - "workflowExecutionTimeout": { - "type": "string", - "description": "Total workflow execution timeout including retries and continue as new." - }, - "workflowRunTimeout": { - "type": "string", - "description": "Timeout of a single workflow run." - }, - "workflowTaskTimeout": { - "type": "string", - "description": "Timeout of a single workflow task." - }, - "identity": { - "type": "string", - "title": "The identity of the client who initiated this request" - }, - "requestId": { - "type": "string", - "description": "A unique identifier for this start request. Typically UUIDv4." - }, - "workflowIdReusePolicy": { - "$ref": "#/definitions/v1WorkflowIdReusePolicy", - "description": "Defines whether to allow re-using the workflow id from a previously *closed* workflow.\nThe default policy is WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE.\n\nSee `workflow_id_conflict_policy` for handling a workflow id duplication with a *running* workflow." - }, - "workflowIdConflictPolicy": { - "$ref": "#/definitions/v1WorkflowIdConflictPolicy", - "description": "Defines how to resolve a workflow id conflict with a *running* workflow.\nThe default policy is WORKFLOW_ID_CONFLICT_POLICY_FAIL.\n\nSee `workflow_id_reuse_policy` for handling a workflow id duplication with a *closed* workflow." - }, - "retryPolicy": { - "$ref": "#/definitions/v1RetryPolicy", - "description": "The retry policy for the workflow. Will never exceed `workflow_execution_timeout`." - }, - "cronSchedule": { - "type": "string", - "title": "See https://docs.temporal.io/docs/content/what-is-a-temporal-cron-job/" - }, - "memo": { - "$ref": "#/definitions/v1Memo" - }, - "searchAttributes": { - "$ref": "#/definitions/v1SearchAttributes" - }, - "header": { - "$ref": "#/definitions/v1Header" - }, - "requestEagerExecution": { - "type": "boolean", - "description": "Request to get the first workflow task inline in the response bypassing matching service and worker polling.\nIf set to `true` the caller is expected to have a worker available and capable of processing the task.\nThe returned task will be marked as started and is expected to be completed by the specified\n`workflow_task_timeout`." - }, - "continuedFailure": { - "$ref": "#/definitions/v1Failure", - "description": "These values will be available as ContinuedFailure and LastCompletionResult in the\nWorkflowExecutionStarted event and through SDKs. The are currently only used by the\nserver itself (for the schedules feature) and are not intended to be exposed in\nStartWorkflowExecution." - }, - "lastCompletionResult": { - "$ref": "#/definitions/v1Payloads" - }, - "workflowStartDelay": { - "type": "string", - "description": "Time to wait before dispatching the first workflow task. Cannot be used with `cron_schedule`.\nIf the workflow gets a signal before the delay, a workflow task will be dispatched and the rest\nof the delay will be ignored." - }, - "completionCallbacks": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Callback" - }, - "description": "Callbacks to be called by the server when this workflow reaches a terminal state.\nIf the workflow continues-as-new, these callbacks will be carried over to the new execution.\nCallback addresses must be whitelisted in the server's dynamic configuration." - }, - "userMetadata": { - "$ref": "#/definitions/v1UserMetadata", - "description": "Metadata on the workflow if it is started. This is carried over to the WorkflowExecutionInfo\nfor use by user interfaces to display the fixed as-of-start summary and details of the\nworkflow." - }, - "links": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Link" - }, - "description": "Links to be associated with the workflow." - }, - "versioningOverride": { - "$ref": "#/definitions/v1VersioningOverride", - "description": "If set, takes precedence over the Versioning Behavior sent by the SDK on Workflow Task completion.\nTo unset the override after the workflow is running, use UpdateWorkflowExecutionOptions." - }, - "onConflictOptions": { - "$ref": "#/definitions/v1OnConflictOptions", - "description": "Defines actions to be done to the existing running workflow when the conflict policy\nWORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING is used. If not set (ie., nil value) or set to a\nempty object (ie., all options with default value), it won't do anything to the existing\nrunning workflow. If set, it will add a history event to the running workflow." - }, - "priority": { - "$ref": "#/definitions/v1Priority", - "title": "Priority metadata" - }, - "eagerWorkerDeploymentOptions": { - "$ref": "#/definitions/v1WorkerDeploymentOptions", - "description": "Deployment Options of the worker who will process the eager task. Passed when `request_eager_execution=true`." - } - } - }, "v1StartWorkflowExecutionResponse": { "type": "object", "properties": { @@ -16709,31 +16462,6 @@ } } }, - "v1UpdateWorkflowExecutionRequest": { - "type": "object", - "properties": { - "namespace": { - "type": "string", - "description": "The namespace name of the target Workflow." - }, - "workflowExecution": { - "$ref": "#/definitions/v1WorkflowExecution", - "description": "The target Workflow Id and (optionally) a specific Run Id thereof." - }, - "firstExecutionRunId": { - "type": "string", - "description": "If set, this call will error if the most recent (if no Run Id is set on\n`workflow_execution`), or specified (if it is) Workflow Execution is not\npart of the same execution chain as this Id." - }, - "waitPolicy": { - "$ref": "#/definitions/v1WaitPolicy", - "description": "Specifies client's intent to wait for Update results.\nNOTE: This field works together with API call timeout which is limited by\nserver timeout (maximum wait time). If server timeout is expired before\nuser specified timeout, API call returns even if specified stage is not reached.\nActual reached stage will be included in the response." - }, - "request": { - "$ref": "#/definitions/v1Request", - "description": "The request information that will be delivered all the way down to the\nWorkflow Execution." - } - } - }, "v1UpdateWorkflowExecutionResponse": { "type": "object", "properties": { diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 9fea4880f..058b71005 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -2817,46 +2817,6 @@ paths: application/json: schema: $ref: '#/components/schemas/Status' - /api/v1/namespaces/{namespace}/workflows/execute-multi-operation: - post: - tags: - - WorkflowService - description: |- - ExecuteMultiOperation executes multiple operations within a single workflow. - - Operations are started atomically, meaning if *any* operation fails to be started, none are, - and the request fails. Upon start, the API returns only when *all* operations have a response. - - Upon failure, it returns `MultiOperationExecutionFailure` where the status code - equals the status code of the *first* operation that failed to be started. - - NOTE: Experimental API. - operationId: ExecuteMultiOperation - parameters: - - name: namespace - in: path - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/ExecuteMultiOperationRequest' - required: true - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/ExecuteMultiOperationResponse' - default: - description: Default error response - content: - application/json: - schema: - $ref: '#/components/schemas/Status' /api/v1/namespaces/{namespace}/workflows/{execution.workflow_id}: get: tags: @@ -6892,46 +6852,6 @@ paths: application/json: schema: $ref: '#/components/schemas/Status' - /namespaces/{namespace}/workflows/execute-multi-operation: - post: - tags: - - WorkflowService - description: |- - ExecuteMultiOperation executes multiple operations within a single workflow. - - Operations are started atomically, meaning if *any* operation fails to be started, none are, - and the request fails. Upon start, the API returns only when *all* operations have a response. - - Upon failure, it returns `MultiOperationExecutionFailure` where the status code - equals the status code of the *first* operation that failed to be started. - - NOTE: Experimental API. - operationId: ExecuteMultiOperation - parameters: - - name: namespace - in: path - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/ExecuteMultiOperationRequest' - required: true - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/ExecuteMultiOperationResponse' - default: - description: Default error response - content: - application/json: - schema: - $ref: '#/components/schemas/Status' /namespaces/{namespace}/workflows/{execution.workflow_id}: get: tags: @@ -9812,63 +9732,6 @@ components: type: string description: Nexus task queue to route requests to. description: Target a worker polling on a Nexus task queue in a specific namespace. - ExecuteMultiOperationRequest: - type: object - properties: - namespace: - type: string - operations: - type: array - items: - $ref: '#/components/schemas/ExecuteMultiOperationRequest_Operation' - description: |- - List of operations to execute within a single workflow. - - Preconditions: - - The list of operations must not be empty. - - The workflow ids must match across operations. - - The only valid list of operations at this time is [StartWorkflow, UpdateWorkflow], in this order. - - Note that additional operation-specific restrictions have to be considered. - ExecuteMultiOperationRequest_Operation: - type: object - properties: - startWorkflow: - allOf: - - $ref: '#/components/schemas/StartWorkflowExecutionRequest' - description: |- - Additional restrictions: - - setting `cron_schedule` is invalid - - setting `request_eager_execution` is invalid - - setting `workflow_start_delay` is invalid - updateWorkflow: - allOf: - - $ref: '#/components/schemas/UpdateWorkflowExecutionRequest' - description: |- - Additional restrictions: - - setting `first_execution_run_id` is invalid - - setting `workflow_execution.run_id` is invalid - ExecuteMultiOperationResponse: - type: object - properties: - responses: - type: array - items: - $ref: '#/components/schemas/ExecuteMultiOperationResponse_Response' - description: |- - IMPORTANT: For [StartWorkflow, UpdateWorkflow] combination ("Update-with-Start") when both - 1. the workflow update for the requested update ID has already completed, and - 2. the workflow for the requested workflow ID has already been closed, - then you'll receive - - an update response containing the update's outcome, and - - a start response with a `status` field that reflects the workflow's current state. - ExecuteMultiOperationResponse_Response: - type: object - properties: - startWorkflow: - $ref: '#/components/schemas/StartWorkflowExecutionResponse' - updateWorkflow: - $ref: '#/components/schemas/UpdateWorkflowExecutionResponse' ExternalWorkflowExecutionCancelRequestedEventAttributes: type: object properties: diff --git a/temporal/api/workflowservice/v1/service.proto b/temporal/api/workflowservice/v1/service.proto index 6f1b2d517..c67a2717b 100644 --- a/temporal/api/workflowservice/v1/service.proto +++ b/temporal/api/workflowservice/v1/service.proto @@ -111,16 +111,9 @@ service WorkflowService { // Upon failure, it returns `MultiOperationExecutionFailure` where the status code // equals the status code of the *first* operation that failed to be started. // - // NOTE: Experimental API. + // (-- api-linter: core::0127::http-annotation=disabled + // aip.dev/not-precedent: To be exposed over HTTP in the future. --) rpc ExecuteMultiOperation (ExecuteMultiOperationRequest) returns (ExecuteMultiOperationResponse) { - option (google.api.http) = { - post: "/namespaces/{namespace}/workflows/execute-multi-operation" - body: "*" - additional_bindings { - post: "/api/v1/namespaces/{namespace}/workflows/execute-multi-operation" - body: "*" - } - }; } // GetWorkflowExecutionHistory returns the history of specified workflow execution. Fails with