Skip to content

feat: overload run and runNoWait to accept multiple options #3421

Open
Spid3rrr wants to merge 2 commits intohatchet-dev:mainfrom
Spid3rrr:main
Open

feat: overload run and runNoWait to accept multiple options #3421
Spid3rrr wants to merge 2 commits intohatchet-dev:mainfrom
Spid3rrr:main

Conversation

@Spid3rrr
Copy link
Copy Markdown
Contributor

Description

This PR updates workflow run option handling for array inputs and adds targeted tests to verify the behavior.

When running workflows with array input:

  • Shared run options are still applied to all items.
  • Per-item options arrays are now supported.
  • A clear error is thrown when the options array length does not match the input array length.
  • Child context behavior remains preserved.

Fixes #3398

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Documentation change (pure documentation change)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (non-breaking changes to code which doesn't change any behaviour)
  • CI (any automation pipeline changes)
  • Chore (changes which are not directly related to any business logic)
  • Test changes (add, refactor, improve or change a test)
  • This change requires a documentation update

What's Changed

  • Add support for per-item RunOpts[] in runNoWait when input is an array.
  • Preserve existing shared-options behavior for array input.
  • Add validation to throw when options array length does not match input length.
  • Add unit tests covering shared options, per-item options, and mismatch error paths.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 27, 2026

Someone is attempting to deploy a commit to the Hatchet Team on Vercel.

A member of the Team first needs to authorize it.

@Spid3rrr Spid3rrr marked this pull request as ready for review March 27, 2026 15:28
Copilot AI review requested due to automatic review settings March 27, 2026 15:28
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the TypeScript SDK workflow/task triggering APIs to support passing per-item RunOpts[] when input is an array, while preserving the existing “shared options” behavior and adding validation + tests.

Changes:

  • Add overloads for run() / runNoWait() (and task wrappers) to accept RunOpts[] for array inputs.
  • Implement per-item option application and validate options.length === input.length for array inputs.
  • Add unit tests intended to cover shared options, per-item options, and mismatch errors.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
sdks/typescript/src/v1/declaration.ts Adds option-array overloads and logic for per-item run options in array triggering paths.
sdks/typescript/src/v1/declaration.spec.ts Adds tests for shared/per-item options and length mismatch validation.

Comment on lines 402 to 403
parentRunContextManager.incrementChildIndex(Array.isArray(input) ? input.length : 1);

Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parentRunContextManager.incrementChildIndex(...) is called twice in runNoWait (once near the top and again after throwIfAborted). This double-increments the stored childIndex and can cause gaps/incorrect ordering for subsequent child spawns; remove one of the calls (typically keep the one after the abort precheck) and ensure the childIndex used for each spawned run is computed from the intended base.

Suggested change
parentRunContextManager.incrementChildIndex(Array.isArray(input) ? input.length : 1);

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't related to my PR so I didn't test this behavior specifically. Can include the fix if preferred.

Comment on lines +539 to +541
const refs = Array.isArray(options)
? await this.runNoWait(input, options, _standaloneTaskName)
: await this.runNoWait(input, options, _standaloneTaskName);
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ternary is redundant: both branches call this.runNoWait(input, options, _standaloneTaskName). It can be simplified to a single call for clarity.

Suggested change
const refs = Array.isArray(options)
? await this.runNoWait(input, options, _standaloneTaskName)
: await this.runNoWait(input, options, _standaloneTaskName);
const refs = await this.runNoWait(input, options, _standaloneTaskName);

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ternary looks redundant but its purpose is to tell TS which version of runNoWait is being used. It otherwise would present an overload error. This is the 'cleanest' way I found to keep it tidy.

@promptless-for-oss
Copy link
Copy Markdown

📝 Documentation updates detected!

New suggestion: Document per-item run options for TypeScript SDK bulk runs


Tip: Planning a big docs refactor? Use Deep Analysis to get help with the heavy lifting 🔍

Copy link
Copy Markdown
Collaborator

@gregfurman gregfurman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution!

I think we should consider whether we want to be further overloading the workflow methods versus introducing specific multi-run methods -- similar to how the python and Go SDKs work.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you possibly add an example and e2e test for these multi option runs in sdks/typescript/src/v1/examples?

Comment on lines +363 to +364
input: I[],
options?: RunOpts[],
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned that this approach deviates too much from how the other SDKs expose similar multi-run functionality. What do you think of instead exposing a runMany method similar to the Go client?

hatchet/sdks/go/client.go

Lines 721 to 723 in 45f1203

// RunMany executes multiple workflow instances with different inputs.
// Returns workflow run IDs that can be used to track the run statuses.
func (c *Client) RunMany(ctx context.Context, workflowName string, inputs []RunManyOpt) ([]WorkflowRunRef, error) {

Then we could wrap the admin client's runWorkflows

/**
* Run multiple workflows runs with the given input and options. This will create new workflow runs and return their IDs.
* Order is preserved in the response.
* @param workflowRuns an array of objects containing the workflow name, input, and options for each workflow run
* @returns an array of workflow run references
*
* @important This method is instrumented by HatchetInstrumentor._patchRunWorkflows.
* Keep the signature in sync with the instrumentor wrapper.
*/
async runWorkflows<Q = object, P = object>(

With some kind of unified RunManyOpt (which is composed by input and RunOpt)

i.e

type RunManyOpt<I> = {
  input: I;
  opts?: RunOpts;
};
async runMany(runs: RunManyOpt<I>[]): Promise<O[]>;

Then usage could look like:

// ...

const workflow = hatchet.workflow({ name: 'simple-multi-workflow' });

workflow.task({
  name: 'step1',
  fn: async (input: { message: string }) => ({ result: input.message }),
});

const results = await workflow.runMany([
  { input: { message: 'hello' } },
  { input: { message: 'world' } },
]);

// ...

Wdyt?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this approach. I wasn't aware the other sdks were exposing a different style for scheduling rus. I'll update the PR with the new approaches once done.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gregfurman Would we want to keep backwards compatibility (no breaking changes) for the existing runNoWait? Meaning that muliple runs can be scheduled using both runMany and run?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forcing the use of runMany for all bulk operations would break every run called with multiple inputs.
The alternative would be leaving it as is and simply adding the runMany method to the side (and updating the docs to encourage the use of runMany).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alternative would be leaving it as is and simply adding the runMany method to the side (and updating the docs to encourage the use of runMany).

Yeah this is what I was thinking. Similar to the other SDKs, think that keeping both around is best.

(cc @mrkaye97)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] Add per-item options arrays for run() and runNoWait() in TypeScript SDK

4 participants