diff --git a/CHANGELOG.md b/CHANGELOG.md index 530daa4c5f..2f9012a655 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## [Unreleased] +### Added +- Runs can now be given a custom `display_name` at trigger time (via any SDK's run/run-many/child-spawn options or the REST trigger endpoint), so fanned-out child runs are identifiable at a glance in the dashboard instead of sharing a generated `-` label. Single-task runs carry the name on the task; multi-step DAG runs carry it on the DAG (steps keep their generated names). Omitting the field (or passing empty/whitespace) preserves the previous generated-name behavior, and names longer than 255 characters are stored truncated rather than rejected ([#4259](https://github.com/hatchet-dev/hatchet/issues/4259)). + ### Highlights - Fixes timeouts in `UserSession` cleanup jobs by adding an index via a new `hatchet-migrate` migration. diff --git a/api-contracts/openapi/components/schemas/v1/workflow_run.yaml b/api-contracts/openapi/components/schemas/v1/workflow_run.yaml index 9ec024b395..6e99935b75 100644 --- a/api-contracts/openapi/components/schemas/v1/workflow_run.yaml +++ b/api-contracts/openapi/components/schemas/v1/workflow_run.yaml @@ -141,6 +141,9 @@ V1TriggerWorkflowRunRequest: priority: type: integer description: The priority of the workflow run. + displayName: + type: string + description: A custom display name for the run. Falls back to a generated name if unset. return_only_id: type: boolean description: A boolean flag indicating whether to only return the id of the created run. diff --git a/api-contracts/v1/shared/trigger.proto b/api-contracts/v1/shared/trigger.proto index ad8913a43d..9470224e41 100644 --- a/api-contracts/v1/shared/trigger.proto +++ b/api-contracts/v1/shared/trigger.proto @@ -74,4 +74,7 @@ message TriggerWorkflowRequest { // (optional) the desired worker labels for the workflow run, which will be used to determine which workers can pick up the workflow's tasks. if not set, defaults to an empty set of labels, which means any worker can pick up the tasks. map desired_worker_labels = 10; + + // (optional) a custom display name for the run; falls back to "-" if unset + optional string display_name = 11; } diff --git a/api-contracts/v1/workflows.proto b/api-contracts/v1/workflows.proto index e155664f61..62392d3990 100644 --- a/api-contracts/v1/workflows.proto +++ b/api-contracts/v1/workflows.proto @@ -50,6 +50,9 @@ message TriggerWorkflowRunRequest { bytes additional_metadata = 3; optional int32 priority = 4; map desired_worker_labels = 5; + + // (optional) a custom display name for the run; falls back to a generated name if unset + optional string display_name = 6; } message TriggerWorkflowRunResponse { diff --git a/api/v1/server/handlers/v1/workflow-runs/trigger.go b/api/v1/server/handlers/v1/workflow-runs/trigger.go index 1c1763cf7e..a3e59ec185 100644 --- a/api/v1/server/handlers/v1/workflow-runs/trigger.go +++ b/api/v1/server/handlers/v1/workflow-runs/trigger.go @@ -63,6 +63,7 @@ func (t *V1WorkflowRunsService) V1WorkflowRunCreate(ctx echo.Context, request ge Input: inputBytes, AdditionalMetadata: additionalMetadataBytes, Priority: priority, + DisplayName: request.Body.DisplayName, } resp, err := t.proxyTrigger.Do( diff --git a/api/v1/server/oas/gen/openapi.gen.go b/api/v1/server/oas/gen/openapi.gen.go index d5eb5b8548..36cd6f2f60 100644 --- a/api/v1/server/oas/gen/openapi.gen.go +++ b/api/v1/server/oas/gen/openapi.gen.go @@ -2065,7 +2065,10 @@ type V1TaskTimingList struct { // V1TriggerWorkflowRunRequest defines model for V1TriggerWorkflowRunRequest. type V1TriggerWorkflowRunRequest struct { AdditionalMetadata *map[string]interface{} `json:"additionalMetadata,omitempty"` - Input map[string]interface{} `json:"input"` + + // DisplayName A custom display name for the run. Falls back to a generated name if unset. + DisplayName *string `json:"displayName,omitempty"` + Input map[string]interface{} `json:"input"` // Priority The priority of the workflow run. Priority *int `json:"priority,omitempty"` @@ -17688,220 +17691,220 @@ var swaggerSpec = []string{ "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", - "4/8LAAD//18k+KSphwMA", + "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/frontend/app/src/lib/api/generated/data-contracts.ts b/frontend/app/src/lib/api/generated/data-contracts.ts index ed7e59d5e8..853a64c12b 100644 --- a/frontend/app/src/lib/api/generated/data-contracts.ts +++ b/frontend/app/src/lib/api/generated/data-contracts.ts @@ -658,6 +658,8 @@ export interface V1TriggerWorkflowRunRequest { additionalMetadata?: object; /** The priority of the workflow run. */ priority?: number; + /** A custom display name for the run. Falls back to a generated name if unset. */ + displayName?: string; /** A boolean flag indicating whether to only return the id of the created run. */ return_only_id?: boolean; } diff --git a/frontend/docs/pages/v1/_meta.js b/frontend/docs/pages/v1/_meta.js index 429226f98a..fe2075098c 100644 --- a/frontend/docs/pages/v1/_meta.js +++ b/frontend/docs/pages/v1/_meta.js @@ -39,6 +39,7 @@ export default { concurrency: "Concurrency", "rate-limits": "Rate Limits", priority: "Priority", + "run-names": "Run Names", "--durable-workflows-section": { title: "Durable Execution", type: "separator", diff --git a/frontend/docs/pages/v1/additional-metadata.mdx b/frontend/docs/pages/v1/additional-metadata.mdx index a2a847dd16..a11c176520 100644 --- a/frontend/docs/pages/v1/additional-metadata.mdx +++ b/frontend/docs/pages/v1/additional-metadata.mdx @@ -14,6 +14,12 @@ Hatchet allows you to attach arbitrary key-value string pairs to events and task runs. + + If you only want a human-readable label to tell fanned-out runs apart in the + dashboard, see [Run Names](./run-names.mdx) — it sets the run's `display_name` + directly instead of relying on metadata. + + You can attach additional metadata when pushing events or triggering task runs using the Hatchet client libraries: diff --git a/frontend/docs/pages/v1/child-spawning.mdx b/frontend/docs/pages/v1/child-spawning.mdx index c2ff543488..0e80264f2e 100644 --- a/frontend/docs/pages/v1/child-spawning.mdx +++ b/frontend/docs/pages/v1/child-spawning.mdx @@ -10,6 +10,12 @@ import FanoutDiagram from "@/components/FanoutDiagram"; A task can spawn child tasks at runtime — including other durable tasks or entire DAG workflows. Children run independently on any available worker, and the parent can wait for their results before continuing. You can spawn children out of any task (durable or not). + + Spawning many children at once? Give each a [display name](./run-names.mdx) so + they're identifiable at a glance in the dashboard instead of sharing a + generated name. + + While child spawning is not unique to durable tasks, we often recommend using durable tasks when spawning children is the main responsibility (or one of the diff --git a/frontend/docs/pages/v1/run-names.mdx b/frontend/docs/pages/v1/run-names.mdx new file mode 100644 index 0000000000..0c3f9e6c49 --- /dev/null +++ b/frontend/docs/pages/v1/run-names.mdx @@ -0,0 +1,85 @@ +import { Callout, Tabs } from "nextra/components"; +import UniversalTabs from "../../components/UniversalTabs"; + +# Naming runs with a custom display name + +By default, each run in Hatchet is labelled with a generated name of the form `-` (for example, `resolve-subprocessor-info-1782146942603`). When a parent fans out many child runs in a single batch, they all share the same step id and batch timestamp, so the runs list renders several identically-named rows and you have to open each run's input to tell them apart. + +You can instead set a human-readable **display name** at trigger time. The dashboard renders it automatically in the runs list, the run detail header, and the children list — no other configuration required. + + + +The display name is applied to the **run**: + +- For a **single-task** workflow, it lands on the task (the task _is_ the run). +- For a **multi-step DAG**, it lands on the DAG run; the DAG's step tasks keep their generated names. + +Omitting the field (or passing an empty/whitespace value) preserves the default generated name. A name longer than 255 characters is stored truncated, never rejected. + + + +## Setting a display name + +Pass the display name in the options you already use to trigger a run. This works for top-level runs, `run_many` / bulk triggers (each item gets its own name), and child spawns (each child gets its own name). + + + + +```python +# Top-level run +workflow.run(input, display_name="Acme Corp") + +# Per-item names in a bulk run +workflow.run_many([ + workflow.create_bulk_run_item(input=input_a, display_name="Acme Corp"), + workflow.create_bulk_run_item(input=input_b, display_name="Globex"), +]) +``` + + + + +```typescript +// Top-level run +await workflow.run(input, { displayName: "Acme Corp" }); + +// Spawning a child with its own name +await ctx.runChild(childWorkflow, input, { displayName: "Acme Corp" }); +``` + + + + +```go +// Top-level run +_, err := client.Run(ctx, "my-workflow", input, hatchet.WithRunDisplayName("Acme Corp")) +``` + + + + +```ruby +# Top-level run +workflow.run(input, options: { display_name: "Acme Corp" }) +``` + + + + +## REST + +The REST trigger endpoint accepts the same field: + +```json +POST /api/v1/stable/tenants/{tenant}/workflow-runs/trigger +{ + "workflowName": "my-workflow", + "input": { ... }, + "displayName": "Acme Corp" +} +``` + +## Related + +- [Additional metadata](./additional-metadata.mdx) — attach arbitrary key/value metadata to a run, which is filterable and searchable (the display name is display-only). +- [Child spawning](./child-spawning.mdx) — fanning out child runs, the most common place a per-run display name helps. diff --git a/internal/services/admin/v1/server.go b/internal/services/admin/v1/server.go index 6873d51c2c..e14c7831f1 100644 --- a/internal/services/admin/v1/server.go +++ b/internal/services/admin/v1/server.go @@ -565,6 +565,7 @@ func (a *AdminServiceImpl) newTriggerOpt( WorkflowName: req.WorkflowName, Data: req.Input, AdditionalMetadata: req.AdditionalMetadata, + DisplayName: v1.NormalizeDisplayName(req.DisplayName), } if len(req.DesiredWorkerLabels) > 0 { diff --git a/internal/services/admin/v1/server_test.go b/internal/services/admin/v1/server_test.go new file mode 100644 index 0000000000..5d176076ee --- /dev/null +++ b/internal/services/admin/v1/server_test.go @@ -0,0 +1,35 @@ +package v1 + +import ( + "context" + "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + contracts "github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1" +) + +func Test_newTriggerOpt_normalizes_display_name(t *testing.T) { + a := &AdminServiceImpl{} + name := " Acme Corp " + + opt, err := a.newTriggerOpt(context.Background(), uuid.New(), &contracts.TriggerWorkflowRunRequest{ + WorkflowName: "my-workflow", + DisplayName: &name, + }) + require.NoError(t, err) + require.NotNil(t, opt.DisplayName, "REST display name should be carried onto the trigger opt") + assert.Equal(t, "Acme Corp", *opt.DisplayName, "REST display name is trimmed via NormalizeDisplayName") +} + +func Test_newTriggerOpt_omits_display_name_when_unset(t *testing.T) { + a := &AdminServiceImpl{} + + opt, err := a.newTriggerOpt(context.Background(), uuid.New(), &contracts.TriggerWorkflowRunRequest{ + WorkflowName: "my-workflow", + }) + require.NoError(t, err) + assert.Nil(t, opt.DisplayName, "omitted display name stays unset so the run falls back to a generated name") +} diff --git a/internal/services/shared/proto/v1/trigger.pb.go b/internal/services/shared/proto/v1/trigger.pb.go index 73fdab6836..0305943847 100644 --- a/internal/services/shared/proto/v1/trigger.pb.go +++ b/internal/services/shared/proto/v1/trigger.pb.go @@ -198,6 +198,8 @@ type TriggerWorkflowRequest struct { Priority *int32 `protobuf:"varint,9,opt,name=priority,proto3,oneof" json:"priority,omitempty"` // (optional) the desired worker labels for the workflow run, which will be used to determine which workers can pick up the workflow's tasks. if not set, defaults to an empty set of labels, which means any worker can pick up the tasks. DesiredWorkerLabels map[string]*DesiredWorkerLabels `protobuf:"bytes,10,rep,name=desired_worker_labels,json=desiredWorkerLabels,proto3" json:"desired_worker_labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // (optional) a custom display name for the run; falls back to "-" if unset + DisplayName *string `protobuf:"bytes,11,opt,name=display_name,json=displayName,proto3,oneof" json:"display_name,omitempty"` } func (x *TriggerWorkflowRequest) Reset() { @@ -302,6 +304,13 @@ func (x *TriggerWorkflowRequest) GetDesiredWorkerLabels() map[string]*DesiredWor return nil } +func (x *TriggerWorkflowRequest) GetDisplayName() string { + if x != nil && x.DisplayName != nil { + return *x.DisplayName + } + return "" +} + var File_v1_shared_trigger_proto protoreflect.FileDescriptor var file_v1_shared_trigger_proto_rawDesc = []byte{ @@ -324,7 +333,7 @@ var file_v1_shared_trigger_proto_rawDesc = []byte{ 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x42, - 0x09, 0x0a, 0x07, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0xc8, 0x05, 0x0a, 0x16, 0x54, + 0x09, 0x0a, 0x07, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x81, 0x06, 0x0a, 0x16, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x70, @@ -354,35 +363,39 @@ var file_v1_shared_trigger_proto_rawDesc = []byte{ 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, - 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x5f, 0x0a, - 0x18, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, - 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x2e, - 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, - 0x65, 0x6c, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0c, - 0x0a, 0x0a, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x42, 0x1e, 0x0a, 0x1c, - 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x72, 0x75, 0x6e, - 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x42, 0x0e, 0x0a, 0x0c, - 0x5f, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x0c, 0x0a, 0x0a, - 0x5f, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x61, - 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x77, - 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x70, 0x72, 0x69, - 0x6f, 0x72, 0x69, 0x74, 0x79, 0x2a, 0x85, 0x01, 0x0a, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, - 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, - 0x09, 0x0a, 0x05, 0x45, 0x51, 0x55, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, - 0x54, 0x5f, 0x45, 0x51, 0x55, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x47, 0x52, 0x45, - 0x41, 0x54, 0x45, 0x52, 0x5f, 0x54, 0x48, 0x41, 0x4e, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x47, - 0x52, 0x45, 0x41, 0x54, 0x45, 0x52, 0x5f, 0x54, 0x48, 0x41, 0x4e, 0x5f, 0x4f, 0x52, 0x5f, 0x45, - 0x51, 0x55, 0x41, 0x4c, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x54, - 0x48, 0x41, 0x4e, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x48, - 0x41, 0x4e, 0x5f, 0x4f, 0x52, 0x5f, 0x45, 0x51, 0x55, 0x41, 0x4c, 0x10, 0x05, 0x42, 0x42, 0x5a, - 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x74, 0x63, - 0x68, 0x65, 0x74, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2f, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, - 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x26, 0x0a, + 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x07, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, + 0x6d, 0x65, 0x88, 0x01, 0x01, 0x1a, 0x5f, 0x0a, 0x18, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, + 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, + 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x5f, 0x69, 0x64, 0x42, 0x1e, 0x0a, 0x1c, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, + 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x5f, 0x69, 0x64, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x6b, + 0x65, 0x79, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x64, + 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x42, 0x0f, 0x0a, + 0x0d, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x2a, 0x85, + 0x01, 0x0a, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x43, 0x6f, + 0x6d, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x51, 0x55, 0x41, + 0x4c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x54, 0x5f, 0x45, 0x51, 0x55, 0x41, 0x4c, + 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x47, 0x52, 0x45, 0x41, 0x54, 0x45, 0x52, 0x5f, 0x54, 0x48, + 0x41, 0x4e, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x47, 0x52, 0x45, 0x41, 0x54, 0x45, 0x52, 0x5f, + 0x54, 0x48, 0x41, 0x4e, 0x5f, 0x4f, 0x52, 0x5f, 0x45, 0x51, 0x55, 0x41, 0x4c, 0x10, 0x03, 0x12, + 0x0d, 0x0a, 0x09, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x48, 0x41, 0x4e, 0x10, 0x04, 0x12, 0x16, + 0x0a, 0x12, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x48, 0x41, 0x4e, 0x5f, 0x4f, 0x52, 0x5f, 0x45, + 0x51, 0x55, 0x41, 0x4c, 0x10, 0x05, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2d, 0x64, 0x65, 0x76, + 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, + 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( diff --git a/internal/services/shared/proto/v1/workflows.pb.go b/internal/services/shared/proto/v1/workflows.pb.go index db2a08f1e7..2f0ad2dbc6 100644 --- a/internal/services/shared/proto/v1/workflows.pb.go +++ b/internal/services/shared/proto/v1/workflows.pb.go @@ -534,6 +534,8 @@ type TriggerWorkflowRunRequest struct { AdditionalMetadata []byte `protobuf:"bytes,3,opt,name=additional_metadata,json=additionalMetadata,proto3" json:"additional_metadata,omitempty"` Priority *int32 `protobuf:"varint,4,opt,name=priority,proto3,oneof" json:"priority,omitempty"` DesiredWorkerLabels map[string]*DesiredWorkerLabels `protobuf:"bytes,5,rep,name=desired_worker_labels,json=desiredWorkerLabels,proto3" json:"desired_worker_labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // (optional) a custom display name for the run; falls back to a generated name if unset + DisplayName *string `protobuf:"bytes,6,opt,name=display_name,json=displayName,proto3,oneof" json:"display_name,omitempty"` } func (x *TriggerWorkflowRunRequest) Reset() { @@ -603,6 +605,13 @@ func (x *TriggerWorkflowRunRequest) GetDesiredWorkerLabels() map[string]*Desired return nil } +func (x *TriggerWorkflowRunRequest) GetDisplayName() string { + if x != nil && x.DisplayName != nil { + return *x.DisplayName + } + return "" +} + type TriggerWorkflowRunResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1626,7 +1635,7 @@ var file_v1_workflows_proto_rawDesc = []byte{ 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x64, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x64, 0x54, 0x61, 0x73, - 0x6b, 0x73, 0x22, 0x82, 0x03, 0x0a, 0x19, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, + 0x6b, 0x73, 0x22, 0xbb, 0x03, 0x0a, 0x19, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, @@ -1643,275 +1652,278 @@ var file_v1_workflows_proto_rawDesc = []byte{ 0x77, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, - 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x5f, 0x0a, 0x18, 0x44, 0x65, 0x73, - 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x69, - 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x70, - 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x3d, 0x0a, 0x1a, 0x54, 0x72, 0x69, 0x67, 0x67, - 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x22, 0x7a, 0x0a, 0x18, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, - 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x61, - 0x73, 0x6b, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, - 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, - 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x5f, - 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, - 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x19, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x44, 0x75, 0x72, 0x61, - 0x62, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x28, 0x0a, 0x10, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x61, 0x73, 0x6b, 0x45, - 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, - 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, - 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x49, 0x64, 0x22, - 0xdd, 0x05, 0x0a, 0x1c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, - 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, - 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, - 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x72, 0x6f, 0x6e, 0x5f, - 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, - 0x63, 0x72, 0x6f, 0x6e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x12, 0x28, 0x0a, 0x05, - 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x70, 0x74, 0x73, 0x52, - 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x31, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, - 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, - 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x22, 0x0a, 0x0a, 0x63, 0x72, 0x6f, - 0x6e, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, - 0x09, 0x63, 0x72, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x88, 0x01, 0x01, 0x12, 0x3f, 0x0a, - 0x0f, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x70, 0x74, 0x73, 0x48, 0x01, 0x52, 0x0d, 0x6f, 0x6e, - 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x12, 0x2f, - 0x0a, 0x06, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x69, 0x63, 0x6b, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, - 0x67, 0x79, 0x48, 0x02, 0x52, 0x06, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x79, 0x88, 0x01, 0x01, 0x12, - 0x2e, 0x0a, 0x10, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x72, 0x69, 0x6f, 0x72, - 0x69, 0x74, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x48, 0x03, 0x52, 0x0f, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x88, 0x01, 0x01, 0x12, - 0x38, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x61, - 0x72, 0x72, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, - 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x63, 0x75, - 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x72, 0x72, 0x12, 0x3a, 0x0a, 0x0f, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x0d, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2f, 0x0a, 0x11, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6a, - 0x73, 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, - 0x48, 0x04, 0x52, 0x0f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x4a, 0x73, 0x6f, 0x6e, 0x53, 0x63, 0x68, - 0x65, 0x6d, 0x61, 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x72, 0x6f, 0x6e, 0x5f, - 0x69, 0x6e, 0x70, 0x75, 0x74, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x69, - 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x74, - 0x69, 0x63, 0x6b, 0x79, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x5f, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x69, 0x6e, - 0x70, 0x75, 0x74, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x22, - 0x70, 0x0a, 0x0d, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, - 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, - 0x61, 0x64, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x22, 0xb7, 0x01, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, - 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x1e, 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x75, 0x6e, 0x73, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x52, 0x75, 0x6e, 0x73, 0x88, 0x01, - 0x01, 0x12, 0x48, 0x0a, 0x0e, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, - 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, - 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x48, 0x01, 0x52, 0x0d, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, - 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x75, 0x6e, 0x73, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x22, 0x85, 0x07, 0x0a, 0x0e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x70, 0x74, 0x73, 0x12, 0x1f, - 0x0a, 0x0b, 0x72, 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x64, 0x12, - 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, - 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, - 0x74, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x38, 0x0a, - 0x0b, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, - 0x73, 0x6b, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x0a, 0x72, 0x61, 0x74, - 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x49, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, - 0x72, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x70, - 0x74, 0x73, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, - 0x6c, 0x73, 0x12, 0x2a, 0x0a, 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x5f, 0x66, 0x61, - 0x63, 0x74, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x02, 0x48, 0x00, 0x52, 0x0d, 0x62, 0x61, - 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x33, - 0x0a, 0x13, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, - 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x48, 0x01, 0x52, 0x11, 0x62, - 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x4d, 0x61, 0x78, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, - 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, - 0x63, 0x79, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, - 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, - 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x37, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, - 0x54, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x48, 0x02, - 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x12, - 0x2e, 0x0a, 0x10, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x6f, 0x75, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x0f, 0x73, 0x63, 0x68, - 0x65, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x88, 0x01, 0x01, 0x12, - 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x0e, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x49, - 0x0a, 0x0d, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, - 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x70, 0x74, 0x73, 0x2e, 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x73, 0x6c, 0x6f, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x1a, 0x58, 0x0a, 0x11, 0x57, 0x6f, 0x72, - 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, - 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x1a, 0x3f, 0x0a, 0x11, 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, - 0x5f, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x62, 0x61, 0x63, 0x6b, - 0x6f, 0x66, 0x66, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x42, - 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x13, - 0x0a, 0x11, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x6f, 0x75, 0x74, 0x22, 0xb8, 0x02, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, - 0x73, 0x6b, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x19, 0x0a, - 0x05, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x05, - 0x75, 0x6e, 0x69, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x1e, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, - 0x65, 0x78, 0x70, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x07, 0x6b, 0x65, - 0x79, 0x45, 0x78, 0x70, 0x72, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x75, 0x6e, 0x69, 0x74, - 0x73, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x09, - 0x75, 0x6e, 0x69, 0x74, 0x73, 0x45, 0x78, 0x70, 0x72, 0x88, 0x01, 0x01, 0x12, 0x2f, 0x0a, 0x11, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x5f, 0x65, 0x78, 0x70, - 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x0f, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x45, 0x78, 0x70, 0x72, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, - 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x15, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x44, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x04, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x42, - 0x0b, 0x0a, 0x09, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x42, 0x0d, 0x0a, 0x0b, - 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x42, 0x14, 0x0a, 0x12, 0x5f, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x5f, 0x65, 0x78, 0x70, - 0x72, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x50, - 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x1f, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, - 0x22, 0x37, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, - 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x22, 0xe4, 0x01, 0x0a, 0x0d, 0x54, 0x61, - 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x65, - 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x75, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x1b, - 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, - 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x0b, 0x72, - 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x72, 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, - 0x69, 0x73, 0x5f, 0x65, 0x76, 0x69, 0x63, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x09, 0x69, 0x73, 0x45, 0x76, 0x69, 0x63, 0x74, 0x65, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x5f, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x22, 0xce, 0x02, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, - 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, - 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, - 0x12, 0x25, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x0d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x75, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x44, 0x0a, 0x09, 0x74, 0x61, 0x73, 0x6b, 0x5f, - 0x72, 0x75, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x08, 0x74, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x73, 0x12, 0x12, 0x0a, - 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x6f, 0x6e, - 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, - 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, - 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x65, 0x76, 0x69, 0x63, 0x74, 0x65, 0x64, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x45, 0x76, 0x69, 0x63, 0x74, 0x65, - 0x64, 0x1a, 0x4e, 0x0a, 0x0d, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, - 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x2a, 0x24, 0x0a, 0x0e, 0x53, 0x74, 0x69, 0x63, 0x6b, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, - 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x4f, 0x46, 0x54, 0x10, 0x00, 0x12, 0x08, 0x0a, - 0x04, 0x48, 0x41, 0x52, 0x44, 0x10, 0x01, 0x2a, 0x5d, 0x0a, 0x11, 0x52, 0x61, 0x74, 0x65, 0x4c, - 0x69, 0x6d, 0x69, 0x74, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, - 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x49, 0x4e, 0x55, - 0x54, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x4f, 0x55, 0x52, 0x10, 0x02, 0x12, 0x07, - 0x0a, 0x03, 0x44, 0x41, 0x59, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x45, 0x45, 0x4b, 0x10, - 0x04, 0x12, 0x09, 0x0a, 0x05, 0x4d, 0x4f, 0x4e, 0x54, 0x48, 0x10, 0x05, 0x12, 0x08, 0x0a, 0x04, - 0x59, 0x45, 0x41, 0x52, 0x10, 0x06, 0x2a, 0x5b, 0x0a, 0x09, 0x52, 0x75, 0x6e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x0a, 0x0a, 0x06, 0x51, 0x55, 0x45, 0x55, 0x45, 0x44, 0x10, 0x00, 0x12, - 0x0b, 0x0a, 0x07, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, - 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x46, - 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x41, 0x4e, 0x43, 0x45, - 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x56, 0x49, 0x43, 0x54, 0x45, - 0x44, 0x10, 0x05, 0x2a, 0x7f, 0x0a, 0x18, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, - 0x63, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, - 0x16, 0x0a, 0x12, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x5f, 0x49, 0x4e, 0x5f, 0x50, 0x52, 0x4f, - 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x52, 0x4f, 0x50, 0x5f, - 0x4e, 0x45, 0x57, 0x45, 0x53, 0x54, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x51, 0x55, 0x45, 0x55, - 0x45, 0x5f, 0x4e, 0x45, 0x57, 0x45, 0x53, 0x54, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x47, 0x52, - 0x4f, 0x55, 0x50, 0x5f, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x52, 0x4f, 0x42, 0x49, 0x4e, 0x10, - 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x5f, 0x4e, 0x45, 0x57, 0x45, - 0x53, 0x54, 0x10, 0x04, 0x32, 0xcf, 0x03, 0x0a, 0x0c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x52, 0x0a, 0x0b, 0x50, 0x75, 0x74, 0x57, 0x6f, 0x72, 0x6b, - 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x20, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x43, 0x61, 0x6e, - 0x63, 0x65, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x16, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x61, 0x73, 0x6b, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x52, 0x65, 0x70, - 0x6c, 0x61, 0x79, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x16, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x70, 0x6c, 0x61, 0x79, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x54, 0x61, 0x73, 0x6b, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x12, 0x54, 0x72, 0x69, - 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x12, - 0x1d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, - 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, - 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, - 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, - 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, - 0x18, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, - 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x76, 0x31, 0x2e, 0x47, - 0x65, 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x11, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x44, 0x75, - 0x72, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x1c, 0x2e, 0x76, 0x31, 0x2e, 0x42, + 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x26, 0x0a, 0x0c, 0x64, 0x69, 0x73, + 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x01, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, + 0x01, 0x1a, 0x5f, 0x0a, 0x18, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, + 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, + 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x42, + 0x0f, 0x0a, 0x0d, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x22, 0x3d, 0x0a, 0x1a, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, + 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x22, + 0x7a, 0x0a, 0x18, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x74, + 0x61, 0x73, 0x6b, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x61, 0x73, 0x6b, 0x45, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x1b, + 0x0a, 0x09, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x08, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x19, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x72, 0x61, - 0x6e, 0x63, 0x68, 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2d, 0x64, 0x65, 0x76, - 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, - 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x61, 0x73, 0x6b, + 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0e, 0x74, 0x61, 0x73, 0x6b, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x62, + 0x72, 0x61, 0x6e, 0x63, 0x68, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, + 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x49, 0x64, 0x22, 0xdd, 0x05, 0x0a, 0x1c, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x5f, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, + 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x72, 0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, + 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x72, 0x6f, 0x6e, 0x54, 0x72, 0x69, + 0x67, 0x67, 0x65, 0x72, 0x73, 0x12, 0x28, 0x0a, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x06, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x70, 0x74, 0x73, 0x52, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x12, + 0x31, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x63, 0x79, 0x12, 0x22, 0x0a, 0x0a, 0x63, 0x72, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x63, 0x72, 0x6f, 0x6e, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x88, 0x01, 0x01, 0x12, 0x3f, 0x0a, 0x0f, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x69, + 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4f, + 0x70, 0x74, 0x73, 0x48, 0x01, 0x52, 0x0d, 0x6f, 0x6e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, + 0x54, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x74, 0x69, 0x63, 0x6b, + 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x69, + 0x63, 0x6b, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x48, 0x02, 0x52, 0x06, 0x73, + 0x74, 0x69, 0x63, 0x6b, 0x79, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x10, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x0b, 0x20, 0x01, + 0x28, 0x05, 0x48, 0x03, 0x52, 0x0f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x72, 0x69, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x88, 0x01, 0x01, 0x12, 0x38, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x61, 0x72, 0x72, 0x18, 0x0c, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x63, 0x79, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x41, + 0x72, 0x72, 0x12, 0x3a, 0x0a, 0x0f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, + 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0e, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2f, + 0x0a, 0x11, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x04, 0x52, 0x0f, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x4a, 0x73, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x88, 0x01, 0x01, 0x42, + 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x72, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x42, 0x12, + 0x0a, 0x10, 0x5f, 0x6f, 0x6e, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x74, 0x61, + 0x73, 0x6b, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x79, 0x42, 0x13, 0x0a, + 0x11, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6a, 0x73, 0x6f, + 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x22, 0x70, 0x0a, 0x0d, 0x44, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, + 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, + 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, + 0x1d, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, + 0x48, 0x00, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x88, 0x01, 0x01, 0x42, 0x0a, + 0x0a, 0x08, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xb7, 0x01, 0x0a, 0x0b, 0x43, + 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x08, 0x6d, 0x61, + 0x78, 0x5f, 0x72, 0x75, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x07, + 0x6d, 0x61, 0x78, 0x52, 0x75, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x12, 0x48, 0x0a, 0x0e, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, + 0x6e, 0x63, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, + 0x48, 0x01, 0x52, 0x0d, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, + 0x79, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x75, 0x6e, + 0x73, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, + 0x74, 0x65, 0x67, 0x79, 0x22, 0x85, 0x07, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, + 0x61, 0x73, 0x6b, 0x4f, 0x70, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x61, 0x64, 0x61, + 0x62, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, + 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, + 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x72, + 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x0b, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x6c, + 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x61, 0x74, 0x65, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x52, 0x0a, 0x72, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, + 0x12, 0x49, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x70, 0x74, 0x73, 0x2e, 0x57, 0x6f, 0x72, 0x6b, + 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x77, + 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x2a, 0x0a, 0x0e, 0x62, + 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x5f, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x02, 0x48, 0x00, 0x52, 0x0d, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x46, 0x61, + 0x63, 0x74, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x33, 0x0a, 0x13, 0x62, 0x61, 0x63, 0x6b, 0x6f, + 0x66, 0x66, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x05, 0x48, 0x01, 0x52, 0x11, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x4d, + 0x61, 0x78, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x0b, + 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x0b, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, + 0x37, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x6e, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x48, 0x02, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x10, 0x73, 0x63, 0x68, 0x65, + 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x0d, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x03, 0x52, 0x0f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x69, + 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x64, + 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, + 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x49, 0x0a, 0x0d, 0x73, 0x6c, 0x6f, 0x74, 0x5f, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x70, + 0x74, 0x73, 0x2e, 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x73, 0x6c, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x73, 0x1a, 0x58, 0x0a, 0x11, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, + 0x73, 0x69, 0x72, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3f, 0x0a, 0x11, + 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x11, 0x0a, + 0x0f, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x5f, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, + 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x5f, 0x6d, 0x61, 0x78, + 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x6f, 0x6e, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x73, 0x63, 0x68, 0x65, + 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0xb8, 0x02, 0x0a, + 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x61, 0x74, 0x65, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x05, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x05, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x88, 0x01, + 0x01, 0x12, 0x1e, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x45, 0x78, 0x70, 0x72, 0x88, 0x01, + 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x09, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x45, 0x78, + 0x70, 0x72, 0x88, 0x01, 0x01, 0x12, 0x2f, 0x0a, 0x11, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x03, 0x52, 0x0f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x45, + 0x78, 0x70, 0x72, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x61, + 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, + 0x04, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x08, + 0x0a, 0x06, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6b, 0x65, 0x79, + 0x5f, 0x65, 0x78, 0x70, 0x72, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x5f, + 0x65, 0x78, 0x70, 0x72, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x64, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x50, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, + 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, + 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x22, 0x37, 0x0a, 0x14, 0x47, 0x65, 0x74, + 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x49, 0x64, 0x22, 0xe4, 0x01, 0x0a, 0x0d, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x44, 0x65, + 0x74, 0x61, 0x69, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x75, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x05, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x61, 0x64, 0x61, + 0x62, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x65, 0x76, 0x69, 0x63, + 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x45, 0x76, 0x69, + 0x63, 0x74, 0x65, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x09, + 0x0a, 0x07, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0xce, 0x02, 0x0a, 0x15, 0x47, 0x65, + 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x25, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x75, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x44, 0x0a, 0x09, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x72, 0x75, 0x6e, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x44, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, + 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x74, 0x61, + 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x61, 0x64, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x69, + 0x73, 0x5f, 0x65, 0x76, 0x69, 0x63, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x09, 0x69, 0x73, 0x45, 0x76, 0x69, 0x63, 0x74, 0x65, 0x64, 0x1a, 0x4e, 0x0a, 0x0d, 0x54, 0x61, + 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x27, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, + 0x31, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x2a, 0x24, 0x0a, 0x0e, 0x53, 0x74, + 0x69, 0x63, 0x6b, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, + 0x53, 0x4f, 0x46, 0x54, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x41, 0x52, 0x44, 0x10, 0x01, + 0x2a, 0x5d, 0x0a, 0x11, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x44, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x10, + 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x49, 0x4e, 0x55, 0x54, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, + 0x04, 0x48, 0x4f, 0x55, 0x52, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x44, 0x41, 0x59, 0x10, 0x03, + 0x12, 0x08, 0x0a, 0x04, 0x57, 0x45, 0x45, 0x4b, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x4d, 0x4f, + 0x4e, 0x54, 0x48, 0x10, 0x05, 0x12, 0x08, 0x0a, 0x04, 0x59, 0x45, 0x41, 0x52, 0x10, 0x06, 0x2a, + 0x5b, 0x0a, 0x09, 0x52, 0x75, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0a, 0x0a, 0x06, + 0x51, 0x55, 0x45, 0x55, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x55, 0x4e, 0x4e, + 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, + 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, + 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, + 0x0b, 0x0a, 0x07, 0x45, 0x56, 0x49, 0x43, 0x54, 0x45, 0x44, 0x10, 0x05, 0x2a, 0x7f, 0x0a, 0x18, + 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, + 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x41, 0x4e, 0x43, + 0x45, 0x4c, 0x5f, 0x49, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x00, + 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x52, 0x4f, 0x50, 0x5f, 0x4e, 0x45, 0x57, 0x45, 0x53, 0x54, 0x10, + 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x51, 0x55, 0x45, 0x55, 0x45, 0x5f, 0x4e, 0x45, 0x57, 0x45, 0x53, + 0x54, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x5f, 0x52, 0x4f, 0x55, + 0x4e, 0x44, 0x5f, 0x52, 0x4f, 0x42, 0x49, 0x4e, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x41, + 0x4e, 0x43, 0x45, 0x4c, 0x5f, 0x4e, 0x45, 0x57, 0x45, 0x53, 0x54, 0x10, 0x04, 0x32, 0xcf, 0x03, + 0x0a, 0x0c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x52, + 0x0a, 0x0b, 0x50, 0x75, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x20, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, + 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x21, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, + 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x61, 0x73, 0x6b, + 0x73, 0x12, 0x16, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x61, 0x73, + 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x54, 0x61, 0x73, 0x6b, + 0x73, 0x12, 0x16, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x54, 0x61, 0x73, + 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x65, 0x70, 0x6c, 0x61, 0x79, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x53, 0x0a, 0x12, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, + 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x12, 0x1d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, + 0x69, 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x69, + 0x67, 0x67, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x75, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x52, 0x75, + 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x18, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x44, 0x65, + 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, + 0x11, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x44, 0x75, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x61, + 0x73, 0x6b, 0x12, 0x1c, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x44, 0x75, + 0x72, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1d, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x44, 0x75, 0x72, 0x61, + 0x62, 0x6c, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, + 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, + 0x74, 0x63, 0x68, 0x65, 0x74, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/pkg/client/admin.go b/pkg/client/admin.go index 20c9edcb17..c18792dedb 100644 --- a/pkg/client/admin.go +++ b/pkg/client/admin.go @@ -34,6 +34,7 @@ type ChildWorkflowOpts struct { AdditionalMetadata *map[string]string Priority *int32 DesiredWorkerLabels map[string]*types.DesiredWorkerLabel + DisplayName *string } // NewChildWorkflowTriggerRequest builds the trigger request used to start a child workflow. @@ -81,6 +82,12 @@ func NewChildWorkflowTriggerRequest(workflowName string, input interface{}, opts } } + if opts.DisplayName != nil { + if err := WithDisplayName(*opts.DisplayName)(request); err != nil { + return nil, fmt.Errorf("could not apply display name: %w", err) + } + } + return request, nil } @@ -346,6 +353,16 @@ func WithPriority(priority int32) RunOptFunc { } } +// WithDisplayName sets a custom display name for the run. The engine trims and +// truncates it; an empty/whitespace value falls back to the generated name. +func WithDisplayName(name string) RunOptFunc { + return func(r *v1contracts.TriggerWorkflowRequest) error { + r.DisplayName = &name + + return nil + } +} + func WithDesiredWorkerLabels(labels map[string]*types.DesiredWorkerLabel) RunOptFunc { return func(r *admincontracts.TriggerWorkflowRequest) error { r.DesiredWorkerLabels = desiredWorkerLabelsToProto(labels) diff --git a/pkg/client/admin_display_name_test.go b/pkg/client/admin_display_name_test.go new file mode 100644 index 0000000000..e70f8b0c10 --- /dev/null +++ b/pkg/client/admin_display_name_test.go @@ -0,0 +1,37 @@ +package client + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + v1contracts "github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1" +) + +func TestWithDisplayName_setsRequestField(t *testing.T) { + req := &v1contracts.TriggerWorkflowRequest{Name: "wf"} + + err := WithDisplayName("Acme Corp")(req) + require.NoError(t, err) + + require.NotNil(t, req.DisplayName) + assert.Equal(t, "Acme Corp", *req.DisplayName) +} + +func TestNewChildWorkflowTriggerRequest_setsDisplayName(t *testing.T) { + name := "Acme Corp" + + req, err := NewChildWorkflowTriggerRequest("child-wf", map[string]any{}, &ChildWorkflowOpts{DisplayName: &name}, nil) + require.NoError(t, err) + + require.NotNil(t, req.DisplayName) + assert.Equal(t, "Acme Corp", *req.DisplayName, "child spawn carries the display name onto the request") +} + +func TestNewChildWorkflowTriggerRequest_omitsDisplayName(t *testing.T) { + req, err := NewChildWorkflowTriggerRequest("child-wf", map[string]any{}, &ChildWorkflowOpts{}, nil) + require.NoError(t, err) + + assert.Nil(t, req.DisplayName, "an unset display name leaves the request field nil") +} diff --git a/pkg/client/rest/gen.go b/pkg/client/rest/gen.go index 63775fad4e..2a8ed54d38 100644 --- a/pkg/client/rest/gen.go +++ b/pkg/client/rest/gen.go @@ -2062,7 +2062,10 @@ type V1TaskTimingList struct { // V1TriggerWorkflowRunRequest defines model for V1TriggerWorkflowRunRequest. type V1TriggerWorkflowRunRequest struct { AdditionalMetadata *map[string]interface{} `json:"additionalMetadata,omitempty"` - Input map[string]interface{} `json:"input"` + + // DisplayName A custom display name for the run. Falls back to a generated name if unset. + DisplayName *string `json:"displayName,omitempty"` + Input map[string]interface{} `json:"input"` // Priority The priority of the workflow run. Priority *int `json:"priority,omitempty"` diff --git a/pkg/repository/durable_events_test.go b/pkg/repository/durable_events_test.go index 14d7cce814..c2c61fee06 100644 --- a/pkg/repository/durable_events_test.go +++ b/pkg/repository/durable_events_test.go @@ -13,6 +13,41 @@ import ( "github.com/stretchr/testify/assert" ) +// A durable replay re-issues the same child spawn; the child is matched by its +// idempotency key and reused with the first spawn's stored name. Because display_name +// is display-only, it must never enter the idempotency key — otherwise editing a +// cosmetic label would change the key, spawn a duplicate, and (per the key comparison +// at the sole non-determinism check) risk a NonDeterminismError. This guards that +// invariant: opts differing only in display_name hash to the same key. +func Test_createIdempotencyKey_ignores_display_name(t *testing.T) { + r := &durableEventsRepository{} + + nameA := "A" + nameB := "B" + + newOpt := func(displayName *string) *WorkflowNameTriggerOpts { + return &WorkflowNameTriggerOpts{ + TriggerTaskData: &TriggerTaskData{ + WorkflowName: "my-workflow", + Data: []byte(`{"x":1}`), + DisplayName: displayName, + }, + } + } + + keyUnset, err := r.createIdempotencyKey(sqlcv1.V1DurableEventLogKindRUN, newOpt(nil), nil) + assert.NoError(t, err) + + keyA, err := r.createIdempotencyKey(sqlcv1.V1DurableEventLogKindRUN, newOpt(&nameA), nil) + assert.NoError(t, err) + + keyB, err := r.createIdempotencyKey(sqlcv1.V1DurableEventLogKindRUN, newOpt(&nameB), nil) + assert.NoError(t, err) + + assert.Equal(t, keyUnset, keyA, "setting a display name must not change the durable idempotency key") + assert.Equal(t, keyA, keyB, "changing display name on replay must not change the key (child reused, first name wins, no NonDeterminismError)") +} + func TestStaleInvocationError_ImplementsError(t *testing.T) { id := uuid.New() err := &StaleInvocationError{ diff --git a/pkg/repository/task.go b/pkg/repository/task.go index 93327c0b26..67a220514d 100644 --- a/pkg/repository/task.go +++ b/pkg/repository/task.go @@ -100,6 +100,10 @@ type CreateTaskOpts struct { // (optional) the key of the event that triggered the workflow run, if there was one TriggeringEventKey *string + + // (optional) custom display name for the run. Only set for single-task (non-DAG) + // runs, where the task IS the run; DAG step tasks keep their generated names. + DisplayName *string } type ReplayTasksResult struct { @@ -1976,7 +1980,11 @@ func (r *sharedRepository) insertTasks( scheduleTimeouts[i] = stepConfig.ScheduleTimeout stepTimeouts[i] = stepConfig.Timeout.String externalIds[i] = task.ExternalId - displayNames[i] = fmt.Sprintf("%s-%d", stepConfig.ReadableId.String, unix) + if task.DisplayName != nil { + displayNames[i] = *task.DisplayName + } else { + displayNames[i] = fmt.Sprintf("%s-%d", stepConfig.ReadableId.String, unix) + } stepIndices[i] = int64(task.StepIndex) retryBackoffFactors[i] = stepConfig.RetryBackoffFactor retryMaxBackoffs[i] = stepConfig.RetryMaxBackoff diff --git a/pkg/repository/trigger.go b/pkg/repository/trigger.go index 5f33141438..ac7e93f1ed 100644 --- a/pkg/repository/trigger.go +++ b/pkg/repository/trigger.go @@ -8,6 +8,7 @@ import ( "slices" "strings" "time" + "unicode/utf8" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgtype" @@ -73,6 +74,33 @@ type TriggerTaskData struct { // (optional) overrides for desired worker labels for the task, used for routing a task to a specific worker (or worker pool) DesiredWorkerLabels []*sqlcv1.GetDesiredLabelsRow `json:"desired_worker_labels"` + + // (optional) custom display name for the run + DisplayName *string `json:"display_name"` +} + +// maxDisplayNameRunes bounds a stored run display name; over-long labels are +// truncated (never rejected) so a cosmetic label can't fail a trigger. +const maxDisplayNameRunes = 255 + +// NormalizeDisplayName normalizes a caller-supplied display name for a run. +func NormalizeDisplayName(in *string) *string { + if in == nil { + return nil + } + + trimmed := strings.TrimSpace(*in) + if trimmed == "" { + return nil + } + + // Truncate to 255 runes (not bytes) so an over-long label is stored rather + // than rejected, and a multibyte character is never split mid-rune. + if utf8.RuneCountInString(trimmed) > maxDisplayNameRunes { + trimmed = string([]rune(trimmed)[:maxDisplayNameRunes]) + } + + return &trimmed } func ProtoToDesiredWorkerLabel(key string, strValue *string, intValue *int32, required *bool, weight *int32, comparator *string) *sqlcv1.GetDesiredLabelsRow { @@ -134,6 +162,9 @@ type createDAGOpts struct { // (optional) overrides for desired worker labels, propagated to all downstream tasks DesiredWorkerLabels []*sqlcv1.GetDesiredLabelsRow + + // (optional) custom display name for the DAG run + DisplayName *string } type TriggerRepository interface { @@ -588,6 +619,7 @@ type triggerTuple struct { desiredWorkerLabels []*sqlcv1.GetDesiredLabelsRow triggeringEventExternalId *uuid.UUID triggeringEventKey *string + displayName *string } type createCoreUserEventOpts struct { @@ -1038,6 +1070,9 @@ func (r *sharedRepository) triggerWorkflows( if isDag { dagTaskOpts[tuple.externalId] = append(dagTaskOpts[tuple.externalId], opt) } else { + // single-task run: the task IS the run, so it carries the display name. + // DAG step tasks keep their generated names (the DAG row is named instead). + opt.DisplayName = tuple.displayName nonDagTaskOpts = append(nonDagTaskOpts, opt) } } @@ -1166,6 +1201,7 @@ func (r *sharedRepository) triggerWorkflows( AdditionalMetadata: tuple.additionalMetadata, ParentTaskExternalID: tuple.parentExternalId, DesiredWorkerLabels: tuple.desiredWorkerLabels, + DisplayName: tuple.displayName, }) } } @@ -1411,7 +1447,11 @@ func (r *sharedRepository) createDAGs(ctx context.Context, tx sqlcv1.DBTX, tenan for _, opt := range opts { tenantIds = append(tenantIds, tenantId) externalIds = append(externalIds, opt.ExternalId) - displayNames = append(displayNames, fmt.Sprintf("%s-%d", opt.WorkflowName, unix)) + if opt.DisplayName != nil { + displayNames = append(displayNames, *opt.DisplayName) + } else { + displayNames = append(displayNames, fmt.Sprintf("%s-%d", opt.WorkflowName, unix)) + } workflowIds = append(workflowIds, opt.WorkflowId) workflowVersionIds = append(workflowVersionIds, opt.WorkflowVersionId) @@ -2361,6 +2401,7 @@ func (r *sharedRepository) prepareTriggerFromWorkflowNames(ctx context.Context, childKey: opt.ChildKey, priority: opt.Priority, desiredWorkerLabels: opt.DesiredWorkerLabels, + displayName: opt.DisplayName, }) } } @@ -2416,6 +2457,7 @@ func (r *sharedRepository) NewTriggerTaskData( AdditionalMetadata: []byte(additionalMeta), DesiredWorkerId: desiredWorkerId, Priority: req.Priority, + DisplayName: NormalizeDisplayName(req.DisplayName), } if len(req.DesiredWorkerLabels) > 0 { diff --git a/pkg/repository/trigger_display_name_integration_test.go b/pkg/repository/trigger_display_name_integration_test.go new file mode 100644 index 0000000000..ec18517b72 --- /dev/null +++ b/pkg/repository/trigger_display_name_integration_test.go @@ -0,0 +1,364 @@ +//go:build integration + +package repository_test + +import ( + "context" + "fmt" + "strings" + "testing" + "time" + "unicode/utf8" + + "github.com/google/uuid" + "github.com/stretchr/testify/require" + + v1contracts "github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1" + "github.com/hatchet-dev/hatchet/internal/testutils" + "github.com/hatchet-dev/hatchet/pkg/config/database" + repo "github.com/hatchet-dev/hatchet/pkg/repository" + "github.com/hatchet-dev/hatchet/pkg/repository/sqlcv1" +) + +func runTriggerTest(t *testing.T, test func(conf *database.Layer) error) { + t.Helper() + // `internal/testutils.Prepare` constructs a server config and requires a RabbitMQ URL. + t.Setenv("SERVER_MSGQUEUE_RABBITMQ_URL", "amqp://user:password@localhost:5672/") + testutils.RunTestWithDatabase(t, test) +} + +// createTriggerTenant creates a fresh tenant so each test's rows are isolated. +func createTriggerTenant(t *testing.T, ctx context.Context, r repo.Repository, name string) uuid.UUID { + t.Helper() + + tenantId := uuid.New() + _, err := r.Tenant().CreateTenant(ctx, &repo.CreateTenantOpts{ + ID: &tenantId, + Name: name, + Slug: fmt.Sprintf("%s-%s", name, tenantId.String()), + }) + require.NoError(t, err) + + return tenantId +} + +// putSingleTaskWorkflow registers a single-task (non-DAG) workflow and returns its name. +func putSingleTaskWorkflow(t *testing.T, ctx context.Context, r repo.Repository, tenantId uuid.UUID, name string) string { + t.Helper() + + desc := "display-name test workflow" + _, err := r.Workflows().PutWorkflowVersion(ctx, tenantId, &repo.CreateWorkflowVersionOpts{ + Name: name, + Description: &desc, + Tasks: []repo.CreateStepOpts{ + {ReadableId: "single-step", Action: "test:run"}, + }, + }) + require.NoError(t, err) + + return name +} + +// putDagWorkflow registers a multi-step (DAG) workflow: step-two depends on step-one. +func putDagWorkflow(t *testing.T, ctx context.Context, r repo.Repository, tenantId uuid.UUID, name string) string { + t.Helper() + + desc := "display-name DAG test workflow" + _, err := r.Workflows().PutWorkflowVersion(ctx, tenantId, &repo.CreateWorkflowVersionOpts{ + Name: name, + Description: &desc, + Tasks: []repo.CreateStepOpts{ + {ReadableId: "step-one", Action: "test:run"}, + {ReadableId: "step-two", Action: "test:run", Parents: []string{"step-one"}}, + }, + }) + require.NoError(t, err) + + return name +} + +// triggerRun drives the real trigger path (NewTriggerTaskData -> PopulateExternalIds -> +// TriggerFromWorkflowNames) with the given display name and returns the created rows. +func triggerRun( + t *testing.T, + ctx context.Context, + r repo.Repository, + tenantId uuid.UUID, + workflowName string, + displayName *string, +) ([]*repo.V1TaskWithPayload, []*repo.DAGWithData) { + t.Helper() + + req := &v1contracts.TriggerWorkflowRequest{ + Name: workflowName, + Input: "{}", + DisplayName: displayName, + } + + ttd, err := r.Triggers().NewTriggerTaskData(ctx, tenantId, req, nil) + require.NoError(t, err) + + opts := []*repo.WorkflowNameTriggerOpts{{TriggerTaskData: ttd}} + + err = r.Triggers().PopulateExternalIdsForWorkflow(ctx, tenantId, opts) + require.NoError(t, err) + + tasks, dags, err := r.Triggers().TriggerFromWorkflowNames(ctx, tenantId, opts) + require.NoError(t, err) + + return tasks, dags +} + +// triggerRunMany drives one TriggerFromWorkflowNames call carrying a per-item display +// name for each element, mirroring run_many / bulk trigger. Returns the created tasks. +func triggerRunMany( + t *testing.T, + ctx context.Context, + r repo.Repository, + tenantId uuid.UUID, + workflowName string, + displayNames []*string, +) []*repo.V1TaskWithPayload { + t.Helper() + + opts := make([]*repo.WorkflowNameTriggerOpts, 0, len(displayNames)) + for _, dn := range displayNames { + req := &v1contracts.TriggerWorkflowRequest{ + Name: workflowName, + Input: "{}", + DisplayName: dn, + } + ttd, err := r.Triggers().NewTriggerTaskData(ctx, tenantId, req, nil) + require.NoError(t, err) + opts = append(opts, &repo.WorkflowNameTriggerOpts{TriggerTaskData: ttd}) + } + + err := r.Triggers().PopulateExternalIdsForWorkflow(ctx, tenantId, opts) + require.NoError(t, err) + + tasks, _, err := r.Triggers().TriggerFromWorkflowNames(ctx, tenantId, opts) + require.NoError(t, err) + + return tasks +} + +func strPtr(s string) *string { return &s } + +func int32Ptr(i int32) *int32 { return &i } + +// spawnChildOnce runs one non-durable child spawn round: build the trigger data with the +// parent + child index, populate external ids (which dedups on the child spawn key), and +// trigger only if the opt was not deduped. Returns the (mutated) opt and any created tasks. +func spawnChildOnce( + t *testing.T, + ctx context.Context, + r repo.Repository, + tenantId uuid.UUID, + childWorkflowName string, + parent *sqlcv1.FlattenExternalIdsRow, + childIndex int32, + displayName *string, +) (*repo.WorkflowNameTriggerOpts, []*repo.V1TaskWithPayload) { + t.Helper() + + req := &v1contracts.TriggerWorkflowRequest{ + Name: childWorkflowName, + Input: "{}", + DisplayName: displayName, + ChildIndex: int32Ptr(childIndex), + } + + ttd, err := r.Triggers().NewTriggerTaskData(ctx, tenantId, req, parent) + require.NoError(t, err) + + opt := &repo.WorkflowNameTriggerOpts{TriggerTaskData: ttd} + opts := []*repo.WorkflowNameTriggerOpts{opt} + + err = r.Triggers().PopulateExternalIdsForWorkflow(ctx, tenantId, opts) + require.NoError(t, err) + + if opt.ShouldSkip { + return opt, nil + } + + tasks, _, err := r.Triggers().TriggerFromWorkflowNames(ctx, tenantId, opts) + require.NoError(t, err) + + return opt, tasks +} + +func TestTriggerDisplayName_KeepsFirstNameOnChildReTrigger(t *testing.T) { + runTriggerTest(t, func(conf *database.Layer) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + r := conf.V1 + tenantId := createTriggerTenant(t, ctx, r, "dn-child") + + // A real parent run to spawn children from. + parentWf := putSingleTaskWorkflow(t, ctx, r, tenantId, "dn-child-parent") + parentTasks, _ := triggerRun(t, ctx, r, tenantId, parentWf, strPtr("Parent")) + require.Len(t, parentTasks, 1) + parent := parentTasks[0] + + parentRow := &sqlcv1.FlattenExternalIdsRow{ + ID: parent.ID, + InsertedAt: parent.InsertedAt, + ExternalID: parent.ExternalID, + WorkflowRunID: parent.WorkflowRunID, + } + + childWf := putSingleTaskWorkflow(t, ctx, r, tenantId, "dn-child-wf") + + // First spawn: child index 0, display name "A" -> creates the child run. + firstOpt, firstTasks := spawnChildOnce(t, ctx, r, tenantId, childWf, parentRow, 0, strPtr("A")) + require.False(t, firstOpt.ShouldSkip, "first spawn is not deduped") + require.Len(t, firstTasks, 1) + require.Equal(t, "A", firstTasks[0].DisplayName) + firstChildId := firstOpt.ExternalId + + // Second spawn: SAME (parent, childIndex, childKey) but display name "B". + secondOpt, secondTasks := spawnChildOnce(t, ctx, r, tenantId, childWf, parentRow, 0, strPtr("B")) + require.True(t, secondOpt.ShouldSkip, + "re-trigger with same (parent, childIndex, childKey) is deduped; display name is not part of the key") + require.Equal(t, firstChildId, secondOpt.ExternalId, "reuses the first child's external id") + require.Nil(t, secondTasks, "no new run is created on re-trigger") + + // The existing child run keeps its original name "A" (never rewritten to "B"). + var storedName string + err := conf.Pool.QueryRow(ctx, + `SELECT display_name FROM v1_task WHERE tenant_id = $1 AND external_id = $2`, + tenantId, firstChildId, + ).Scan(&storedName) + require.NoError(t, err) + require.Equal(t, "A", storedName, "first display name wins on re-trigger") + + return nil + }) +} + +func TestTriggerDisplayName_NamesSingleTaskRun(t *testing.T) { + runTriggerTest(t, func(conf *database.Layer) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + r := conf.V1 + tenantId := createTriggerTenant(t, ctx, r, "dn-single") + workflowName := putSingleTaskWorkflow(t, ctx, r, tenantId, "dn-single-wf") + + tasks, dags := triggerRun(t, ctx, r, tenantId, workflowName, strPtr("Acme Corp")) + + require.Len(t, dags, 0, "single-task workflow creates no DAG") + require.Len(t, tasks, 1) + require.Equal(t, "Acme Corp", tasks[0].DisplayName, "the task IS the run, so it carries the display name") + + return nil + }) +} + +func TestTriggerDisplayName_NamesDagRunNotSteps(t *testing.T) { + runTriggerTest(t, func(conf *database.Layer) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + r := conf.V1 + tenantId := createTriggerTenant(t, ctx, r, "dn-dag") + workflowName := putDagWorkflow(t, ctx, r, tenantId, "dn-dag-wf") + + tasks, dags := triggerRun(t, ctx, r, tenantId, workflowName, strPtr("Acme Corp")) + + require.Len(t, dags, 1, "multi-step workflow creates a DAG") + require.Equal(t, "Acme Corp", dags[0].DisplayName, "the DAG row carries the display name") + + for _, task := range tasks { + require.Regexp(t, `^step-(one|two)-\d+$`, task.DisplayName, + "DAG step tasks keep their generated - names") + } + + return nil + }) +} + +func TestTriggerDisplayName_FallsBackWhenNil(t *testing.T) { + runTriggerTest(t, func(conf *database.Layer) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + r := conf.V1 + tenantId := createTriggerTenant(t, ctx, r, "dn-nil") + workflowName := putSingleTaskWorkflow(t, ctx, r, tenantId, "dn-nil-wf") + + tasks, _ := triggerRun(t, ctx, r, tenantId, workflowName, nil) + + require.Len(t, tasks, 1) + require.Regexp(t, `^single-step-\d+$`, tasks[0].DisplayName, + "omitting display name preserves the generated - label") + + return nil + }) +} + +func TestTriggerDisplayName_TreatsWhitespaceAsUnset(t *testing.T) { + runTriggerTest(t, func(conf *database.Layer) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + r := conf.V1 + tenantId := createTriggerTenant(t, ctx, r, "dn-ws") + workflowName := putSingleTaskWorkflow(t, ctx, r, tenantId, "dn-ws-wf") + + tasks, _ := triggerRun(t, ctx, r, tenantId, workflowName, strPtr(" ")) + + require.Len(t, tasks, 1) + require.Regexp(t, `^single-step-\d+$`, tasks[0].DisplayName, + "whitespace-only display name is treated as unset") + + return nil + }) +} + +func TestTriggerDisplayName_TruncatesTo255Runes(t *testing.T) { + runTriggerTest(t, func(conf *database.Layer) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + r := conf.V1 + tenantId := createTriggerTenant(t, ctx, r, "dn-trunc") + workflowName := putSingleTaskWorkflow(t, ctx, r, tenantId, "dn-trunc-wf") + + // "世" is a 3-byte rune; 300 of them would split mid-rune under byte truncation. + long := strings.Repeat("世", 300) + tasks, _ := triggerRun(t, ctx, r, tenantId, workflowName, strPtr(long)) + + require.Len(t, tasks, 1) + require.Equal(t, 255, utf8.RuneCountInString(tasks[0].DisplayName), + "stored display name is truncated to 255 runes") + require.True(t, utf8.ValidString(tasks[0].DisplayName), "no multibyte rune was split") + + return nil + }) +} + +func TestTriggerDisplayName_DistinctNamePerRunMany(t *testing.T) { + runTriggerTest(t, func(conf *database.Layer) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + r := conf.V1 + tenantId := createTriggerTenant(t, ctx, r, "dn-many") + workflowName := putSingleTaskWorkflow(t, ctx, r, tenantId, "dn-many-wf") + + tasks := triggerRunMany(t, ctx, r, tenantId, workflowName, + []*string{strPtr("Alpha"), strPtr("Bravo"), strPtr("Charlie")}) + + require.Len(t, tasks, 3) + names := map[string]bool{} + for _, task := range tasks { + names[task.DisplayName] = true + } + require.Equal(t, map[string]bool{"Alpha": true, "Bravo": true, "Charlie": true}, names, + "each run_many item carries its own display name") + + return nil + }) +} diff --git a/pkg/repository/trigger_test.go b/pkg/repository/trigger_test.go index c0294b0f70..ca076b6792 100644 --- a/pkg/repository/trigger_test.go +++ b/pkg/repository/trigger_test.go @@ -3,7 +3,9 @@ package repository import ( "encoding/hex" "encoding/json" + "strings" "testing" + "unicode/utf8" "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -43,6 +45,39 @@ func Test_cleanAdditionalMetadataTableTest(t *testing.T) { } } +func Test_NormalizeDisplayName_returns_trimmed_value(t *testing.T) { + in := "Acme Corp" + + got := NormalizeDisplayName(&in) + + require.NotNil(t, got) + assert.Equal(t, "Acme Corp", *got) +} + +func Test_NormalizeDisplayName_returns_nil_for_nil(t *testing.T) { + assert.Nil(t, NormalizeDisplayName(nil)) +} + +func Test_NormalizeDisplayName_returns_nil_for_whitespace(t *testing.T) { + empty := "" + assert.Nil(t, NormalizeDisplayName(&empty)) + + spaces := " \t\n " + assert.Nil(t, NormalizeDisplayName(&spaces)) +} + +func Test_NormalizeDisplayName_truncates_by_rune_not_byte(t *testing.T) { + // "世" is 3 bytes; 300 of them is 900 bytes. Byte-truncation would split a + // multibyte rune, so this proves the truncation is rune-safe. + in := strings.Repeat("世", 300) + + got := NormalizeDisplayName(&in) + + require.NotNil(t, got) + assert.Equal(t, 255, utf8.RuneCountInString(*got), "truncated to 255 runes") + assert.True(t, utf8.ValidString(*got), "no multibyte rune was split") +} + func Test_ensureTraceparent_creates_when_absent(t *testing.T) { wfRunID := uuid.New() meta := []byte(`{"key":"value"}`) diff --git a/pkg/worker/context.go b/pkg/worker/context.go index dace28405a..f068d6dd98 100644 --- a/pkg/worker/context.go +++ b/pkg/worker/context.go @@ -597,6 +597,7 @@ type SpawnWorkflowOpts struct { AdditionalMetadata *map[string]string Priority *int32 DesiredWorkerLabels map[string]*types.DesiredWorkerLabel + DisplayName *string } func (h *hatchetContext) saveOrLoadListener() (*client.WorkflowRunsListener, error) { @@ -675,6 +676,7 @@ func (h *hatchetContext) SpawnWorkflow(workflowName string, input any, opts *Spa AdditionalMetadata: opts.AdditionalMetadata, Priority: opts.Priority, DesiredWorkerLabels: opts.DesiredWorkerLabels, + DisplayName: opts.DisplayName, }, ) @@ -694,6 +696,7 @@ type SpawnWorkflowsOpts struct { Sticky *bool AdditionalMetadata *map[string]string DesiredWorkerLabels map[string]*types.DesiredWorkerLabel + DisplayName *string } // Deprecated: SpawnWorkflows is an internal method used by the new Go SDK. @@ -743,6 +746,7 @@ func (h *hatchetContext) SpawnWorkflows(childWorkflows []*SpawnWorkflowsOpts) ([ DesiredWorkerId: desiredWorker, AdditionalMetadata: c.AdditionalMetadata, DesiredWorkerLabels: c.DesiredWorkerLabels, + DisplayName: c.DisplayName, }, } } diff --git a/sdks/go/client.go b/sdks/go/client.go index f45b730bf3..e0302f08ef 100644 --- a/sdks/go/client.go +++ b/sdks/go/client.go @@ -946,6 +946,9 @@ func (c *Client) runWorkflowInternal(ctx context.Context, otelCtx context.Contex if runOpts.DesiredWorkerLabels != nil { v0Opts = append(v0Opts, v0Client.WithDesiredWorkerLabels(runOpts.DesiredWorkerLabels)) } + if runOpts.DisplayName != nil { + v0Opts = append(v0Opts, v0Client.WithDisplayName(*runOpts.DisplayName)) + } var v0Workflow *v0Client.Workflow var err error @@ -974,6 +977,7 @@ func (c *Client) runWorkflowInternal(ctx context.Context, otelCtx context.Contex Priority: priority, AdditionalMetadata: additionalMetadata, DesiredWorkerLabels: runOpts.DesiredWorkerLabels, + DisplayName: runOpts.DisplayName, }) } else { v0Workflow, err = c.legacyClient.Admin().RunWorkflow(workflowName, input, v0Opts...) diff --git a/sdks/go/display_name_test.go b/sdks/go/display_name_test.go new file mode 100644 index 0000000000..d1b869090c --- /dev/null +++ b/sdks/go/display_name_test.go @@ -0,0 +1,27 @@ +package hatchet + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestWithRunDisplayName_setsRunOpt(t *testing.T) { + opts := &runOpts{} + + WithRunDisplayName("Acme Corp")(opts) + + require.NotNil(t, opts.DisplayName) + assert.Equal(t, "Acme Corp", *opts.DisplayName) +} + +func TestRunOpts_displayNameUnsetByDefault(t *testing.T) { + opts := &runOpts{} + + for _, opt := range []RunOptFunc{WithRunKey("k"), WithRunSticky(true)} { + opt(opts) + } + + assert.Nil(t, opts.DisplayName, "display name stays unset unless WithRunDisplayName is used") +} diff --git a/sdks/go/durable_child.go b/sdks/go/durable_child.go index f3620f5a11..16fec501ed 100644 --- a/sdks/go/durable_child.go +++ b/sdks/go/durable_child.go @@ -200,6 +200,7 @@ func durableChildWorkflowOpts( AdditionalMetadata: runOpts.AdditionalMetadata, Priority: priority, DesiredWorkerLabels: runOpts.DesiredWorkerLabels, + DisplayName: runOpts.DisplayName, }, nil } diff --git a/sdks/go/workflow.go b/sdks/go/workflow.go index c018f95195..a97d12c2c0 100644 --- a/sdks/go/workflow.go +++ b/sdks/go/workflow.go @@ -59,6 +59,7 @@ type runOpts struct { Sticky *bool Key *string DesiredWorkerLabels map[string]*DesiredWorkerLabel + DisplayName *string } type RunOptFunc func(*runOpts) @@ -91,6 +92,14 @@ func WithRunKey(key string) RunOptFunc { } } +// WithRunDisplayName sets a custom display name for the workflow run. The engine +// trims and truncates it; an empty/whitespace value falls back to the generated name. +func WithRunDisplayName(displayName string) RunOptFunc { + return func(opts *runOpts) { + opts.DisplayName = &displayName + } +} + // WithDesiredWorkerLabels sets desired worker labels for routing the workflow run to specific workers. func WithDesiredWorkerLabels(labels map[string]*DesiredWorkerLabel) RunOptFunc { return func(opts *runOpts) { @@ -698,6 +707,10 @@ func (w *Workflow) runWorkflowInternal(ctx context.Context, otelCtx context.Cont v0Opts = append(v0Opts, v0Client.WithDesiredWorkerLabels(runOpts.DesiredWorkerLabels)) } + if runOpts.DisplayName != nil { + v0Opts = append(v0Opts, v0Client.WithDisplayName(*runOpts.DisplayName)) + } + var v0Workflow *v0Client.Workflow var err error @@ -720,6 +733,7 @@ func (w *Workflow) runWorkflowInternal(ctx context.Context, otelCtx context.Cont Priority: priority, AdditionalMetadata: runOpts.AdditionalMetadata, DesiredWorkerLabels: runOpts.DesiredWorkerLabels, + DisplayName: runOpts.DisplayName, }) } else { v0Workflow, err = w.v0Client.Admin().RunWorkflow(w.declaration.Name(), input, v0Opts...) diff --git a/sdks/python/CHANGELOG.md b/sdks/python/CHANGELOG.md index 7fba72574e..4a07f374b2 100644 --- a/sdks/python/CHANGELOG.md +++ b/sdks/python/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to Hatchet's Python SDK will be documented in this changelog The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +- Added a `display_name` option to set a custom, human-readable name on a run at trigger time. It is accepted as a direct keyword argument on every run surface (`run`, `run_no_wait`, `aio_run`, `aio_run_no_wait`, per-item via `create_bulk_run_item` for `run_many`, and child spawns) and on `TriggerWorkflowOptions`. Single-task runs carry the name on the task; multi-step DAG runs carry it on the DAG (the DAG's step tasks keep their generated names). Empty or whitespace-only values fall back to the generated `-` name, and names longer than 255 characters are stored truncated rather than rejected ([#4259](https://github.com/hatchet-dev/hatchet/issues/4259)). + ## [1.33.17] - 2026-07-07 ### Fixed diff --git a/sdks/python/hatchet_sdk/clients/admin.py b/sdks/python/hatchet_sdk/clients/admin.py index be15f0f3a5..900b20f08d 100644 --- a/sdks/python/hatchet_sdk/clients/admin.py +++ b/sdks/python/hatchet_sdk/clients/admin.py @@ -164,6 +164,7 @@ class TriggerWorkflowRequest(BaseModel): desired_worker_label: ( dict[str, DesiredWorkerLabel] | list[DesiredWorkerLabel] | None ) = None + display_name: str | None = None @field_validator("additional_metadata", mode="before") @classmethod @@ -219,6 +220,7 @@ def _prepare_workflow_request( desired_worker_id=_options.desired_worker_id, priority=_options.priority, desired_worker_labels=desired_worker_labels, + display_name=_options.display_name, ) def _parse_schedule(self, schedule: datetime) -> timestamp_pb2.Timestamp: @@ -395,6 +397,7 @@ def _create_workflow_run_request( sticky=options.sticky, key=options.key, desired_worker_label=options.desired_worker_label, + display_name=options.display_name, ) namespace = options.namespace or self.namespace diff --git a/sdks/python/hatchet_sdk/contracts/v1/shared/trigger_pb2.py b/sdks/python/hatchet_sdk/contracts/v1/shared/trigger_pb2.py index a1e6b14f14..e568e7c308 100644 --- a/sdks/python/hatchet_sdk/contracts/v1/shared/trigger_pb2.py +++ b/sdks/python/hatchet_sdk/contracts/v1/shared/trigger_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: v1/shared/trigger.proto -# Protobuf Python Version: 6.31.1 +# Protobuf Python Version: 6.33.5 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -12,8 +12,8 @@ _runtime_version.ValidateProtobufRuntimeVersion( _runtime_version.Domain.PUBLIC, 6, - 31, - 1, + 33, + 5, '', 'v1/shared/trigger.proto' ) @@ -24,7 +24,7 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17v1/shared/trigger.proto\x12\x02v1\"\xe8\x01\n\x13\x44\x65siredWorkerLabels\x12\x16\n\tstr_value\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x16\n\tint_value\x18\x02 \x01(\x05H\x01\x88\x01\x01\x12\x15\n\x08required\x18\x03 \x01(\x08H\x02\x88\x01\x01\x12\x32\n\ncomparator\x18\x04 \x01(\x0e\x32\x19.v1.WorkerLabelComparatorH\x03\x88\x01\x01\x12\x13\n\x06weight\x18\x05 \x01(\x05H\x04\x88\x01\x01\x42\x0c\n\n_str_valueB\x0c\n\n_int_valueB\x0b\n\t_requiredB\r\n\x0b_comparatorB\t\n\x07_weight\"\xb2\x04\n\x16TriggerWorkflowRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\t\x12\x16\n\tparent_id\x18\x03 \x01(\tH\x00\x88\x01\x01\x12(\n\x1bparent_task_run_external_id\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0b\x63hild_index\x18\x05 \x01(\x05H\x02\x88\x01\x01\x12\x16\n\tchild_key\x18\x06 \x01(\tH\x03\x88\x01\x01\x12 \n\x13\x61\x64\x64itional_metadata\x18\x07 \x01(\tH\x04\x88\x01\x01\x12\x1e\n\x11\x64\x65sired_worker_id\x18\x08 \x01(\tH\x05\x88\x01\x01\x12\x15\n\x08priority\x18\t \x01(\x05H\x06\x88\x01\x01\x12R\n\x15\x64\x65sired_worker_labels\x18\n \x03(\x0b\x32\x33.v1.TriggerWorkflowRequest.DesiredWorkerLabelsEntry\x1aS\n\x18\x44\x65siredWorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x42\x0c\n\n_parent_idB\x1e\n\x1c_parent_task_run_external_idB\x0e\n\x0c_child_indexB\x0c\n\n_child_keyB\x16\n\x14_additional_metadataB\x14\n\x12_desired_worker_idB\x0b\n\t_priority*\x85\x01\n\x15WorkerLabelComparator\x12\t\n\x05\x45QUAL\x10\x00\x12\r\n\tNOT_EQUAL\x10\x01\x12\x10\n\x0cGREATER_THAN\x10\x02\x12\x19\n\x15GREATER_THAN_OR_EQUAL\x10\x03\x12\r\n\tLESS_THAN\x10\x04\x12\x16\n\x12LESS_THAN_OR_EQUAL\x10\x05\x42\x42Z@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1b\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17v1/shared/trigger.proto\x12\x02v1\"\xe8\x01\n\x13\x44\x65siredWorkerLabels\x12\x16\n\tstr_value\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x16\n\tint_value\x18\x02 \x01(\x05H\x01\x88\x01\x01\x12\x15\n\x08required\x18\x03 \x01(\x08H\x02\x88\x01\x01\x12\x32\n\ncomparator\x18\x04 \x01(\x0e\x32\x19.v1.WorkerLabelComparatorH\x03\x88\x01\x01\x12\x13\n\x06weight\x18\x05 \x01(\x05H\x04\x88\x01\x01\x42\x0c\n\n_str_valueB\x0c\n\n_int_valueB\x0b\n\t_requiredB\r\n\x0b_comparatorB\t\n\x07_weight\"\xde\x04\n\x16TriggerWorkflowRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\t\x12\x16\n\tparent_id\x18\x03 \x01(\tH\x00\x88\x01\x01\x12(\n\x1bparent_task_run_external_id\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0b\x63hild_index\x18\x05 \x01(\x05H\x02\x88\x01\x01\x12\x16\n\tchild_key\x18\x06 \x01(\tH\x03\x88\x01\x01\x12 \n\x13\x61\x64\x64itional_metadata\x18\x07 \x01(\tH\x04\x88\x01\x01\x12\x1e\n\x11\x64\x65sired_worker_id\x18\x08 \x01(\tH\x05\x88\x01\x01\x12\x15\n\x08priority\x18\t \x01(\x05H\x06\x88\x01\x01\x12R\n\x15\x64\x65sired_worker_labels\x18\n \x03(\x0b\x32\x33.v1.TriggerWorkflowRequest.DesiredWorkerLabelsEntry\x12\x19\n\x0c\x64isplay_name\x18\x0b \x01(\tH\x07\x88\x01\x01\x1aS\n\x18\x44\x65siredWorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x42\x0c\n\n_parent_idB\x1e\n\x1c_parent_task_run_external_idB\x0e\n\x0c_child_indexB\x0c\n\n_child_keyB\x16\n\x14_additional_metadataB\x14\n\x12_desired_worker_idB\x0b\n\t_priorityB\x0f\n\r_display_name*\x85\x01\n\x15WorkerLabelComparator\x12\t\n\x05\x45QUAL\x10\x00\x12\r\n\tNOT_EQUAL\x10\x01\x12\x10\n\x0cGREATER_THAN\x10\x02\x12\x19\n\x15GREATER_THAN_OR_EQUAL\x10\x03\x12\r\n\tLESS_THAN\x10\x04\x12\x16\n\x12LESS_THAN_OR_EQUAL\x10\x05\x42\x42Z@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -34,12 +34,12 @@ _globals['DESCRIPTOR']._serialized_options = b'Z@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1' _globals['_TRIGGERWORKFLOWREQUEST_DESIREDWORKERLABELSENTRY']._loaded_options = None _globals['_TRIGGERWORKFLOWREQUEST_DESIREDWORKERLABELSENTRY']._serialized_options = b'8\001' - _globals['_WORKERLABELCOMPARATOR']._serialized_start=832 - _globals['_WORKERLABELCOMPARATOR']._serialized_end=965 + _globals['_WORKERLABELCOMPARATOR']._serialized_start=876 + _globals['_WORKERLABELCOMPARATOR']._serialized_end=1009 _globals['_DESIREDWORKERLABELS']._serialized_start=32 _globals['_DESIREDWORKERLABELS']._serialized_end=264 _globals['_TRIGGERWORKFLOWREQUEST']._serialized_start=267 - _globals['_TRIGGERWORKFLOWREQUEST']._serialized_end=829 - _globals['_TRIGGERWORKFLOWREQUEST_DESIREDWORKERLABELSENTRY']._serialized_start=611 - _globals['_TRIGGERWORKFLOWREQUEST_DESIREDWORKERLABELSENTRY']._serialized_end=694 + _globals['_TRIGGERWORKFLOWREQUEST']._serialized_end=873 + _globals['_TRIGGERWORKFLOWREQUEST_DESIREDWORKERLABELSENTRY']._serialized_start=638 + _globals['_TRIGGERWORKFLOWREQUEST_DESIREDWORKERLABELSENTRY']._serialized_end=721 # @@protoc_insertion_point(module_scope) diff --git a/sdks/python/hatchet_sdk/contracts/v1/shared/trigger_pb2.pyi b/sdks/python/hatchet_sdk/contracts/v1/shared/trigger_pb2.pyi index 28aefdcb4b..852f136210 100644 --- a/sdks/python/hatchet_sdk/contracts/v1/shared/trigger_pb2.pyi +++ b/sdks/python/hatchet_sdk/contracts/v1/shared/trigger_pb2.pyi @@ -34,10 +34,10 @@ class DesiredWorkerLabels(_message.Message): required: bool comparator: WorkerLabelComparator weight: int - def __init__(self, str_value: _Optional[str] = ..., int_value: _Optional[int] = ..., required: bool = ..., comparator: _Optional[_Union[WorkerLabelComparator, str]] = ..., weight: _Optional[int] = ...) -> None: ... + def __init__(self, str_value: _Optional[str] = ..., int_value: _Optional[int] = ..., required: _Optional[bool] = ..., comparator: _Optional[_Union[WorkerLabelComparator, str]] = ..., weight: _Optional[int] = ...) -> None: ... class TriggerWorkflowRequest(_message.Message): - __slots__ = ("name", "input", "parent_id", "parent_task_run_external_id", "child_index", "child_key", "additional_metadata", "desired_worker_id", "priority", "desired_worker_labels") + __slots__ = ("name", "input", "parent_id", "parent_task_run_external_id", "child_index", "child_key", "additional_metadata", "desired_worker_id", "priority", "desired_worker_labels", "display_name") class DesiredWorkerLabelsEntry(_message.Message): __slots__ = ("key", "value") KEY_FIELD_NUMBER: _ClassVar[int] @@ -55,6 +55,7 @@ class TriggerWorkflowRequest(_message.Message): DESIRED_WORKER_ID_FIELD_NUMBER: _ClassVar[int] PRIORITY_FIELD_NUMBER: _ClassVar[int] DESIRED_WORKER_LABELS_FIELD_NUMBER: _ClassVar[int] + DISPLAY_NAME_FIELD_NUMBER: _ClassVar[int] name: str input: str parent_id: str @@ -65,4 +66,5 @@ class TriggerWorkflowRequest(_message.Message): desired_worker_id: str priority: int desired_worker_labels: _containers.MessageMap[str, DesiredWorkerLabels] - def __init__(self, name: _Optional[str] = ..., input: _Optional[str] = ..., parent_id: _Optional[str] = ..., parent_task_run_external_id: _Optional[str] = ..., child_index: _Optional[int] = ..., child_key: _Optional[str] = ..., additional_metadata: _Optional[str] = ..., desired_worker_id: _Optional[str] = ..., priority: _Optional[int] = ..., desired_worker_labels: _Optional[_Mapping[str, DesiredWorkerLabels]] = ...) -> None: ... + display_name: str + def __init__(self, name: _Optional[str] = ..., input: _Optional[str] = ..., parent_id: _Optional[str] = ..., parent_task_run_external_id: _Optional[str] = ..., child_index: _Optional[int] = ..., child_key: _Optional[str] = ..., additional_metadata: _Optional[str] = ..., desired_worker_id: _Optional[str] = ..., priority: _Optional[int] = ..., desired_worker_labels: _Optional[_Mapping[str, DesiredWorkerLabels]] = ..., display_name: _Optional[str] = ...) -> None: ... diff --git a/sdks/python/hatchet_sdk/contracts/v1/workflows_pb2.py b/sdks/python/hatchet_sdk/contracts/v1/workflows_pb2.py index 3a9ab133c1..d04a10a724 100644 --- a/sdks/python/hatchet_sdk/contracts/v1/workflows_pb2.py +++ b/sdks/python/hatchet_sdk/contracts/v1/workflows_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: v1/workflows.proto -# Protobuf Python Version: 6.31.1 +# Protobuf Python Version: 6.33.5 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -12,8 +12,8 @@ _runtime_version.ValidateProtobufRuntimeVersion( _runtime_version.Domain.PUBLIC, 6, - 31, - 1, + 33, + 5, '', 'v1/workflows.proto' ) @@ -27,7 +27,7 @@ from hatchet_sdk.contracts.v1.shared import trigger_pb2 as v1_dot_shared_dot_trigger__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12v1/workflows.proto\x12\x02v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x19v1/shared/condition.proto\x1a\x17v1/shared/trigger.proto\"[\n\x12\x43\x61ncelTasksRequest\x12\x14\n\x0c\x65xternal_ids\x18\x01 \x03(\t\x12$\n\x06\x66ilter\x18\x02 \x01(\x0b\x32\x0f.v1.TasksFilterH\x00\x88\x01\x01\x42\t\n\x07_filter\"[\n\x12ReplayTasksRequest\x12\x14\n\x0c\x65xternal_ids\x18\x01 \x03(\t\x12$\n\x06\x66ilter\x18\x02 \x01(\x0b\x32\x0f.v1.TasksFilterH\x00\x88\x01\x01\x42\t\n\x07_filter\"\xb7\x01\n\x0bTasksFilter\x12\x10\n\x08statuses\x18\x01 \x03(\t\x12)\n\x05since\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\x05until\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x88\x01\x01\x12\x14\n\x0cworkflow_ids\x18\x04 \x03(\t\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x05 \x03(\tB\x08\n\x06_until\".\n\x13\x43\x61ncelTasksResponse\x12\x17\n\x0f\x63\x61ncelled_tasks\x18\x01 \x03(\t\"-\n\x13ReplayTasksResponse\x12\x16\n\x0ereplayed_tasks\x18\x01 \x03(\t\"\xae\x02\n\x19TriggerWorkflowRunRequest\x12\x15\n\rworkflow_name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\x0c\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x03 \x01(\x0c\x12\x15\n\x08priority\x18\x04 \x01(\x05H\x00\x88\x01\x01\x12U\n\x15\x64\x65sired_worker_labels\x18\x05 \x03(\x0b\x32\x36.v1.TriggerWorkflowRunRequest.DesiredWorkerLabelsEntry\x1aS\n\x18\x44\x65siredWorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x42\x0b\n\t_priority\"1\n\x1aTriggerWorkflowRunResponse\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"X\n\x18\x42ranchDurableTaskRequest\x12\x18\n\x10task_external_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x03\x12\x11\n\tbranch_id\x18\x03 \x01(\x03\"Y\n\x19\x42ranchDurableTaskResponse\x12\x18\n\x10task_external_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x03\x12\x11\n\tbranch_id\x18\x03 \x01(\x03\"\xac\x04\n\x1c\x43reateWorkflowVersionRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x16\n\x0e\x65vent_triggers\x18\x04 \x03(\t\x12\x15\n\rcron_triggers\x18\x05 \x03(\t\x12!\n\x05tasks\x18\x06 \x03(\x0b\x32\x12.v1.CreateTaskOpts\x12$\n\x0b\x63oncurrency\x18\x07 \x01(\x0b\x32\x0f.v1.Concurrency\x12\x17\n\ncron_input\x18\x08 \x01(\tH\x00\x88\x01\x01\x12\x30\n\x0fon_failure_task\x18\t \x01(\x0b\x32\x12.v1.CreateTaskOptsH\x01\x88\x01\x01\x12\'\n\x06sticky\x18\n \x01(\x0e\x32\x12.v1.StickyStrategyH\x02\x88\x01\x01\x12\x1d\n\x10\x64\x65\x66\x61ult_priority\x18\x0b \x01(\x05H\x03\x88\x01\x01\x12(\n\x0f\x63oncurrency_arr\x18\x0c \x03(\x0b\x32\x0f.v1.Concurrency\x12*\n\x0f\x64\x65\x66\x61ult_filters\x18\r \x03(\x0b\x32\x11.v1.DefaultFilter\x12\x1e\n\x11input_json_schema\x18\x0e \x01(\x0cH\x04\x88\x01\x01\x42\r\n\x0b_cron_inputB\x12\n\x10_on_failure_taskB\t\n\x07_stickyB\x13\n\x11_default_priorityB\x14\n\x12_input_json_schema\"T\n\rDefaultFilter\x12\x12\n\nexpression\x18\x01 \x01(\t\x12\r\n\x05scope\x18\x02 \x01(\t\x12\x14\n\x07payload\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x42\n\n\x08_payload\"\x93\x01\n\x0b\x43oncurrency\x12\x12\n\nexpression\x18\x01 \x01(\t\x12\x15\n\x08max_runs\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x39\n\x0elimit_strategy\x18\x03 \x01(\x0e\x32\x1c.v1.ConcurrencyLimitStrategyH\x01\x88\x01\x01\x42\x0b\n\t_max_runsB\x11\n\x0f_limit_strategy\"\xb7\x05\n\x0e\x43reateTaskOpts\x12\x13\n\x0breadable_id\x18\x01 \x01(\t\x12\x0e\n\x06\x61\x63tion\x18\x02 \x01(\t\x12\x0f\n\x07timeout\x18\x03 \x01(\t\x12\x0e\n\x06inputs\x18\x04 \x01(\t\x12\x0f\n\x07parents\x18\x05 \x03(\t\x12\x0f\n\x07retries\x18\x06 \x01(\x05\x12,\n\x0brate_limits\x18\x07 \x03(\x0b\x32\x17.v1.CreateTaskRateLimit\x12;\n\rworker_labels\x18\x08 \x03(\x0b\x32$.v1.CreateTaskOpts.WorkerLabelsEntry\x12\x1b\n\x0e\x62\x61\x63koff_factor\x18\t \x01(\x02H\x00\x88\x01\x01\x12 \n\x13\x62\x61\x63koff_max_seconds\x18\n \x01(\x05H\x01\x88\x01\x01\x12$\n\x0b\x63oncurrency\x18\x0b \x03(\x0b\x32\x0f.v1.Concurrency\x12+\n\nconditions\x18\x0c \x01(\x0b\x32\x12.v1.TaskConditionsH\x02\x88\x01\x01\x12\x1d\n\x10schedule_timeout\x18\r \x01(\tH\x03\x88\x01\x01\x12\x12\n\nis_durable\x18\x0e \x01(\x08\x12;\n\rslot_requests\x18\x0f \x03(\x0b\x32$.v1.CreateTaskOpts.SlotRequestsEntry\x1aL\n\x11WorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x1a\x33\n\x11SlotRequestsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x42\x11\n\x0f_backoff_factorB\x16\n\x14_backoff_max_secondsB\r\n\x0b_conditionsB\x13\n\x11_schedule_timeout\"\xfd\x01\n\x13\x43reateTaskRateLimit\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x12\n\x05units\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x15\n\x08key_expr\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x17\n\nunits_expr\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x1e\n\x11limit_values_expr\x18\x05 \x01(\tH\x03\x88\x01\x01\x12,\n\x08\x64uration\x18\x06 \x01(\x0e\x32\x15.v1.RateLimitDurationH\x04\x88\x01\x01\x42\x08\n\x06_unitsB\x0b\n\t_key_exprB\r\n\x0b_units_exprB\x14\n\x12_limit_values_exprB\x0b\n\t_duration\"@\n\x1d\x43reateWorkflowVersionResponse\x12\n\n\x02id\x18\x01 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x02 \x01(\t\"+\n\x14GetRunDetailsRequest\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"\xaa\x01\n\rTaskRunDetail\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\x12\x1d\n\x06status\x18\x02 \x01(\x0e\x32\r.v1.RunStatus\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06output\x18\x04 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x0breadable_id\x18\x05 \x01(\t\x12\x12\n\nis_evicted\x18\x06 \x01(\x08\x42\x08\n\x06_errorB\t\n\x07_output\"\x84\x02\n\x15GetRunDetailsResponse\x12\r\n\x05input\x18\x01 \x01(\x0c\x12\x1d\n\x06status\x18\x02 \x01(\x0e\x32\r.v1.RunStatus\x12:\n\ttask_runs\x18\x03 \x03(\x0b\x32\'.v1.GetRunDetailsResponse.TaskRunsEntry\x12\x0c\n\x04\x64one\x18\x04 \x01(\x08\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x05 \x01(\x0c\x12\x12\n\nis_evicted\x18\x06 \x01(\x08\x1a\x42\n\rTaskRunsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12 \n\x05value\x18\x02 \x01(\x0b\x32\x11.v1.TaskRunDetail:\x02\x38\x01*$\n\x0eStickyStrategy\x12\x08\n\x04SOFT\x10\x00\x12\x08\n\x04HARD\x10\x01*]\n\x11RateLimitDuration\x12\n\n\x06SECOND\x10\x00\x12\n\n\x06MINUTE\x10\x01\x12\x08\n\x04HOUR\x10\x02\x12\x07\n\x03\x44\x41Y\x10\x03\x12\x08\n\x04WEEK\x10\x04\x12\t\n\x05MONTH\x10\x05\x12\x08\n\x04YEAR\x10\x06*[\n\tRunStatus\x12\n\n\x06QUEUED\x10\x00\x12\x0b\n\x07RUNNING\x10\x01\x12\r\n\tCOMPLETED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\x12\r\n\tCANCELLED\x10\x04\x12\x0b\n\x07\x45VICTED\x10\x05*\x7f\n\x18\x43oncurrencyLimitStrategy\x12\x16\n\x12\x43\x41NCEL_IN_PROGRESS\x10\x00\x12\x0f\n\x0b\x44ROP_NEWEST\x10\x01\x12\x10\n\x0cQUEUE_NEWEST\x10\x02\x12\x15\n\x11GROUP_ROUND_ROBIN\x10\x03\x12\x11\n\rCANCEL_NEWEST\x10\x04\x32\xcf\x03\n\x0c\x41\x64minService\x12R\n\x0bPutWorkflow\x12 .v1.CreateWorkflowVersionRequest\x1a!.v1.CreateWorkflowVersionResponse\x12>\n\x0b\x43\x61ncelTasks\x12\x16.v1.CancelTasksRequest\x1a\x17.v1.CancelTasksResponse\x12>\n\x0bReplayTasks\x12\x16.v1.ReplayTasksRequest\x1a\x17.v1.ReplayTasksResponse\x12S\n\x12TriggerWorkflowRun\x12\x1d.v1.TriggerWorkflowRunRequest\x1a\x1e.v1.TriggerWorkflowRunResponse\x12\x44\n\rGetRunDetails\x12\x18.v1.GetRunDetailsRequest\x1a\x19.v1.GetRunDetailsResponse\x12P\n\x11\x42ranchDurableTask\x12\x1c.v1.BranchDurableTaskRequest\x1a\x1d.v1.BranchDurableTaskResponseBBZ@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1b\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12v1/workflows.proto\x12\x02v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x19v1/shared/condition.proto\x1a\x17v1/shared/trigger.proto\"[\n\x12\x43\x61ncelTasksRequest\x12\x14\n\x0c\x65xternal_ids\x18\x01 \x03(\t\x12$\n\x06\x66ilter\x18\x02 \x01(\x0b\x32\x0f.v1.TasksFilterH\x00\x88\x01\x01\x42\t\n\x07_filter\"[\n\x12ReplayTasksRequest\x12\x14\n\x0c\x65xternal_ids\x18\x01 \x03(\t\x12$\n\x06\x66ilter\x18\x02 \x01(\x0b\x32\x0f.v1.TasksFilterH\x00\x88\x01\x01\x42\t\n\x07_filter\"\xb7\x01\n\x0bTasksFilter\x12\x10\n\x08statuses\x18\x01 \x03(\t\x12)\n\x05since\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\x05until\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x88\x01\x01\x12\x14\n\x0cworkflow_ids\x18\x04 \x03(\t\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x05 \x03(\tB\x08\n\x06_until\".\n\x13\x43\x61ncelTasksResponse\x12\x17\n\x0f\x63\x61ncelled_tasks\x18\x01 \x03(\t\"-\n\x13ReplayTasksResponse\x12\x16\n\x0ereplayed_tasks\x18\x01 \x03(\t\"\xda\x02\n\x19TriggerWorkflowRunRequest\x12\x15\n\rworkflow_name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\x0c\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x03 \x01(\x0c\x12\x15\n\x08priority\x18\x04 \x01(\x05H\x00\x88\x01\x01\x12U\n\x15\x64\x65sired_worker_labels\x18\x05 \x03(\x0b\x32\x36.v1.TriggerWorkflowRunRequest.DesiredWorkerLabelsEntry\x12\x19\n\x0c\x64isplay_name\x18\x06 \x01(\tH\x01\x88\x01\x01\x1aS\n\x18\x44\x65siredWorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x42\x0b\n\t_priorityB\x0f\n\r_display_name\"1\n\x1aTriggerWorkflowRunResponse\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"X\n\x18\x42ranchDurableTaskRequest\x12\x18\n\x10task_external_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x03\x12\x11\n\tbranch_id\x18\x03 \x01(\x03\"Y\n\x19\x42ranchDurableTaskResponse\x12\x18\n\x10task_external_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x03\x12\x11\n\tbranch_id\x18\x03 \x01(\x03\"\xac\x04\n\x1c\x43reateWorkflowVersionRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x16\n\x0e\x65vent_triggers\x18\x04 \x03(\t\x12\x15\n\rcron_triggers\x18\x05 \x03(\t\x12!\n\x05tasks\x18\x06 \x03(\x0b\x32\x12.v1.CreateTaskOpts\x12$\n\x0b\x63oncurrency\x18\x07 \x01(\x0b\x32\x0f.v1.Concurrency\x12\x17\n\ncron_input\x18\x08 \x01(\tH\x00\x88\x01\x01\x12\x30\n\x0fon_failure_task\x18\t \x01(\x0b\x32\x12.v1.CreateTaskOptsH\x01\x88\x01\x01\x12\'\n\x06sticky\x18\n \x01(\x0e\x32\x12.v1.StickyStrategyH\x02\x88\x01\x01\x12\x1d\n\x10\x64\x65\x66\x61ult_priority\x18\x0b \x01(\x05H\x03\x88\x01\x01\x12(\n\x0f\x63oncurrency_arr\x18\x0c \x03(\x0b\x32\x0f.v1.Concurrency\x12*\n\x0f\x64\x65\x66\x61ult_filters\x18\r \x03(\x0b\x32\x11.v1.DefaultFilter\x12\x1e\n\x11input_json_schema\x18\x0e \x01(\x0cH\x04\x88\x01\x01\x42\r\n\x0b_cron_inputB\x12\n\x10_on_failure_taskB\t\n\x07_stickyB\x13\n\x11_default_priorityB\x14\n\x12_input_json_schema\"T\n\rDefaultFilter\x12\x12\n\nexpression\x18\x01 \x01(\t\x12\r\n\x05scope\x18\x02 \x01(\t\x12\x14\n\x07payload\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x42\n\n\x08_payload\"\x93\x01\n\x0b\x43oncurrency\x12\x12\n\nexpression\x18\x01 \x01(\t\x12\x15\n\x08max_runs\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x39\n\x0elimit_strategy\x18\x03 \x01(\x0e\x32\x1c.v1.ConcurrencyLimitStrategyH\x01\x88\x01\x01\x42\x0b\n\t_max_runsB\x11\n\x0f_limit_strategy\"\xb7\x05\n\x0e\x43reateTaskOpts\x12\x13\n\x0breadable_id\x18\x01 \x01(\t\x12\x0e\n\x06\x61\x63tion\x18\x02 \x01(\t\x12\x0f\n\x07timeout\x18\x03 \x01(\t\x12\x0e\n\x06inputs\x18\x04 \x01(\t\x12\x0f\n\x07parents\x18\x05 \x03(\t\x12\x0f\n\x07retries\x18\x06 \x01(\x05\x12,\n\x0brate_limits\x18\x07 \x03(\x0b\x32\x17.v1.CreateTaskRateLimit\x12;\n\rworker_labels\x18\x08 \x03(\x0b\x32$.v1.CreateTaskOpts.WorkerLabelsEntry\x12\x1b\n\x0e\x62\x61\x63koff_factor\x18\t \x01(\x02H\x00\x88\x01\x01\x12 \n\x13\x62\x61\x63koff_max_seconds\x18\n \x01(\x05H\x01\x88\x01\x01\x12$\n\x0b\x63oncurrency\x18\x0b \x03(\x0b\x32\x0f.v1.Concurrency\x12+\n\nconditions\x18\x0c \x01(\x0b\x32\x12.v1.TaskConditionsH\x02\x88\x01\x01\x12\x1d\n\x10schedule_timeout\x18\r \x01(\tH\x03\x88\x01\x01\x12\x12\n\nis_durable\x18\x0e \x01(\x08\x12;\n\rslot_requests\x18\x0f \x03(\x0b\x32$.v1.CreateTaskOpts.SlotRequestsEntry\x1aL\n\x11WorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x1a\x33\n\x11SlotRequestsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x42\x11\n\x0f_backoff_factorB\x16\n\x14_backoff_max_secondsB\r\n\x0b_conditionsB\x13\n\x11_schedule_timeout\"\xfd\x01\n\x13\x43reateTaskRateLimit\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x12\n\x05units\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x15\n\x08key_expr\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x17\n\nunits_expr\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x1e\n\x11limit_values_expr\x18\x05 \x01(\tH\x03\x88\x01\x01\x12,\n\x08\x64uration\x18\x06 \x01(\x0e\x32\x15.v1.RateLimitDurationH\x04\x88\x01\x01\x42\x08\n\x06_unitsB\x0b\n\t_key_exprB\r\n\x0b_units_exprB\x14\n\x12_limit_values_exprB\x0b\n\t_duration\"@\n\x1d\x43reateWorkflowVersionResponse\x12\n\n\x02id\x18\x01 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x02 \x01(\t\"+\n\x14GetRunDetailsRequest\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"\xaa\x01\n\rTaskRunDetail\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\x12\x1d\n\x06status\x18\x02 \x01(\x0e\x32\r.v1.RunStatus\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06output\x18\x04 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x0breadable_id\x18\x05 \x01(\t\x12\x12\n\nis_evicted\x18\x06 \x01(\x08\x42\x08\n\x06_errorB\t\n\x07_output\"\x84\x02\n\x15GetRunDetailsResponse\x12\r\n\x05input\x18\x01 \x01(\x0c\x12\x1d\n\x06status\x18\x02 \x01(\x0e\x32\r.v1.RunStatus\x12:\n\ttask_runs\x18\x03 \x03(\x0b\x32\'.v1.GetRunDetailsResponse.TaskRunsEntry\x12\x0c\n\x04\x64one\x18\x04 \x01(\x08\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x05 \x01(\x0c\x12\x12\n\nis_evicted\x18\x06 \x01(\x08\x1a\x42\n\rTaskRunsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12 \n\x05value\x18\x02 \x01(\x0b\x32\x11.v1.TaskRunDetail:\x02\x38\x01*$\n\x0eStickyStrategy\x12\x08\n\x04SOFT\x10\x00\x12\x08\n\x04HARD\x10\x01*]\n\x11RateLimitDuration\x12\n\n\x06SECOND\x10\x00\x12\n\n\x06MINUTE\x10\x01\x12\x08\n\x04HOUR\x10\x02\x12\x07\n\x03\x44\x41Y\x10\x03\x12\x08\n\x04WEEK\x10\x04\x12\t\n\x05MONTH\x10\x05\x12\x08\n\x04YEAR\x10\x06*[\n\tRunStatus\x12\n\n\x06QUEUED\x10\x00\x12\x0b\n\x07RUNNING\x10\x01\x12\r\n\tCOMPLETED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\x12\r\n\tCANCELLED\x10\x04\x12\x0b\n\x07\x45VICTED\x10\x05*\x7f\n\x18\x43oncurrencyLimitStrategy\x12\x16\n\x12\x43\x41NCEL_IN_PROGRESS\x10\x00\x12\x0f\n\x0b\x44ROP_NEWEST\x10\x01\x12\x10\n\x0cQUEUE_NEWEST\x10\x02\x12\x15\n\x11GROUP_ROUND_ROBIN\x10\x03\x12\x11\n\rCANCEL_NEWEST\x10\x04\x32\xcf\x03\n\x0c\x41\x64minService\x12R\n\x0bPutWorkflow\x12 .v1.CreateWorkflowVersionRequest\x1a!.v1.CreateWorkflowVersionResponse\x12>\n\x0b\x43\x61ncelTasks\x12\x16.v1.CancelTasksRequest\x1a\x17.v1.CancelTasksResponse\x12>\n\x0bReplayTasks\x12\x16.v1.ReplayTasksRequest\x1a\x17.v1.ReplayTasksResponse\x12S\n\x12TriggerWorkflowRun\x12\x1d.v1.TriggerWorkflowRunRequest\x1a\x1e.v1.TriggerWorkflowRunResponse\x12\x44\n\rGetRunDetails\x12\x18.v1.GetRunDetailsRequest\x1a\x19.v1.GetRunDetailsResponse\x12P\n\x11\x42ranchDurableTask\x12\x1c.v1.BranchDurableTaskRequest\x1a\x1d.v1.BranchDurableTaskResponseBBZ@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -43,14 +43,14 @@ _globals['_CREATETASKOPTS_SLOTREQUESTSENTRY']._serialized_options = b'8\001' _globals['_GETRUNDETAILSRESPONSE_TASKRUNSENTRY']._loaded_options = None _globals['_GETRUNDETAILSRESPONSE_TASKRUNSENTRY']._serialized_options = b'8\001' - _globals['_STICKYSTRATEGY']._serialized_start=3411 - _globals['_STICKYSTRATEGY']._serialized_end=3447 - _globals['_RATELIMITDURATION']._serialized_start=3449 - _globals['_RATELIMITDURATION']._serialized_end=3542 - _globals['_RUNSTATUS']._serialized_start=3544 - _globals['_RUNSTATUS']._serialized_end=3635 - _globals['_CONCURRENCYLIMITSTRATEGY']._serialized_start=3637 - _globals['_CONCURRENCYLIMITSTRATEGY']._serialized_end=3764 + _globals['_STICKYSTRATEGY']._serialized_start=3455 + _globals['_STICKYSTRATEGY']._serialized_end=3491 + _globals['_RATELIMITDURATION']._serialized_start=3493 + _globals['_RATELIMITDURATION']._serialized_end=3586 + _globals['_RUNSTATUS']._serialized_start=3588 + _globals['_RUNSTATUS']._serialized_end=3679 + _globals['_CONCURRENCYLIMITSTRATEGY']._serialized_start=3681 + _globals['_CONCURRENCYLIMITSTRATEGY']._serialized_end=3808 _globals['_CANCELTASKSREQUEST']._serialized_start=111 _globals['_CANCELTASKSREQUEST']._serialized_end=202 _globals['_REPLAYTASKSREQUEST']._serialized_start=204 @@ -62,39 +62,39 @@ _globals['_REPLAYTASKSRESPONSE']._serialized_start=531 _globals['_REPLAYTASKSRESPONSE']._serialized_end=576 _globals['_TRIGGERWORKFLOWRUNREQUEST']._serialized_start=579 - _globals['_TRIGGERWORKFLOWRUNREQUEST']._serialized_end=881 - _globals['_TRIGGERWORKFLOWRUNREQUEST_DESIREDWORKERLABELSENTRY']._serialized_start=785 - _globals['_TRIGGERWORKFLOWRUNREQUEST_DESIREDWORKERLABELSENTRY']._serialized_end=868 - _globals['_TRIGGERWORKFLOWRUNRESPONSE']._serialized_start=883 - _globals['_TRIGGERWORKFLOWRUNRESPONSE']._serialized_end=932 - _globals['_BRANCHDURABLETASKREQUEST']._serialized_start=934 - _globals['_BRANCHDURABLETASKREQUEST']._serialized_end=1022 - _globals['_BRANCHDURABLETASKRESPONSE']._serialized_start=1024 - _globals['_BRANCHDURABLETASKRESPONSE']._serialized_end=1113 - _globals['_CREATEWORKFLOWVERSIONREQUEST']._serialized_start=1116 - _globals['_CREATEWORKFLOWVERSIONREQUEST']._serialized_end=1672 - _globals['_DEFAULTFILTER']._serialized_start=1674 - _globals['_DEFAULTFILTER']._serialized_end=1758 - _globals['_CONCURRENCY']._serialized_start=1761 - _globals['_CONCURRENCY']._serialized_end=1908 - _globals['_CREATETASKOPTS']._serialized_start=1911 - _globals['_CREATETASKOPTS']._serialized_end=2606 - _globals['_CREATETASKOPTS_WORKERLABELSENTRY']._serialized_start=2398 - _globals['_CREATETASKOPTS_WORKERLABELSENTRY']._serialized_end=2474 - _globals['_CREATETASKOPTS_SLOTREQUESTSENTRY']._serialized_start=2476 - _globals['_CREATETASKOPTS_SLOTREQUESTSENTRY']._serialized_end=2527 - _globals['_CREATETASKRATELIMIT']._serialized_start=2609 - _globals['_CREATETASKRATELIMIT']._serialized_end=2862 - _globals['_CREATEWORKFLOWVERSIONRESPONSE']._serialized_start=2864 - _globals['_CREATEWORKFLOWVERSIONRESPONSE']._serialized_end=2928 - _globals['_GETRUNDETAILSREQUEST']._serialized_start=2930 - _globals['_GETRUNDETAILSREQUEST']._serialized_end=2973 - _globals['_TASKRUNDETAIL']._serialized_start=2976 - _globals['_TASKRUNDETAIL']._serialized_end=3146 - _globals['_GETRUNDETAILSRESPONSE']._serialized_start=3149 - _globals['_GETRUNDETAILSRESPONSE']._serialized_end=3409 - _globals['_GETRUNDETAILSRESPONSE_TASKRUNSENTRY']._serialized_start=3343 - _globals['_GETRUNDETAILSRESPONSE_TASKRUNSENTRY']._serialized_end=3409 - _globals['_ADMINSERVICE']._serialized_start=3767 - _globals['_ADMINSERVICE']._serialized_end=4230 + _globals['_TRIGGERWORKFLOWRUNREQUEST']._serialized_end=925 + _globals['_TRIGGERWORKFLOWRUNREQUEST_DESIREDWORKERLABELSENTRY']._serialized_start=812 + _globals['_TRIGGERWORKFLOWRUNREQUEST_DESIREDWORKERLABELSENTRY']._serialized_end=895 + _globals['_TRIGGERWORKFLOWRUNRESPONSE']._serialized_start=927 + _globals['_TRIGGERWORKFLOWRUNRESPONSE']._serialized_end=976 + _globals['_BRANCHDURABLETASKREQUEST']._serialized_start=978 + _globals['_BRANCHDURABLETASKREQUEST']._serialized_end=1066 + _globals['_BRANCHDURABLETASKRESPONSE']._serialized_start=1068 + _globals['_BRANCHDURABLETASKRESPONSE']._serialized_end=1157 + _globals['_CREATEWORKFLOWVERSIONREQUEST']._serialized_start=1160 + _globals['_CREATEWORKFLOWVERSIONREQUEST']._serialized_end=1716 + _globals['_DEFAULTFILTER']._serialized_start=1718 + _globals['_DEFAULTFILTER']._serialized_end=1802 + _globals['_CONCURRENCY']._serialized_start=1805 + _globals['_CONCURRENCY']._serialized_end=1952 + _globals['_CREATETASKOPTS']._serialized_start=1955 + _globals['_CREATETASKOPTS']._serialized_end=2650 + _globals['_CREATETASKOPTS_WORKERLABELSENTRY']._serialized_start=2442 + _globals['_CREATETASKOPTS_WORKERLABELSENTRY']._serialized_end=2518 + _globals['_CREATETASKOPTS_SLOTREQUESTSENTRY']._serialized_start=2520 + _globals['_CREATETASKOPTS_SLOTREQUESTSENTRY']._serialized_end=2571 + _globals['_CREATETASKRATELIMIT']._serialized_start=2653 + _globals['_CREATETASKRATELIMIT']._serialized_end=2906 + _globals['_CREATEWORKFLOWVERSIONRESPONSE']._serialized_start=2908 + _globals['_CREATEWORKFLOWVERSIONRESPONSE']._serialized_end=2972 + _globals['_GETRUNDETAILSREQUEST']._serialized_start=2974 + _globals['_GETRUNDETAILSREQUEST']._serialized_end=3017 + _globals['_TASKRUNDETAIL']._serialized_start=3020 + _globals['_TASKRUNDETAIL']._serialized_end=3190 + _globals['_GETRUNDETAILSRESPONSE']._serialized_start=3193 + _globals['_GETRUNDETAILSRESPONSE']._serialized_end=3453 + _globals['_GETRUNDETAILSRESPONSE_TASKRUNSENTRY']._serialized_start=3387 + _globals['_GETRUNDETAILSRESPONSE_TASKRUNSENTRY']._serialized_end=3453 + _globals['_ADMINSERVICE']._serialized_start=3811 + _globals['_ADMINSERVICE']._serialized_end=4274 # @@protoc_insertion_point(module_scope) diff --git a/sdks/python/hatchet_sdk/contracts/v1/workflows_pb2.pyi b/sdks/python/hatchet_sdk/contracts/v1/workflows_pb2.pyi index 3015f82678..85edd9c325 100644 --- a/sdks/python/hatchet_sdk/contracts/v1/workflows_pb2.pyi +++ b/sdks/python/hatchet_sdk/contracts/v1/workflows_pb2.pyi @@ -107,7 +107,7 @@ class ReplayTasksResponse(_message.Message): def __init__(self, replayed_tasks: _Optional[_Iterable[str]] = ...) -> None: ... class TriggerWorkflowRunRequest(_message.Message): - __slots__ = ("workflow_name", "input", "additional_metadata", "priority", "desired_worker_labels") + __slots__ = ("workflow_name", "input", "additional_metadata", "priority", "desired_worker_labels", "display_name") class DesiredWorkerLabelsEntry(_message.Message): __slots__ = ("key", "value") KEY_FIELD_NUMBER: _ClassVar[int] @@ -120,12 +120,14 @@ class TriggerWorkflowRunRequest(_message.Message): ADDITIONAL_METADATA_FIELD_NUMBER: _ClassVar[int] PRIORITY_FIELD_NUMBER: _ClassVar[int] DESIRED_WORKER_LABELS_FIELD_NUMBER: _ClassVar[int] + DISPLAY_NAME_FIELD_NUMBER: _ClassVar[int] workflow_name: str input: bytes additional_metadata: bytes priority: int desired_worker_labels: _containers.MessageMap[str, _trigger_pb2.DesiredWorkerLabels] - def __init__(self, workflow_name: _Optional[str] = ..., input: _Optional[bytes] = ..., additional_metadata: _Optional[bytes] = ..., priority: _Optional[int] = ..., desired_worker_labels: _Optional[_Mapping[str, _trigger_pb2.DesiredWorkerLabels]] = ...) -> None: ... + display_name: str + def __init__(self, workflow_name: _Optional[str] = ..., input: _Optional[bytes] = ..., additional_metadata: _Optional[bytes] = ..., priority: _Optional[int] = ..., desired_worker_labels: _Optional[_Mapping[str, _trigger_pb2.DesiredWorkerLabels]] = ..., display_name: _Optional[str] = ...) -> None: ... class TriggerWorkflowRunResponse(_message.Message): __slots__ = ("external_id",) @@ -251,7 +253,7 @@ class CreateTaskOpts(_message.Message): schedule_timeout: str is_durable: bool slot_requests: _containers.ScalarMap[str, int] - def __init__(self, readable_id: _Optional[str] = ..., action: _Optional[str] = ..., timeout: _Optional[str] = ..., inputs: _Optional[str] = ..., parents: _Optional[_Iterable[str]] = ..., retries: _Optional[int] = ..., rate_limits: _Optional[_Iterable[_Union[CreateTaskRateLimit, _Mapping]]] = ..., worker_labels: _Optional[_Mapping[str, _trigger_pb2.DesiredWorkerLabels]] = ..., backoff_factor: _Optional[float] = ..., backoff_max_seconds: _Optional[int] = ..., concurrency: _Optional[_Iterable[_Union[Concurrency, _Mapping]]] = ..., conditions: _Optional[_Union[_condition_pb2.TaskConditions, _Mapping]] = ..., schedule_timeout: _Optional[str] = ..., is_durable: bool = ..., slot_requests: _Optional[_Mapping[str, int]] = ...) -> None: ... + def __init__(self, readable_id: _Optional[str] = ..., action: _Optional[str] = ..., timeout: _Optional[str] = ..., inputs: _Optional[str] = ..., parents: _Optional[_Iterable[str]] = ..., retries: _Optional[int] = ..., rate_limits: _Optional[_Iterable[_Union[CreateTaskRateLimit, _Mapping]]] = ..., worker_labels: _Optional[_Mapping[str, _trigger_pb2.DesiredWorkerLabels]] = ..., backoff_factor: _Optional[float] = ..., backoff_max_seconds: _Optional[int] = ..., concurrency: _Optional[_Iterable[_Union[Concurrency, _Mapping]]] = ..., conditions: _Optional[_Union[_condition_pb2.TaskConditions, _Mapping]] = ..., schedule_timeout: _Optional[str] = ..., is_durable: _Optional[bool] = ..., slot_requests: _Optional[_Mapping[str, int]] = ...) -> None: ... class CreateTaskRateLimit(_message.Message): __slots__ = ("key", "units", "key_expr", "units_expr", "limit_values_expr", "duration") @@ -297,7 +299,7 @@ class TaskRunDetail(_message.Message): output: bytes readable_id: str is_evicted: bool - def __init__(self, external_id: _Optional[str] = ..., status: _Optional[_Union[RunStatus, str]] = ..., error: _Optional[str] = ..., output: _Optional[bytes] = ..., readable_id: _Optional[str] = ..., is_evicted: bool = ...) -> None: ... + def __init__(self, external_id: _Optional[str] = ..., status: _Optional[_Union[RunStatus, str]] = ..., error: _Optional[str] = ..., output: _Optional[bytes] = ..., readable_id: _Optional[str] = ..., is_evicted: _Optional[bool] = ...) -> None: ... class GetRunDetailsResponse(_message.Message): __slots__ = ("input", "status", "task_runs", "done", "additional_metadata", "is_evicted") @@ -320,4 +322,4 @@ class GetRunDetailsResponse(_message.Message): done: bool additional_metadata: bytes is_evicted: bool - def __init__(self, input: _Optional[bytes] = ..., status: _Optional[_Union[RunStatus, str]] = ..., task_runs: _Optional[_Mapping[str, TaskRunDetail]] = ..., done: bool = ..., additional_metadata: _Optional[bytes] = ..., is_evicted: bool = ...) -> None: ... + def __init__(self, input: _Optional[bytes] = ..., status: _Optional[_Union[RunStatus, str]] = ..., task_runs: _Optional[_Mapping[str, TaskRunDetail]] = ..., done: _Optional[bool] = ..., additional_metadata: _Optional[bytes] = ..., is_evicted: _Optional[bool] = ...) -> None: ... diff --git a/sdks/python/hatchet_sdk/runnables/workflow.py b/sdks/python/hatchet_sdk/runnables/workflow.py index 56966f5faf..3614db5f9e 100644 --- a/sdks/python/hatchet_sdk/runnables/workflow.py +++ b/sdks/python/hatchet_sdk/runnables/workflow.py @@ -291,6 +291,7 @@ def _create_trigger_run_options_with_combined_additional_meta( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> TriggerWorkflowOptions: if options is not None: warn( @@ -306,6 +307,7 @@ def _create_trigger_run_options_with_combined_additional_meta( sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_label=desired_worker_labels, + display_name=display_name, ) options_copy = options.model_copy() options_copy.additional_metadata = self._combine_additional_metadata( @@ -381,6 +383,7 @@ def create_bulk_run_item( desired_worker_id: str | None = None, sticky: bool = False, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> WorkflowRunTriggerConfig: """ Create a bulk run item for the workflow. This is intended to be used in conjunction with the various `run_many` methods. @@ -394,6 +397,7 @@ def create_bulk_run_item( :param desired_worker_id: The ID of the desired worker to run the workflow on. :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: A `WorkflowRunTriggerConfig` object that can be used to trigger the workflow run, which you then pass into the `run_many` methods. """ @@ -408,6 +412,7 @@ def create_bulk_run_item( sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, + display_name=display_name, ), key=key, ) @@ -866,6 +871,7 @@ def run_no_wait( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> WorkflowRunRef: """ Synchronously trigger a workflow run without waiting for it to complete. @@ -879,6 +885,7 @@ def run_no_wait( :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_id: The ID of the desired worker to run the workflow on. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: A `WorkflowRunRef` object representing the reference to the workflow run. @@ -897,6 +904,7 @@ def run_no_wait( child_key=child_key, additional_metadata=additional_metadata, priority=priority, + display_name=display_name, sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, @@ -914,6 +922,7 @@ def run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> dict[str, Any]: ... @overload @@ -929,6 +938,7 @@ def run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> WorkflowRunRef: ... def run( @@ -942,6 +952,7 @@ def run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> WorkflowRunRef | dict[str, Any]: """ Run the workflow synchronously and wait for it to complete. @@ -957,6 +968,7 @@ def run( :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_id: The ID of the desired worker to run the workflow on. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: The result of the workflow execution as a dictionary, or a WorkflowRunRef if wait_for_result is False. """ @@ -972,6 +984,7 @@ def run( sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, + display_name=display_name, ), ) @@ -990,6 +1003,7 @@ async def aio_run_no_wait( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> WorkflowRunRef: """ Asynchronously trigger a workflow run without waiting for it to complete. @@ -1003,6 +1017,7 @@ async def aio_run_no_wait( :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_id: The ID of the desired worker to run the workflow on. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: A `WorkflowRunRef` object representing the reference to the workflow run. @@ -1021,6 +1036,7 @@ async def aio_run_no_wait( child_key=child_key, additional_metadata=additional_metadata, priority=priority, + display_name=display_name, sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, @@ -1038,6 +1054,7 @@ async def aio_run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> dict[str, Any]: ... @overload @@ -1053,6 +1070,7 @@ async def aio_run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> WorkflowRunRef: ... async def aio_run( @@ -1066,6 +1084,7 @@ async def aio_run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> WorkflowRunRef | dict[str, Any]: """ Run the workflow asynchronously and wait for it to complete. @@ -1081,6 +1100,7 @@ async def aio_run( :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_id: The ID of the desired worker to run the workflow on. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: The result of the workflow execution as a dictionary, or a WorkflowRunRef if wait_for_result is False. @@ -1093,6 +1113,7 @@ async def aio_run( additional_metadata=additional_metadata, priority=priority, sticky=sticky, + display_name=display_name, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, ) @@ -1822,6 +1843,7 @@ def run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> R: ... @overload @@ -1837,6 +1859,7 @@ def run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> TaskRunRef[TWorkflowInput, R]: ... def run( @@ -1850,6 +1873,7 @@ def run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> TaskRunRef[TWorkflowInput, R] | R: """ Run the workflow synchronously and wait for it to complete. @@ -1865,6 +1889,7 @@ def run( :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_id: The ID of the desired worker to run the workflow on. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: The extracted result of the workflow execution, or a TaskRunRef if wait_for_result is False. """ @@ -1876,6 +1901,7 @@ def run( child_key=child_key, additional_metadata=additional_metadata, priority=priority, + display_name=display_name, sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, @@ -1890,6 +1916,7 @@ def run( child_key=child_key, additional_metadata=additional_metadata, priority=priority, + display_name=display_name, sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, @@ -1908,6 +1935,7 @@ async def aio_run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> R: ... @overload @@ -1923,6 +1951,7 @@ async def aio_run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> TaskRunRef[TWorkflowInput, R]: ... async def aio_run( @@ -1936,6 +1965,7 @@ async def aio_run( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> TaskRunRef[TWorkflowInput, R] | R: """ Run the workflow asynchronously and wait for it to complete. @@ -1951,6 +1981,7 @@ async def aio_run( :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_id: The ID of the desired worker to run the workflow on. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: The extracted result of the workflow execution, or a TaskRunRef if wait_for_result is False. """ @@ -1963,6 +1994,7 @@ async def aio_run( child_key=child_key, additional_metadata=additional_metadata, priority=priority, + display_name=display_name, sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, @@ -1977,6 +2009,7 @@ async def aio_run( child_key=child_key, additional_metadata=additional_metadata, priority=priority, + display_name=display_name, sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, @@ -1993,6 +2026,7 @@ def run_no_wait( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> TaskRunRef[TWorkflowInput, R]: """ Trigger a workflow run without waiting for it to complete. @@ -2007,6 +2041,7 @@ def run_no_wait( :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_id: The ID of the desired worker to run the workflow on. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: A `TaskRunRef` object representing the reference to the workflow run. @@ -2025,6 +2060,7 @@ def run_no_wait( child_key=child_key, additional_metadata=additional_metadata, priority=priority, + display_name=display_name, sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, @@ -2040,6 +2076,7 @@ async def aio_run_no_wait( sticky: bool = False, desired_worker_id: str | None = None, desired_worker_labels: list[DesiredWorkerLabel] | None = None, + display_name: str | None = None, ) -> TaskRunRef[TWorkflowInput, R]: """ Asynchronously trigger a workflow run without waiting for it to complete. @@ -2053,6 +2090,7 @@ async def aio_run_no_wait( :param sticky: Whether to use sticky scheduling for the workflow run. :param desired_worker_id: The ID of the desired worker to run the workflow on. :param desired_worker_labels: A list of desired worker labels for worker affinity. + :param display_name: A custom display name for the workflow run. If not provided, a name is generated automatically. :returns: A `TaskRunRef` object representing the reference to the workflow run. @@ -2071,6 +2109,7 @@ async def aio_run_no_wait( child_key=child_key, additional_metadata=additional_metadata, priority=priority, + display_name=display_name, sticky=sticky, desired_worker_id=desired_worker_id, desired_worker_labels=desired_worker_labels, diff --git a/sdks/python/hatchet_sdk/types/trigger.py b/sdks/python/hatchet_sdk/types/trigger.py index 5ddbbb58dd..373d6aaf21 100644 --- a/sdks/python/hatchet_sdk/types/trigger.py +++ b/sdks/python/hatchet_sdk/types/trigger.py @@ -24,6 +24,7 @@ class TriggerWorkflowOptions(ScheduleTriggerWorkflowOptions): desired_worker_label: ( dict[str, DesiredWorkerLabel] | list[DesiredWorkerLabel] | None ) = None + display_name: str | None = None class WorkflowRunTriggerConfig(BaseModel): diff --git a/sdks/python/tests/unit/test_trigger_display_name.py b/sdks/python/tests/unit/test_trigger_display_name.py new file mode 100644 index 0000000000..1473ff5977 --- /dev/null +++ b/sdks/python/tests/unit/test_trigger_display_name.py @@ -0,0 +1,73 @@ +from types import SimpleNamespace + +from hatchet_sdk.clients.admin import AdminClient +from hatchet_sdk.runnables.workflow import BaseWorkflow +from hatchet_sdk.types.trigger import TriggerWorkflowOptions + + +def _admin() -> AdminClient: + # _prepare_workflow_request only uses the nested TriggerWorkflowRequest class + # attribute, so we can bypass connection setup. + return object.__new__(AdminClient) + + +def _admin_for_run() -> AdminClient: + # _create_workflow_run_request additionally reads self.namespace and + # self.config.apply_namespace; everything else comes from contextvars that + # default to None. Stub just those two so we can drive the real request path. + admin = object.__new__(AdminClient) + admin.namespace = "" + admin.config = SimpleNamespace(apply_namespace=lambda name, _ns: name) # type: ignore[assignment] + return admin + + +def test_prepare_workflow_request_maps_display_name() -> None: + req = _admin()._prepare_workflow_request( + "my-workflow", "{}", TriggerWorkflowOptions(display_name="Acme Corp") + ) + + assert req.HasField("display_name") + assert req.display_name == "Acme Corp" + + +def test_prepare_workflow_request_omits_display_name_when_unset() -> None: + req = _admin()._prepare_workflow_request( + "my-workflow", "{}", TriggerWorkflowOptions() + ) + + assert not req.HasField("display_name") + + +def test_create_workflow_run_request_sends_display_name() -> None: + # Regression guard: every public run surface (run/run_no_wait/aio_* and bulk) + # and durable child spawns build their gRPC request via + # _create_workflow_run_request, which reconstructs TriggerWorkflowOptions. + # display_name must survive that reconstruction and reach the protobuf. + req = _admin_for_run()._create_workflow_run_request( + "my-workflow", "{}", TriggerWorkflowOptions(display_name="Acme Corp") + ) + + assert req.HasField("display_name") + assert req.display_name == "Acme Corp" + + +def test_create_workflow_run_request_omits_display_name_when_unset() -> None: + req = _admin_for_run()._create_workflow_run_request( + "my-workflow", "{}", TriggerWorkflowOptions() + ) + + assert not req.HasField("display_name") + + +def test_direct_display_name_kwarg_flows_through_run_options() -> None: + # The modern run()/run_many() API passes display_name as a direct keyword + # argument (not via the deprecated `options` object). This is the shared funnel + # every run surface routes through. + workflow = object.__new__(BaseWorkflow) + workflow._config = SimpleNamespace(default_additional_metadata={}) # type: ignore[assignment] + + options = workflow._create_trigger_run_options_with_combined_additional_meta( + None, display_name="Acme Corp" + ) + + assert options.display_name == "Acme Corp" diff --git a/sdks/ruby/src/CHANGELOG.md b/sdks/ruby/src/CHANGELOG.md index 34a2fba4f7..b013050f3e 100644 --- a/sdks/ruby/src/CHANGELOG.md +++ b/sdks/ruby/src/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to Hatchet's Ruby SDK will be documented in this changelog. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +- Added a `display_name` option to set a custom, human-readable name on a run at trigger time, supported by both `trigger_workflow` and `bulk_trigger_workflow` (per-item) and available on `TriggerWorkflowOptions`. Single-task runs carry the name on the task; multi-step DAG runs carry it on the DAG (the DAG's step tasks keep their generated names). Empty or whitespace-only values fall back to the generated `-` name, and names longer than 255 characters are stored truncated rather than rejected ([#4259](https://github.com/hatchet-dev/hatchet/issues/4259)). + ## [0.3.1] - 2026-06-12 ### Fixed diff --git a/sdks/ruby/src/lib/hatchet/clients/grpc/admin.rb b/sdks/ruby/src/lib/hatchet/clients/grpc/admin.rb index 4c78f120cc..6edc8c84fb 100644 --- a/sdks/ruby/src/lib/hatchet/clients/grpc/admin.rb +++ b/sdks/ruby/src/lib/hatchet/clients/grpc/admin.rb @@ -74,6 +74,7 @@ def trigger_workflow(workflow_name, input: {}, options: {}) request_args[:child_key] = options[:child_key] if options[:child_key] request_args[:desired_worker_id] = options[:desired_worker_id] if options[:desired_worker_id] request_args[:priority] = options[:priority] if options[:priority] + request_args[:display_name] = options[:display_name] if options[:display_name] if options[:additional_metadata] request_args[:additional_metadata] = if options[:additional_metadata].is_a?(String) @@ -128,6 +129,7 @@ def bulk_trigger_workflow(workflow_name, items) request_args[:child_key] = opts[:child_key] if opts[:child_key] request_args[:desired_worker_id] = opts[:desired_worker_id] if opts[:desired_worker_id] request_args[:priority] = opts[:priority] if opts[:priority] + request_args[:display_name] = opts[:display_name] if opts[:display_name] if opts[:additional_metadata] request_args[:additional_metadata] = if opts[:additional_metadata].is_a?(String) diff --git a/sdks/ruby/src/lib/hatchet/contracts/v1/shared/trigger_pb.rb b/sdks/ruby/src/lib/hatchet/contracts/v1/shared/trigger_pb.rb index a4582ee990..480bb90736 100644 --- a/sdks/ruby/src/lib/hatchet/contracts/v1/shared/trigger_pb.rb +++ b/sdks/ruby/src/lib/hatchet/contracts/v1/shared/trigger_pb.rb @@ -5,7 +5,7 @@ require 'google/protobuf' -descriptor_data = "\n\x17v1/shared/trigger.proto\x12\x02v1\"\xe8\x01\n\x13\x44\x65siredWorkerLabels\x12\x16\n\tstr_value\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x16\n\tint_value\x18\x02 \x01(\x05H\x01\x88\x01\x01\x12\x15\n\x08required\x18\x03 \x01(\x08H\x02\x88\x01\x01\x12\x32\n\ncomparator\x18\x04 \x01(\x0e\x32\x19.v1.WorkerLabelComparatorH\x03\x88\x01\x01\x12\x13\n\x06weight\x18\x05 \x01(\x05H\x04\x88\x01\x01\x42\x0c\n\n_str_valueB\x0c\n\n_int_valueB\x0b\n\t_requiredB\r\n\x0b_comparatorB\t\n\x07_weight\"\xb2\x04\n\x16TriggerWorkflowRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\t\x12\x16\n\tparent_id\x18\x03 \x01(\tH\x00\x88\x01\x01\x12(\n\x1bparent_task_run_external_id\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0b\x63hild_index\x18\x05 \x01(\x05H\x02\x88\x01\x01\x12\x16\n\tchild_key\x18\x06 \x01(\tH\x03\x88\x01\x01\x12 \n\x13\x61\x64\x64itional_metadata\x18\x07 \x01(\tH\x04\x88\x01\x01\x12\x1e\n\x11\x64\x65sired_worker_id\x18\x08 \x01(\tH\x05\x88\x01\x01\x12\x15\n\x08priority\x18\t \x01(\x05H\x06\x88\x01\x01\x12R\n\x15\x64\x65sired_worker_labels\x18\n \x03(\x0b\x32\x33.v1.TriggerWorkflowRequest.DesiredWorkerLabelsEntry\x1aS\n\x18\x44\x65siredWorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x42\x0c\n\n_parent_idB\x1e\n\x1c_parent_task_run_external_idB\x0e\n\x0c_child_indexB\x0c\n\n_child_keyB\x16\n\x14_additional_metadataB\x14\n\x12_desired_worker_idB\x0b\n\t_priority*\x85\x01\n\x15WorkerLabelComparator\x12\t\n\x05\x45QUAL\x10\x00\x12\r\n\tNOT_EQUAL\x10\x01\x12\x10\n\x0cGREATER_THAN\x10\x02\x12\x19\n\x15GREATER_THAN_OR_EQUAL\x10\x03\x12\r\n\tLESS_THAN\x10\x04\x12\x16\n\x12LESS_THAN_OR_EQUAL\x10\x05\x42\x42Z@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1b\x06proto3" +descriptor_data = "\n\x17v1/shared/trigger.proto\x12\x02v1\"\xe8\x01\n\x13\x44\x65siredWorkerLabels\x12\x16\n\tstr_value\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x16\n\tint_value\x18\x02 \x01(\x05H\x01\x88\x01\x01\x12\x15\n\x08required\x18\x03 \x01(\x08H\x02\x88\x01\x01\x12\x32\n\ncomparator\x18\x04 \x01(\x0e\x32\x19.v1.WorkerLabelComparatorH\x03\x88\x01\x01\x12\x13\n\x06weight\x18\x05 \x01(\x05H\x04\x88\x01\x01\x42\x0c\n\n_str_valueB\x0c\n\n_int_valueB\x0b\n\t_requiredB\r\n\x0b_comparatorB\t\n\x07_weight\"\xde\x04\n\x16TriggerWorkflowRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\t\x12\x16\n\tparent_id\x18\x03 \x01(\tH\x00\x88\x01\x01\x12(\n\x1bparent_task_run_external_id\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0b\x63hild_index\x18\x05 \x01(\x05H\x02\x88\x01\x01\x12\x16\n\tchild_key\x18\x06 \x01(\tH\x03\x88\x01\x01\x12 \n\x13\x61\x64\x64itional_metadata\x18\x07 \x01(\tH\x04\x88\x01\x01\x12\x1e\n\x11\x64\x65sired_worker_id\x18\x08 \x01(\tH\x05\x88\x01\x01\x12\x15\n\x08priority\x18\t \x01(\x05H\x06\x88\x01\x01\x12R\n\x15\x64\x65sired_worker_labels\x18\n \x03(\x0b\x32\x33.v1.TriggerWorkflowRequest.DesiredWorkerLabelsEntry\x12\x19\n\x0c\x64isplay_name\x18\x0b \x01(\tH\x07\x88\x01\x01\x1aS\n\x18\x44\x65siredWorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x42\x0c\n\n_parent_idB\x1e\n\x1c_parent_task_run_external_idB\x0e\n\x0c_child_indexB\x0c\n\n_child_keyB\x16\n\x14_additional_metadataB\x14\n\x12_desired_worker_idB\x0b\n\t_priorityB\x0f\n\r_display_name*\x85\x01\n\x15WorkerLabelComparator\x12\t\n\x05\x45QUAL\x10\x00\x12\r\n\tNOT_EQUAL\x10\x01\x12\x10\n\x0cGREATER_THAN\x10\x02\x12\x19\n\x15GREATER_THAN_OR_EQUAL\x10\x03\x12\r\n\tLESS_THAN\x10\x04\x12\x16\n\x12LESS_THAN_OR_EQUAL\x10\x05\x42\x42Z@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1b\x06proto3" pool = ::Google::Protobuf::DescriptorPool.generated_pool pool.add_serialized_file(descriptor_data) diff --git a/sdks/ruby/src/lib/hatchet/contracts/v1/workflows_pb.rb b/sdks/ruby/src/lib/hatchet/contracts/v1/workflows_pb.rb index 628b311eea..3e976c2df3 100644 --- a/sdks/ruby/src/lib/hatchet/contracts/v1/workflows_pb.rb +++ b/sdks/ruby/src/lib/hatchet/contracts/v1/workflows_pb.rb @@ -9,7 +9,7 @@ require 'v1/shared/trigger_pb' -descriptor_data = "\n\x12v1/workflows.proto\x12\x02v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x19v1/shared/condition.proto\x1a\x17v1/shared/trigger.proto\"[\n\x12\x43\x61ncelTasksRequest\x12\x14\n\x0c\x65xternal_ids\x18\x01 \x03(\t\x12$\n\x06\x66ilter\x18\x02 \x01(\x0b\x32\x0f.v1.TasksFilterH\x00\x88\x01\x01\x42\t\n\x07_filter\"[\n\x12ReplayTasksRequest\x12\x14\n\x0c\x65xternal_ids\x18\x01 \x03(\t\x12$\n\x06\x66ilter\x18\x02 \x01(\x0b\x32\x0f.v1.TasksFilterH\x00\x88\x01\x01\x42\t\n\x07_filter\"\xb7\x01\n\x0bTasksFilter\x12\x10\n\x08statuses\x18\x01 \x03(\t\x12)\n\x05since\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\x05until\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x88\x01\x01\x12\x14\n\x0cworkflow_ids\x18\x04 \x03(\t\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x05 \x03(\tB\x08\n\x06_until\".\n\x13\x43\x61ncelTasksResponse\x12\x17\n\x0f\x63\x61ncelled_tasks\x18\x01 \x03(\t\"-\n\x13ReplayTasksResponse\x12\x16\n\x0ereplayed_tasks\x18\x01 \x03(\t\"\xae\x02\n\x19TriggerWorkflowRunRequest\x12\x15\n\rworkflow_name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\x0c\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x03 \x01(\x0c\x12\x15\n\x08priority\x18\x04 \x01(\x05H\x00\x88\x01\x01\x12U\n\x15\x64\x65sired_worker_labels\x18\x05 \x03(\x0b\x32\x36.v1.TriggerWorkflowRunRequest.DesiredWorkerLabelsEntry\x1aS\n\x18\x44\x65siredWorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x42\x0b\n\t_priority\"1\n\x1aTriggerWorkflowRunResponse\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"X\n\x18\x42ranchDurableTaskRequest\x12\x18\n\x10task_external_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x03\x12\x11\n\tbranch_id\x18\x03 \x01(\x03\"Y\n\x19\x42ranchDurableTaskResponse\x12\x18\n\x10task_external_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x03\x12\x11\n\tbranch_id\x18\x03 \x01(\x03\"\xac\x04\n\x1c\x43reateWorkflowVersionRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x16\n\x0e\x65vent_triggers\x18\x04 \x03(\t\x12\x15\n\rcron_triggers\x18\x05 \x03(\t\x12!\n\x05tasks\x18\x06 \x03(\x0b\x32\x12.v1.CreateTaskOpts\x12$\n\x0b\x63oncurrency\x18\x07 \x01(\x0b\x32\x0f.v1.Concurrency\x12\x17\n\ncron_input\x18\x08 \x01(\tH\x00\x88\x01\x01\x12\x30\n\x0fon_failure_task\x18\t \x01(\x0b\x32\x12.v1.CreateTaskOptsH\x01\x88\x01\x01\x12\'\n\x06sticky\x18\n \x01(\x0e\x32\x12.v1.StickyStrategyH\x02\x88\x01\x01\x12\x1d\n\x10\x64\x65\x66\x61ult_priority\x18\x0b \x01(\x05H\x03\x88\x01\x01\x12(\n\x0f\x63oncurrency_arr\x18\x0c \x03(\x0b\x32\x0f.v1.Concurrency\x12*\n\x0f\x64\x65\x66\x61ult_filters\x18\r \x03(\x0b\x32\x11.v1.DefaultFilter\x12\x1e\n\x11input_json_schema\x18\x0e \x01(\x0cH\x04\x88\x01\x01\x42\r\n\x0b_cron_inputB\x12\n\x10_on_failure_taskB\t\n\x07_stickyB\x13\n\x11_default_priorityB\x14\n\x12_input_json_schema\"T\n\rDefaultFilter\x12\x12\n\nexpression\x18\x01 \x01(\t\x12\r\n\x05scope\x18\x02 \x01(\t\x12\x14\n\x07payload\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x42\n\n\x08_payload\"\x93\x01\n\x0b\x43oncurrency\x12\x12\n\nexpression\x18\x01 \x01(\t\x12\x15\n\x08max_runs\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x39\n\x0elimit_strategy\x18\x03 \x01(\x0e\x32\x1c.v1.ConcurrencyLimitStrategyH\x01\x88\x01\x01\x42\x0b\n\t_max_runsB\x11\n\x0f_limit_strategy\"\xb7\x05\n\x0e\x43reateTaskOpts\x12\x13\n\x0breadable_id\x18\x01 \x01(\t\x12\x0e\n\x06\x61\x63tion\x18\x02 \x01(\t\x12\x0f\n\x07timeout\x18\x03 \x01(\t\x12\x0e\n\x06inputs\x18\x04 \x01(\t\x12\x0f\n\x07parents\x18\x05 \x03(\t\x12\x0f\n\x07retries\x18\x06 \x01(\x05\x12,\n\x0brate_limits\x18\x07 \x03(\x0b\x32\x17.v1.CreateTaskRateLimit\x12;\n\rworker_labels\x18\x08 \x03(\x0b\x32$.v1.CreateTaskOpts.WorkerLabelsEntry\x12\x1b\n\x0e\x62\x61\x63koff_factor\x18\t \x01(\x02H\x00\x88\x01\x01\x12 \n\x13\x62\x61\x63koff_max_seconds\x18\n \x01(\x05H\x01\x88\x01\x01\x12$\n\x0b\x63oncurrency\x18\x0b \x03(\x0b\x32\x0f.v1.Concurrency\x12+\n\nconditions\x18\x0c \x01(\x0b\x32\x12.v1.TaskConditionsH\x02\x88\x01\x01\x12\x1d\n\x10schedule_timeout\x18\r \x01(\tH\x03\x88\x01\x01\x12\x12\n\nis_durable\x18\x0e \x01(\x08\x12;\n\rslot_requests\x18\x0f \x03(\x0b\x32$.v1.CreateTaskOpts.SlotRequestsEntry\x1aL\n\x11WorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x1a\x33\n\x11SlotRequestsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x42\x11\n\x0f_backoff_factorB\x16\n\x14_backoff_max_secondsB\r\n\x0b_conditionsB\x13\n\x11_schedule_timeout\"\xfd\x01\n\x13\x43reateTaskRateLimit\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x12\n\x05units\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x15\n\x08key_expr\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x17\n\nunits_expr\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x1e\n\x11limit_values_expr\x18\x05 \x01(\tH\x03\x88\x01\x01\x12,\n\x08\x64uration\x18\x06 \x01(\x0e\x32\x15.v1.RateLimitDurationH\x04\x88\x01\x01\x42\x08\n\x06_unitsB\x0b\n\t_key_exprB\r\n\x0b_units_exprB\x14\n\x12_limit_values_exprB\x0b\n\t_duration\"@\n\x1d\x43reateWorkflowVersionResponse\x12\n\n\x02id\x18\x01 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x02 \x01(\t\"+\n\x14GetRunDetailsRequest\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"\xaa\x01\n\rTaskRunDetail\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\x12\x1d\n\x06status\x18\x02 \x01(\x0e\x32\r.v1.RunStatus\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06output\x18\x04 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x0breadable_id\x18\x05 \x01(\t\x12\x12\n\nis_evicted\x18\x06 \x01(\x08\x42\x08\n\x06_errorB\t\n\x07_output\"\x84\x02\n\x15GetRunDetailsResponse\x12\r\n\x05input\x18\x01 \x01(\x0c\x12\x1d\n\x06status\x18\x02 \x01(\x0e\x32\r.v1.RunStatus\x12:\n\ttask_runs\x18\x03 \x03(\x0b\x32\'.v1.GetRunDetailsResponse.TaskRunsEntry\x12\x0c\n\x04\x64one\x18\x04 \x01(\x08\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x05 \x01(\x0c\x12\x12\n\nis_evicted\x18\x06 \x01(\x08\x1a\x42\n\rTaskRunsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12 \n\x05value\x18\x02 \x01(\x0b\x32\x11.v1.TaskRunDetail:\x02\x38\x01*$\n\x0eStickyStrategy\x12\x08\n\x04SOFT\x10\x00\x12\x08\n\x04HARD\x10\x01*]\n\x11RateLimitDuration\x12\n\n\x06SECOND\x10\x00\x12\n\n\x06MINUTE\x10\x01\x12\x08\n\x04HOUR\x10\x02\x12\x07\n\x03\x44\x41Y\x10\x03\x12\x08\n\x04WEEK\x10\x04\x12\t\n\x05MONTH\x10\x05\x12\x08\n\x04YEAR\x10\x06*[\n\tRunStatus\x12\n\n\x06QUEUED\x10\x00\x12\x0b\n\x07RUNNING\x10\x01\x12\r\n\tCOMPLETED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\x12\r\n\tCANCELLED\x10\x04\x12\x0b\n\x07\x45VICTED\x10\x05*\x7f\n\x18\x43oncurrencyLimitStrategy\x12\x16\n\x12\x43\x41NCEL_IN_PROGRESS\x10\x00\x12\x0f\n\x0b\x44ROP_NEWEST\x10\x01\x12\x10\n\x0cQUEUE_NEWEST\x10\x02\x12\x15\n\x11GROUP_ROUND_ROBIN\x10\x03\x12\x11\n\rCANCEL_NEWEST\x10\x04\x32\xcf\x03\n\x0c\x41\x64minService\x12R\n\x0bPutWorkflow\x12 .v1.CreateWorkflowVersionRequest\x1a!.v1.CreateWorkflowVersionResponse\x12>\n\x0b\x43\x61ncelTasks\x12\x16.v1.CancelTasksRequest\x1a\x17.v1.CancelTasksResponse\x12>\n\x0bReplayTasks\x12\x16.v1.ReplayTasksRequest\x1a\x17.v1.ReplayTasksResponse\x12S\n\x12TriggerWorkflowRun\x12\x1d.v1.TriggerWorkflowRunRequest\x1a\x1e.v1.TriggerWorkflowRunResponse\x12\x44\n\rGetRunDetails\x12\x18.v1.GetRunDetailsRequest\x1a\x19.v1.GetRunDetailsResponse\x12P\n\x11\x42ranchDurableTask\x12\x1c.v1.BranchDurableTaskRequest\x1a\x1d.v1.BranchDurableTaskResponseBBZ@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1b\x06proto3" +descriptor_data = "\n\x12v1/workflows.proto\x12\x02v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x19v1/shared/condition.proto\x1a\x17v1/shared/trigger.proto\"[\n\x12\x43\x61ncelTasksRequest\x12\x14\n\x0c\x65xternal_ids\x18\x01 \x03(\t\x12$\n\x06\x66ilter\x18\x02 \x01(\x0b\x32\x0f.v1.TasksFilterH\x00\x88\x01\x01\x42\t\n\x07_filter\"[\n\x12ReplayTasksRequest\x12\x14\n\x0c\x65xternal_ids\x18\x01 \x03(\t\x12$\n\x06\x66ilter\x18\x02 \x01(\x0b\x32\x0f.v1.TasksFilterH\x00\x88\x01\x01\x42\t\n\x07_filter\"\xb7\x01\n\x0bTasksFilter\x12\x10\n\x08statuses\x18\x01 \x03(\t\x12)\n\x05since\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\x05until\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x88\x01\x01\x12\x14\n\x0cworkflow_ids\x18\x04 \x03(\t\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x05 \x03(\tB\x08\n\x06_until\".\n\x13\x43\x61ncelTasksResponse\x12\x17\n\x0f\x63\x61ncelled_tasks\x18\x01 \x03(\t\"-\n\x13ReplayTasksResponse\x12\x16\n\x0ereplayed_tasks\x18\x01 \x03(\t\"\xda\x02\n\x19TriggerWorkflowRunRequest\x12\x15\n\rworkflow_name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x01(\x0c\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x03 \x01(\x0c\x12\x15\n\x08priority\x18\x04 \x01(\x05H\x00\x88\x01\x01\x12U\n\x15\x64\x65sired_worker_labels\x18\x05 \x03(\x0b\x32\x36.v1.TriggerWorkflowRunRequest.DesiredWorkerLabelsEntry\x12\x19\n\x0c\x64isplay_name\x18\x06 \x01(\tH\x01\x88\x01\x01\x1aS\n\x18\x44\x65siredWorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x42\x0b\n\t_priorityB\x0f\n\r_display_name\"1\n\x1aTriggerWorkflowRunResponse\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"X\n\x18\x42ranchDurableTaskRequest\x12\x18\n\x10task_external_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x03\x12\x11\n\tbranch_id\x18\x03 \x01(\x03\"Y\n\x19\x42ranchDurableTaskResponse\x12\x18\n\x10task_external_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\x03\x12\x11\n\tbranch_id\x18\x03 \x01(\x03\"\xac\x04\n\x1c\x43reateWorkflowVersionRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x16\n\x0e\x65vent_triggers\x18\x04 \x03(\t\x12\x15\n\rcron_triggers\x18\x05 \x03(\t\x12!\n\x05tasks\x18\x06 \x03(\x0b\x32\x12.v1.CreateTaskOpts\x12$\n\x0b\x63oncurrency\x18\x07 \x01(\x0b\x32\x0f.v1.Concurrency\x12\x17\n\ncron_input\x18\x08 \x01(\tH\x00\x88\x01\x01\x12\x30\n\x0fon_failure_task\x18\t \x01(\x0b\x32\x12.v1.CreateTaskOptsH\x01\x88\x01\x01\x12\'\n\x06sticky\x18\n \x01(\x0e\x32\x12.v1.StickyStrategyH\x02\x88\x01\x01\x12\x1d\n\x10\x64\x65\x66\x61ult_priority\x18\x0b \x01(\x05H\x03\x88\x01\x01\x12(\n\x0f\x63oncurrency_arr\x18\x0c \x03(\x0b\x32\x0f.v1.Concurrency\x12*\n\x0f\x64\x65\x66\x61ult_filters\x18\r \x03(\x0b\x32\x11.v1.DefaultFilter\x12\x1e\n\x11input_json_schema\x18\x0e \x01(\x0cH\x04\x88\x01\x01\x42\r\n\x0b_cron_inputB\x12\n\x10_on_failure_taskB\t\n\x07_stickyB\x13\n\x11_default_priorityB\x14\n\x12_input_json_schema\"T\n\rDefaultFilter\x12\x12\n\nexpression\x18\x01 \x01(\t\x12\r\n\x05scope\x18\x02 \x01(\t\x12\x14\n\x07payload\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x42\n\n\x08_payload\"\x93\x01\n\x0b\x43oncurrency\x12\x12\n\nexpression\x18\x01 \x01(\t\x12\x15\n\x08max_runs\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x39\n\x0elimit_strategy\x18\x03 \x01(\x0e\x32\x1c.v1.ConcurrencyLimitStrategyH\x01\x88\x01\x01\x42\x0b\n\t_max_runsB\x11\n\x0f_limit_strategy\"\xb7\x05\n\x0e\x43reateTaskOpts\x12\x13\n\x0breadable_id\x18\x01 \x01(\t\x12\x0e\n\x06\x61\x63tion\x18\x02 \x01(\t\x12\x0f\n\x07timeout\x18\x03 \x01(\t\x12\x0e\n\x06inputs\x18\x04 \x01(\t\x12\x0f\n\x07parents\x18\x05 \x03(\t\x12\x0f\n\x07retries\x18\x06 \x01(\x05\x12,\n\x0brate_limits\x18\x07 \x03(\x0b\x32\x17.v1.CreateTaskRateLimit\x12;\n\rworker_labels\x18\x08 \x03(\x0b\x32$.v1.CreateTaskOpts.WorkerLabelsEntry\x12\x1b\n\x0e\x62\x61\x63koff_factor\x18\t \x01(\x02H\x00\x88\x01\x01\x12 \n\x13\x62\x61\x63koff_max_seconds\x18\n \x01(\x05H\x01\x88\x01\x01\x12$\n\x0b\x63oncurrency\x18\x0b \x03(\x0b\x32\x0f.v1.Concurrency\x12+\n\nconditions\x18\x0c \x01(\x0b\x32\x12.v1.TaskConditionsH\x02\x88\x01\x01\x12\x1d\n\x10schedule_timeout\x18\r \x01(\tH\x03\x88\x01\x01\x12\x12\n\nis_durable\x18\x0e \x01(\x08\x12;\n\rslot_requests\x18\x0f \x03(\x0b\x32$.v1.CreateTaskOpts.SlotRequestsEntry\x1aL\n\x11WorkerLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.v1.DesiredWorkerLabels:\x02\x38\x01\x1a\x33\n\x11SlotRequestsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x42\x11\n\x0f_backoff_factorB\x16\n\x14_backoff_max_secondsB\r\n\x0b_conditionsB\x13\n\x11_schedule_timeout\"\xfd\x01\n\x13\x43reateTaskRateLimit\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x12\n\x05units\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x15\n\x08key_expr\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x17\n\nunits_expr\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x1e\n\x11limit_values_expr\x18\x05 \x01(\tH\x03\x88\x01\x01\x12,\n\x08\x64uration\x18\x06 \x01(\x0e\x32\x15.v1.RateLimitDurationH\x04\x88\x01\x01\x42\x08\n\x06_unitsB\x0b\n\t_key_exprB\r\n\x0b_units_exprB\x14\n\x12_limit_values_exprB\x0b\n\t_duration\"@\n\x1d\x43reateWorkflowVersionResponse\x12\n\n\x02id\x18\x01 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x02 \x01(\t\"+\n\x14GetRunDetailsRequest\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"\xaa\x01\n\rTaskRunDetail\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\x12\x1d\n\x06status\x18\x02 \x01(\x0e\x32\r.v1.RunStatus\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06output\x18\x04 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x0breadable_id\x18\x05 \x01(\t\x12\x12\n\nis_evicted\x18\x06 \x01(\x08\x42\x08\n\x06_errorB\t\n\x07_output\"\x84\x02\n\x15GetRunDetailsResponse\x12\r\n\x05input\x18\x01 \x01(\x0c\x12\x1d\n\x06status\x18\x02 \x01(\x0e\x32\r.v1.RunStatus\x12:\n\ttask_runs\x18\x03 \x03(\x0b\x32\'.v1.GetRunDetailsResponse.TaskRunsEntry\x12\x0c\n\x04\x64one\x18\x04 \x01(\x08\x12\x1b\n\x13\x61\x64\x64itional_metadata\x18\x05 \x01(\x0c\x12\x12\n\nis_evicted\x18\x06 \x01(\x08\x1a\x42\n\rTaskRunsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12 \n\x05value\x18\x02 \x01(\x0b\x32\x11.v1.TaskRunDetail:\x02\x38\x01*$\n\x0eStickyStrategy\x12\x08\n\x04SOFT\x10\x00\x12\x08\n\x04HARD\x10\x01*]\n\x11RateLimitDuration\x12\n\n\x06SECOND\x10\x00\x12\n\n\x06MINUTE\x10\x01\x12\x08\n\x04HOUR\x10\x02\x12\x07\n\x03\x44\x41Y\x10\x03\x12\x08\n\x04WEEK\x10\x04\x12\t\n\x05MONTH\x10\x05\x12\x08\n\x04YEAR\x10\x06*[\n\tRunStatus\x12\n\n\x06QUEUED\x10\x00\x12\x0b\n\x07RUNNING\x10\x01\x12\r\n\tCOMPLETED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\x12\r\n\tCANCELLED\x10\x04\x12\x0b\n\x07\x45VICTED\x10\x05*\x7f\n\x18\x43oncurrencyLimitStrategy\x12\x16\n\x12\x43\x41NCEL_IN_PROGRESS\x10\x00\x12\x0f\n\x0b\x44ROP_NEWEST\x10\x01\x12\x10\n\x0cQUEUE_NEWEST\x10\x02\x12\x15\n\x11GROUP_ROUND_ROBIN\x10\x03\x12\x11\n\rCANCEL_NEWEST\x10\x04\x32\xcf\x03\n\x0c\x41\x64minService\x12R\n\x0bPutWorkflow\x12 .v1.CreateWorkflowVersionRequest\x1a!.v1.CreateWorkflowVersionResponse\x12>\n\x0b\x43\x61ncelTasks\x12\x16.v1.CancelTasksRequest\x1a\x17.v1.CancelTasksResponse\x12>\n\x0bReplayTasks\x12\x16.v1.ReplayTasksRequest\x1a\x17.v1.ReplayTasksResponse\x12S\n\x12TriggerWorkflowRun\x12\x1d.v1.TriggerWorkflowRunRequest\x1a\x1e.v1.TriggerWorkflowRunResponse\x12\x44\n\rGetRunDetails\x12\x18.v1.GetRunDetailsRequest\x1a\x19.v1.GetRunDetailsResponse\x12P\n\x11\x42ranchDurableTask\x12\x1c.v1.BranchDurableTaskRequest\x1a\x1d.v1.BranchDurableTaskResponseBBZ@github.com/hatchet-dev/hatchet/internal/services/shared/proto/v1b\x06proto3" pool = ::Google::Protobuf::DescriptorPool.generated_pool pool.add_serialized_file(descriptor_data) diff --git a/sdks/ruby/src/lib/hatchet/trigger_options.rb b/sdks/ruby/src/lib/hatchet/trigger_options.rb index 7eab7fcd53..5ab892bbf2 100644 --- a/sdks/ruby/src/lib/hatchet/trigger_options.rb +++ b/sdks/ruby/src/lib/hatchet/trigger_options.rb @@ -33,6 +33,9 @@ class TriggerWorkflowOptions # @return [Hash, nil] Desired worker labels for scheduling attr_reader :desired_worker_labels + # @return [String, nil] Custom display name for the run + attr_reader :display_name + # @param additional_metadata [Hash, nil] Metadata to attach to the run # @param key [String, nil] Deduplication key # @param priority [Integer, nil] Priority level @@ -41,6 +44,7 @@ class TriggerWorkflowOptions # @param child_index [Integer, nil] Child index # @param sticky [Boolean, nil] Enable sticky scheduling # @param desired_worker_labels [Hash, nil] Worker labels for scheduling + # @param display_name [String, nil] Custom display name for the run def initialize( additional_metadata: nil, key: nil, @@ -49,7 +53,8 @@ def initialize( parent_step_run_id: nil, child_index: nil, sticky: nil, - desired_worker_labels: nil + desired_worker_labels: nil, + display_name: nil ) @additional_metadata = additional_metadata @key = key @@ -59,6 +64,7 @@ def initialize( @child_index = child_index @sticky = sticky @desired_worker_labels = desired_worker_labels + @display_name = display_name end # @return [Hash] @@ -72,6 +78,7 @@ def to_h h[:child_index] = @child_index if @child_index h[:sticky] = @sticky unless @sticky.nil? h[:desired_worker_labels] = @desired_worker_labels if @desired_worker_labels + h[:display_name] = @display_name if @display_name h end end diff --git a/sdks/ruby/src/sig/hatchet/trigger_options.rbs b/sdks/ruby/src/sig/hatchet/trigger_options.rbs index 6d618ffadd..cacc3e8baa 100644 --- a/sdks/ruby/src/sig/hatchet/trigger_options.rbs +++ b/sdks/ruby/src/sig/hatchet/trigger_options.rbs @@ -8,6 +8,7 @@ module Hatchet attr_reader child_index: Integer? attr_reader sticky: bool? attr_reader desired_worker_labels: Hash[Symbol, untyped]? + attr_reader display_name: String? def initialize: ( ?additional_metadata: Hash[String, untyped]?, @@ -17,7 +18,8 @@ module Hatchet ?parent_step_run_id: String?, ?child_index: Integer?, ?sticky: bool?, - ?desired_worker_labels: Hash[Symbol, untyped]? + ?desired_worker_labels: Hash[Symbol, untyped]?, + ?display_name: String? ) -> void def to_h: () -> Hash[Symbol, untyped] diff --git a/sdks/ruby/src/spec/hatchet/clients/grpc/admin_spec.rb b/sdks/ruby/src/spec/hatchet/clients/grpc/admin_spec.rb new file mode 100644 index 0000000000..e9956347b0 --- /dev/null +++ b/sdks/ruby/src/spec/hatchet/clients/grpc/admin_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Hatchet::Clients::Grpc::Admin do + let(:logger) { instance_double(Logger, info: nil, warn: nil, debug: nil) } + let(:config) do + instance_double( + Hatchet::Config, + logger: logger, + auth_metadata: {}, + ) + end + let(:channel) { instance_double("GRPC::Core::Channel") } + let(:v0_stub) { instance_double(WorkflowService::Stub) } + let(:response) { double("TriggerWorkflowResponse", workflow_run_id: "run-1") } + + subject(:admin) { described_class.new(config: config, channel: channel) } + + before do + allow(config).to receive(:apply_namespace) { |name| name } + allow(admin).to receive(:ensure_connected!) + admin.instance_variable_set(:@v0_stub, v0_stub) + allow(v0_stub).to receive(:trigger_workflow).and_return(response) + end + + describe "#trigger_workflow" do + it "maps display_name onto the trigger request" do + admin.trigger_workflow("my-workflow", input: {}, options: { display_name: "Acme Corp" }) + + expect(v0_stub).to have_received(:trigger_workflow) do |request, metadata:| + expect(request.display_name).to eq("Acme Corp") + expect(metadata).to eq({}) + end + end + + it "leaves display_name unset when not provided" do + admin.trigger_workflow("my-workflow", input: {}) + + expect(v0_stub).to have_received(:trigger_workflow) do |request, _metadata| + expect(request.display_name).to eq("") + end + end + end + + describe "#bulk_trigger_workflow" do + let(:bulk_response) { double("BulkTriggerWorkflowResponse", workflow_run_ids: %w[run-1 run-2]) } + + before do + allow(v0_stub).to receive(:bulk_trigger_workflow).and_return(bulk_response) + end + + it "maps a per-item display_name onto each request" do + admin.bulk_trigger_workflow("my-workflow", [ + { input: {}, options: { display_name: "Alpha" } }, + { input: {}, options: { display_name: "Bravo" } }, + ],) + + expect(v0_stub).to have_received(:bulk_trigger_workflow) do |bulk_request, metadata:| + names = bulk_request.workflows.map(&:display_name) + expect(names).to eq(%w[Alpha Bravo]) + expect(metadata).to eq({}) + end + end + end +end diff --git a/sdks/ruby/src/spec/hatchet/trigger_options_spec.rb b/sdks/ruby/src/spec/hatchet/trigger_options_spec.rb new file mode 100644 index 0000000000..c78496b5a4 --- /dev/null +++ b/sdks/ruby/src/spec/hatchet/trigger_options_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Hatchet::TriggerWorkflowOptions do + describe "#display_name" do + it "exposes the display name and includes it in to_h" do + options = described_class.new(display_name: "Acme Corp") + + expect(options.display_name).to eq("Acme Corp") + expect(options.to_h).to include(display_name: "Acme Corp") + end + + it "omits display_name from to_h when not provided" do + options = described_class.new + + expect(options.display_name).to be_nil + expect(options.to_h).not_to have_key(:display_name) + end + end +end diff --git a/sdks/typescript/CHANGELOG.md b/sdks/typescript/CHANGELOG.md index 55d479d983..20eb6657ad 100644 --- a/sdks/typescript/CHANGELOG.md +++ b/sdks/typescript/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to Hatchet's TypeScript SDK will be documented in this chang The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +- Added a `displayName` run option to set a custom, human-readable name on a run at trigger time. It is accepted in the options for `run`, `runNoWait`, `runMany`/`runManyNoWait` (per-item), and child spawns (`runChild`/`runChildren`). Single-task runs carry the name on the task; multi-step DAG runs carry it on the DAG (the DAG's step tasks keep their generated names). Empty or whitespace-only values fall back to the generated `-` name, and names longer than 255 characters are stored truncated rather than rejected ([#4259](https://github.com/hatchet-dev/hatchet/issues/4259)). + ## [1.24.3] - 2026-06-17 ### Removed diff --git a/sdks/typescript/src/protoc/v1/shared/trigger.ts b/sdks/typescript/src/protoc/v1/shared/trigger.ts index 6b3a49268d..fc663db04d 100644 --- a/sdks/typescript/src/protoc/v1/shared/trigger.ts +++ b/sdks/typescript/src/protoc/v1/shared/trigger.ts @@ -1,7 +1,7 @@ // Code generated by protoc-gen-ts_proto. DO NOT EDIT. // versions: // protoc-gen-ts_proto v2.11.8 -// protoc v3.19.1 +// protoc v7.35.1 // source: v1/shared/trigger.proto /* eslint-disable */ @@ -120,6 +120,8 @@ export interface TriggerWorkflowRequest { priority?: number | undefined; /** (optional) the desired worker labels for the workflow run, which will be used to determine which workers can pick up the workflow's tasks. if not set, defaults to an empty set of labels, which means any worker can pick up the tasks. */ desiredWorkerLabels: { [key: string]: DesiredWorkerLabels }; + /** (optional) a custom display name for the run; falls back to "-" if unset */ + displayName?: string | undefined; } export interface TriggerWorkflowRequest_DesiredWorkerLabelsEntry { @@ -279,6 +281,7 @@ function createBaseTriggerWorkflowRequest(): TriggerWorkflowRequest { desiredWorkerId: undefined, priority: undefined, desiredWorkerLabels: {}, + displayName: undefined, }; } @@ -319,6 +322,9 @@ export const TriggerWorkflowRequest: MessageFns = { ).join(); } ); + if (message.displayName !== undefined) { + writer.uint32(90).string(message.displayName); + } return writer; }, @@ -415,6 +421,14 @@ export const TriggerWorkflowRequest: MessageFns = { } continue; } + case 11: { + if (tag !== 90) { + break; + } + + message.displayName = reader.string(); + continue; + } } if ((tag & 7) === 4 || tag === 0) { break; @@ -476,6 +490,11 @@ export const TriggerWorkflowRequest: MessageFns = { {} ) : {}, + displayName: isSet(object.displayName) + ? globalThis.String(object.displayName) + : isSet(object.display_name) + ? globalThis.String(object.display_name) + : undefined, }; }, @@ -520,6 +539,9 @@ export const TriggerWorkflowRequest: MessageFns = { }); } } + if (message.displayName !== undefined) { + obj.displayName = message.displayName; + } return obj; }, @@ -551,6 +573,7 @@ export const TriggerWorkflowRequest: MessageFns = { }, {} ); + message.displayName = object.displayName ?? undefined; return message; }, }; diff --git a/sdks/typescript/src/protoc/v1/workflows.ts b/sdks/typescript/src/protoc/v1/workflows.ts index 6e729c1514..e0a3aa13bd 100644 --- a/sdks/typescript/src/protoc/v1/workflows.ts +++ b/sdks/typescript/src/protoc/v1/workflows.ts @@ -1,7 +1,7 @@ // Code generated by protoc-gen-ts_proto. DO NOT EDIT. // versions: // protoc-gen-ts_proto v2.11.8 -// protoc v3.19.1 +// protoc v7.35.1 // source: v1/workflows.proto /* eslint-disable */ @@ -253,6 +253,8 @@ export interface TriggerWorkflowRunRequest { additionalMetadata: Uint8Array; priority?: number | undefined; desiredWorkerLabels: { [key: string]: DesiredWorkerLabels }; + /** (optional) a custom display name for the run; falls back to a generated name if unset */ + displayName?: string | undefined; } export interface TriggerWorkflowRunRequest_DesiredWorkerLabelsEntry { @@ -878,6 +880,7 @@ function createBaseTriggerWorkflowRunRequest(): TriggerWorkflowRunRequest { additionalMetadata: new Uint8Array(0), priority: undefined, desiredWorkerLabels: {}, + displayName: undefined, }; } @@ -906,6 +909,9 @@ export const TriggerWorkflowRunRequest: MessageFns = ).join(); } ); + if (message.displayName !== undefined) { + writer.uint32(50).string(message.displayName); + } return writer; }, @@ -962,6 +968,14 @@ export const TriggerWorkflowRunRequest: MessageFns = } continue; } + case 6: { + if (tag !== 50) { + break; + } + + message.displayName = reader.string(); + continue; + } } if ((tag & 7) === 4 || tag === 0) { break; @@ -1002,6 +1016,11 @@ export const TriggerWorkflowRunRequest: MessageFns = {} ) : {}, + displayName: isSet(object.displayName) + ? globalThis.String(object.displayName) + : isSet(object.display_name) + ? globalThis.String(object.display_name) + : undefined, }; }, @@ -1031,6 +1050,9 @@ export const TriggerWorkflowRunRequest: MessageFns = }); } } + if (message.displayName !== undefined) { + obj.displayName = message.displayName; + } return obj; }, @@ -1057,6 +1079,7 @@ export const TriggerWorkflowRunRequest: MessageFns = }, {} ); + message.displayName = object.displayName ?? undefined; return message; }, }; diff --git a/sdks/typescript/src/v1/client/admin.test.ts b/sdks/typescript/src/v1/client/admin.test.ts index c3439c38f1..cf2183eae5 100644 --- a/sdks/typescript/src/v1/client/admin.test.ts +++ b/sdks/typescript/src/v1/client/admin.test.ts @@ -73,3 +73,39 @@ describe('AdminClient workflow name normalization', () => { ); }); }); + +describe('AdminClient display name', () => { + it('runWorkflow maps displayName onto the trigger request', async () => { + const admin = createMockAdmin(); + await admin.runWorkflow('my-workflow', {}, { displayName: 'Acme Corp' }); + + expect(admin.workflowsGrpc.triggerWorkflow).toHaveBeenCalledWith( + expect.objectContaining({ displayName: 'Acme Corp' }) + ); + }); + + it('runWorkflow leaves displayName undefined when not provided', async () => { + const admin = createMockAdmin(); + await admin.runWorkflow('my-workflow', {}); + + const [[request]] = (admin.workflowsGrpc.triggerWorkflow as jest.Mock).mock.calls; + expect(request.displayName).toBeUndefined(); + }); + + it('runWorkflows maps a per-item displayName in batch', async () => { + const admin = createMockAdmin(); + await admin.runWorkflows([ + { workflowName: 'WorkflowOne', input: {}, options: { displayName: 'Alpha' } }, + { workflowName: 'WorkflowTwo', input: {}, options: { displayName: 'Bravo' } }, + ]); + + expect(admin.workflowsGrpc.bulkTriggerWorkflow).toHaveBeenCalledWith( + expect.objectContaining({ + workflows: expect.arrayContaining([ + expect.objectContaining({ displayName: 'Alpha' }), + expect.objectContaining({ displayName: 'Bravo' }), + ]), + }) + ); + }); +}); diff --git a/sdks/typescript/src/v1/client/admin.ts b/sdks/typescript/src/v1/client/admin.ts index 87540053cc..4a9f2b4e6e 100644 --- a/sdks/typescript/src/v1/client/admin.ts +++ b/sdks/typescript/src/v1/client/admin.ts @@ -132,6 +132,7 @@ export class AdminClient { desiredWorkerId?: string | undefined; priority?: Priority; desiredWorkerLabels?: Record; + displayName?: string | undefined; _standaloneTaskName?: string | undefined; } ) { @@ -216,6 +217,7 @@ export class AdminClient { desiredWorkerId?: string | undefined; priority?: Priority; desiredWorkerLabels?: Record; + displayName?: string | undefined; _standaloneTaskName?: string | undefined; }; }>, diff --git a/sdks/typescript/src/v1/client/worker/context.ts b/sdks/typescript/src/v1/client/worker/context.ts index 87ae750b86..5d6057d7d6 100644 --- a/sdks/typescript/src/v1/client/worker/context.ts +++ b/sdks/typescript/src/v1/client/worker/context.ts @@ -1161,6 +1161,7 @@ export class DurableContext extends Context { desiredWorkerId: options?.sticky ? this.worker.id() : undefined, priority: options?.priority, desiredWorkerLabels: {}, + displayName: options?.displayName, }; return { workflowName, triggerOpts }; diff --git a/sdks/typescript/src/v1/declaration.ts b/sdks/typescript/src/v1/declaration.ts index 24d19d507e..483de3b55a 100644 --- a/sdks/typescript/src/v1/declaration.ts +++ b/sdks/typescript/src/v1/declaration.ts @@ -75,6 +75,13 @@ export type RunOpts = { */ priority?: Priority; + /** + * (optional) a custom display name for the run, shown in the dashboard. + * The engine trims and truncates it; an empty/whitespace value falls back to + * the generated `-` label. + */ + displayName?: string; + /** * (optional) if the task run should be run on the same worker. * only used if spawned from within a parent task.