From 2684ccb1207a983f80c7d3c10d83167488b4d895 Mon Sep 17 00:00:00 2001 From: Sam Gunner Date: Fri, 30 Oct 2026 10:58:39 +0000 Subject: [PATCH 1/2] feat: add optional taskQueue to run.workflow Signed-off-by: Sam Gunner --- definitions.go | 7 +++ definitions_test.go | 23 +++++++++ schema.json | 6 +++ schema.yaml | 7 +++ schema_test.go | 111 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 154 insertions(+) diff --git a/definitions.go b/definitions.go index 2186942..51f6c73 100644 --- a/definitions.go +++ b/definitions.go @@ -1185,6 +1185,13 @@ var runTaskDefinition = &jsonschema.Schema{ "The value should be validated against the target workflow's input schema, if specified.", AdditionalProperties: trueSchema(), }, + propTaskQueue: { + Type: typeString, + Title: "SubflowTaskQueue", + MinLength: utils.Ptr(1), + Description: "The Temporal task queue to start the child workflow on. " + + "If not set, the child workflow runs on the parent workflow's task queue.", + }, propType: { Type: typeString, Title: "SubflowType", diff --git a/definitions_test.go b/definitions_test.go index 181d306..1f01703 100644 --- a/definitions_test.go +++ b/definitions_test.go @@ -265,6 +265,29 @@ func TestRunTaskDefinitionVariants(t *testing.T) { } } +func TestRunWorkflowTaskQueueProperty(t *testing.T) { + var workflow *jsonschema.Schema + for _, variant := range runTaskDefinition.AllOf[1].Properties["run"].OneOf { + if variant.Title != "RunWorkflow" { + continue + } + workflow = variant.Properties["workflow"] + break + } + + require.NotNil(t, workflow, "RunWorkflow should define a workflow property") + require.Contains(t, workflow.Properties, propTaskQueue) + taskQueue := workflow.Properties[propTaskQueue] + require.NotNil(t, taskQueue) + + assert.Equal(t, typeString, taskQueue.Type) + assert.Equal(t, "SubflowTaskQueue", taskQueue.Title) + require.NotNil(t, taskQueue.MinLength) + assert.Equal(t, 1, *taskQueue.MinLength) + assert.Empty(t, taskQueue.Pattern) + assert.Equal(t, []string{propType}, workflow.Required) +} + // TestSchemaDefinitionInlineOnly verifies that schemaDefinition supports only // the inline document form and not the external resource form. func TestSchemaDefinitionInlineOnly(t *testing.T) { diff --git a/schema.json b/schema.json index 24a1879..4c4fb63 100644 --- a/schema.json +++ b/schema.json @@ -1343,6 +1343,12 @@ "description": "The data, if any, to pass as input to the workflow to execute. The value should be validated against the target workflow's input schema, if specified.", "additionalProperties": true }, + "taskQueue": { + "type": "string", + "title": "SubflowTaskQueue", + "description": "The Temporal task queue to start the child workflow on. If not set, the child workflow runs on the parent workflow's task queue.", + "minLength": 1 + }, "type": { "type": "string", "title": "SubflowType", diff --git a/schema.yaml b/schema.yaml index 22414d6..4778fff 100644 --- a/schema.yaml +++ b/schema.yaml @@ -903,6 +903,13 @@ $defs: workflow's input schema, if specified. title: SubflowInput type: object + taskQueue: + description: The Temporal task queue to start the child workflow + on. If not set, the child workflow runs on the parent workflow's + task queue. + minLength: 1 + title: SubflowTaskQueue + type: string type: description: The workflow type to run. title: SubflowType diff --git a/schema_test.go b/schema_test.go index b21b7a4..9d5e1c8 100644 --- a/schema_test.go +++ b/schema_test.go @@ -17,6 +17,7 @@ package schema import ( + "strings" "testing" "github.com/stretchr/testify/assert" @@ -49,6 +50,20 @@ func minimalWorkflow() map[string]any { } } +func runWorkflowDoc(workflow map[string]any) map[string]any { + doc := minimalWorkflow() + doc[propDo] = []any{ + map[string]any{ + "callChild": map[string]any{ + "run": map[string]any{ + "workflow": workflow, + }, + }, + }, + } + return doc +} + // TestSchema_DocumentFields verifies that the document schema accepts the // Zigflow-aligned field names and rejects the old Serverless Workflow names. func TestSchema_DocumentFields(t *testing.T) { @@ -139,3 +154,99 @@ func TestSchema_RejectsUnknownTopLevelProperties(t *testing.T) { assert.NoError(t, err, "document with only known top-level properties should pass validation") }) } + +func TestSchema_RunWorkflowTaskQueue(t *testing.T) { + resolved := resolvedTestSchema(t) + tests := []struct { + name string + workflow map[string]any + awaitFalse bool + wantError bool + }{ + { + name: "without taskQueue is accepted", + workflow: map[string]any{propType: testWorkflowType}, + }, + { + name: "with taskQueue is accepted", + workflow: map[string]any{propType: testWorkflowType, propTaskQueue: "other-queue"}, + }, + { + name: "orders.v2 is accepted", + workflow: map[string]any{propType: testWorkflowType, propTaskQueue: "orders.v2"}, + }, + { + name: "test_workflow is accepted", + workflow: map[string]any{propType: testWorkflowType, propTaskQueue: "test_workflow"}, + }, + { + name: "single-character name is accepted", + workflow: map[string]any{propType: testWorkflowType, propTaskQueue: "a"}, + }, + { + name: "64-character name is accepted", + workflow: map[string]any{ + propType: testWorkflowType, + propTaskQueue: strings.Repeat("a", 64), + }, + }, + { + name: "taskQueue with input and await false is accepted", + workflow: map[string]any{ + propType: testWorkflowType, + propTaskQueue: "other-queue", + propInput: map[string]any{"a": 1}, + }, + awaitFalse: true, + }, + { + name: "empty taskQueue is rejected", + workflow: map[string]any{ + propType: testWorkflowType, + propTaskQueue: "", + }, + wantError: true, + }, + { + name: "integer taskQueue is rejected", + workflow: map[string]any{ + propType: testWorkflowType, + propTaskQueue: 123, + }, + wantError: true, + }, + { + name: "object taskQueue is rejected", + workflow: map[string]any{ + propType: testWorkflowType, + propTaskQueue: map[string]any{}, + }, + wantError: true, + }, + { + name: "unknown sibling property is rejected", + workflow: map[string]any{ + propType: testWorkflowType, + "queue": "x", + }, + wantError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + doc := runWorkflowDoc(tt.workflow) + if tt.awaitFalse { + task := doc[propDo].([]any)[0].(map[string]any)["callChild"].(map[string]any) + task["run"].(map[string]any)["await"] = false + } + + err := resolved.Validate(doc) + if tt.wantError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} From 2cc1302ef3128fea62e9dbc9cf1395f5c791b63f Mon Sep 17 00:00:00 2001 From: Sam Gunner Date: Mon, 2 Nov 2026 14:41:19 +0000 Subject: [PATCH 2/2] test: remove 64 char limit task queue test case Signed-off-by: Sam Gunner --- schema_test.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/schema_test.go b/schema_test.go index 9d5e1c8..d6bd8e1 100644 --- a/schema_test.go +++ b/schema_test.go @@ -17,7 +17,6 @@ package schema import ( - "strings" "testing" "github.com/stretchr/testify/assert" @@ -183,13 +182,6 @@ func TestSchema_RunWorkflowTaskQueue(t *testing.T) { name: "single-character name is accepted", workflow: map[string]any{propType: testWorkflowType, propTaskQueue: "a"}, }, - { - name: "64-character name is accepted", - workflow: map[string]any{ - propType: testWorkflowType, - propTaskQueue: strings.Repeat("a", 64), - }, - }, { name: "taskQueue with input and await false is accepted", workflow: map[string]any{