Workflows

Start a workflow instance

Start workflow instances from code and the CLI: build the subject reference, pre-flight start requirements, and retry a start safely.

A workflow instance is one run of a deployed definition against a piece of content. In the quick start the CLI started one for you. This guide starts article-review instances from code and from the CLI, refuses a second review of an article that already has one open, and makes a retried start safe.

At the end you have a script that checks whether a start is allowed before it writes anything, explains a refusal, and resumes a start that failed partway instead of creating a duplicate.

You need:

  • The finished quick start: article-review deployed, and a sanity.workflow.ts that exports the dev deployment.
  • scripts/engine.ts from Run the engine from your own code, which exports engine, and an API token with write access to the dataset in SANITY_AUTH_TOKEN.
  • The _id of the published article from the quick start.

Allow one open review per article

startInstance runs a definition's start requirements before it writes anything. Add a singleSubject requirement to article-review so an article can have at most one unfinished review. Edit workflows/article-review.ts:

A singleSubject requirement refuses a new start while an unfinished instance of the same definition already has the same subject. It checks instances of every deployed version of the definition. title is the text shown when the requirement refuses a start. For GROQ requirements, and for the start.filter that decides where a workflow is offered, see Start filters and requirements.

Deploy the change:

The deploy stores a new version of article-review. Instances already running stay on the version they started on, and new starts use the new version.

Write the start script

Create scripts/start-review.ts. It takes the article _id, and optionally the instance ID of an earlier attempt to retry:

Subject reference. The subject field takes a global document reference (GDR): an object with an id and a type. gdrRef builds it from the deployment’s workflowResource and the document _id. The id is the same dataset:PROJECT_ID:DATASET_NAME:DOCUMENT_ID string you typed in the quick start.

Pass the published _id. A drafts. or versions. ID throws VersionSpecificDatasetGdrError. The instance’s perspective decides whether it reads draft or release content, not the ID. If you need only the id string, without a type, use gdrFromResource(res, documentId).

To learn more about the format, see Global document references. To act on content in another dataset, see Coordinate content across projects and datasets.

Initial fields. initialFields gives a value to each field the definition declares as an input (initialValue: {type: 'input'}) at workflow scope. Each row matches a field by type and name. article-review declares one input, subject. To declare more inputs, see Configure workflow fields.

Pre-flight. evaluateStart runs the same checks as startInstance without writing anything. Read three things from its result:

  • allowed: true only when every supplied row is valid and every start requirement is satisfied. requirements lists each requirement with its outcome. The outcome is satisfied, unsatisfied, or unevaluable. unevaluable means the requirement reads an input you haven’t supplied yet.
  • missingRequired: the required inputs you haven’t supplied. It doesn’t affect allowed, so check it separately.
  • invalidInitialFields: the rows startInstance would reject. Each row has a reason, such as undeclared, not-input, wrong-kind, duplicate, or document-not-found.

The pre-flight is advisory. Another start can happen between the pre-flight and your start. So startInstance checks the requirements again. If a requirement refuses the start, it throws StartNotAllowedError, and unmetRequirements lists the requirements that failed. You can’t override a requirement.

evaluateStart finds existing instances with a GROQ query, so it can miss a commit made in the last second or so. For details, see commit visibility.

Instance ID. The script creates an instance ID with instanceDocId(partition) and prints it before it starts the instance. If the start fails, you can retry it with that ID:

  • If the start was interrupted, the engine finishes it.
  • If the start already finished, the call does nothing.
  • If the ID belongs to an instance of a different definition, the call throws ContractViolationError.

Without an ID, each call creates a new one, so a blind retry can create a second instance. The retry path skips the pre-flight. The interrupted start already holds the subject, so the singleSubject requirement would refuse it.

Start an instance

Run the script with the article _id. Replace YOUR_TOKEN with an API token that has write access to the dataset, and DOCUMENT_ID with the article _id:

The script prints the instance ID, then the stage the instance settled in:

Verify the start rules

Run the same command again. The first review is still open, so the pre-flight refuses the start and nothing is written:

Now retry the first start with its instance ID, as you would after a network failure:

Replace INSTANCE_ID with the ID the first run printed. The script prints the same instance in the same stage, and no second instance exists. Check with the CLI:

The list shows one in-flight article-review instance for the article, the one your first run started.

When a start fails partway

Start from the CLI

The CLI start command runs the same checks. Pass each input with --field, and --instance-id to retry an earlier attempt:

While the article's review is open, a start without --instance-id exits with an error that names the refused requirement:

The `start` command reference lists every flag, including --version to start from an older deployed version and --json for scripts.

Next steps

Was this page helpful?