Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions docs/content/docs/api-reference/workflow/get-attribute.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
title: getAttribute
description: Read a single attribute from the current workflow run.
type: reference
preRelease: true
summary: Use getAttribute to look up a key on the current run's attribute snapshot.
prerequisites:
- /docs/foundations/workflows-and-steps
- /docs/foundations/attributes
related:
- /docs/foundations/attributes
- /docs/api-reference/workflow/get-attributes
- /docs/api-reference/workflow/set-attribute
---

Returns the current value of a single attribute on the workflow run, or `undefined` if the key is not set. Synchronous β€” `getAttribute` reads from the in-memory snapshot the runtime maintains for the run; it does not hit the network.

```typescript lineNumbers
import { getAttribute, setAttribute } from "workflow"

async function exampleWorkflow() {
"use workflow"
await setAttribute("phase", "init")
const phase = getAttribute("phase") // "init" // [!code highlight]
}
```

## Read-your-writes

Within the same workflow or step body, `getAttribute` reflects any writes you have already issued, even if the underlying event has not yet round-tripped to the server.

```typescript lineNumbers
import { getAttribute, setAttribute } from "workflow"

async function readStep() {
"use step"
await setAttribute("orderId", "ord_1")
const value = getAttribute("orderId") // "ord_1" β€” local update is visible
}
```

## Reading initial attributes from `start()`

If the run was started with [`start(workflow, input, { attributes })`](/docs/foundations/starting-workflows), those attributes are visible to `getAttribute` from the very first line of the workflow body:

```typescript lineNumbers
import { getAttribute } from "workflow"
import { start } from "workflow/api"
declare const order: any; // @setup
declare const myWorkflow: (order: any) => Promise<void>; // @setup

// caller:
await start(myWorkflow, [order], { attributes: { tenantId: "t_acme" } } as any)
// TODO(attributes V1): drop the cast once StartOptions accepts attributes.

// inside myWorkflow:
async function myWorkflowImpl(order: any) {
"use workflow"
const tenantId = getAttribute("tenantId") // "t_acme" // [!code highlight]
}
```

## Workflow context vs step context

`getAttribute` works in both contexts. The values are eventually consistent:

- Inside a **step**, the step sees the run's attribute snapshot at step start, plus any of its own writes (read-your-writes).
- Inside a **workflow** body, the workflow sees the snapshot up to the most-recent observed event. While the workflow is suspended waiting on a step, the workflow does not observe attribute writes the step is doing β€” those become visible once the step completes and the workflow resumes.

## Errors

`getAttribute` throws if called outside any workflow or step context. Otherwise it never throws β€” unset keys simply return `undefined`.

## See also

- [Attributes guide](/docs/foundations/attributes)
- [`getAttributes`](/docs/api-reference/workflow/get-attributes) β€” read all attributes at once.
- [`setAttribute`](/docs/api-reference/workflow/set-attribute) β€” write a single attribute.
76 changes: 76 additions & 0 deletions docs/content/docs/api-reference/workflow/get-attributes.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
title: getAttributes
description: Read all attributes on the current workflow run as a record.
type: reference
preRelease: true
summary: Use getAttributes to retrieve the full attribute snapshot for the current run.
prerequisites:
- /docs/foundations/workflows-and-steps
- /docs/foundations/attributes
related:
- /docs/foundations/attributes
- /docs/api-reference/workflow/get-attribute
- /docs/api-reference/workflow/set-attributes
---

Returns the full set of attributes on the current workflow run as a `Record<string, string>`. The returned object is a snapshot β€” mutating it has no effect on the run.

```typescript lineNumbers
import { getAttributes, setAttribute } from "workflow"

async function exampleWorkflow() {
"use workflow"
await setAttribute("phase", "init")
await setAttribute("orderId", "ord_1")

const attrs = getAttributes() // [!code highlight]
// { phase: "init", orderId: "ord_1" }
}
```

`getAttributes` is the bulk equivalent of [`getAttribute`](/docs/api-reference/workflow/get-attribute). Use it when you need to inspect or log the full state β€” for example, attaching the full attribute set to a log line:

```typescript lineNumbers
import { getAttributes, getWorkflowMetadata } from "workflow"

function logWithAttributes(message: string) {
const { workflowRunId } = getWorkflowMetadata()
const attrs = getAttributes()
console.log(`[${workflowRunId}]`, message, attrs)
}
```

## Read-your-writes

Inside a single workflow or step body, `getAttributes` reflects any prior `setAttribute` / `setAttributes` calls in that body, including unsets:

```typescript lineNumbers
import { getAttributes, setAttribute, setAttributes } from "workflow"

async function step() {
"use step"
await setAttributes({ a: "1", b: "2" })
await setAttribute("a", undefined)

getAttributes() // { b: "2" } β€” `a` was unset
}
```

## When `getAttributes` is empty

`getAttributes()` returns `{}` (an empty record) when:

- The run was started without `start({ attributes })`, and
- No `setAttribute` / `setAttributes` calls have been made.

It never returns `undefined`.

## Errors

`getAttributes` throws if called outside any workflow or step context.

## See also

- [Attributes guide](/docs/foundations/attributes)
- [`getAttribute`](/docs/api-reference/workflow/get-attribute) β€” read a single attribute.
- [`setAttributes`](/docs/api-reference/workflow/set-attributes) β€” write many attributes at once.
96 changes: 96 additions & 0 deletions docs/content/docs/api-reference/workflow/set-attribute.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
title: setAttribute
description: Set a single attribute on the current workflow run from inside a workflow or step.
type: reference
preRelease: true
summary: Use setAttribute to record a key-value attribute on the current run for observability and filtering.
prerequisites:
- /docs/foundations/workflows-and-steps
- /docs/foundations/attributes
related:
- /docs/foundations/attributes
- /docs/api-reference/workflow/set-attributes
- /docs/api-reference/workflow/get-attribute
---

Sets a single key-value attribute on the current workflow run. Attributes are small, plaintext metadata that you can search, filter, and display in the observability UI without exposing step inputs/outputs.

You can call `setAttribute` from either a workflow function or a step function. The runtime records who wrote what (workflow body vs. specific step + attempt) in the event log so observability can attribute each change to its source.

```typescript lineNumbers
import { setAttribute } from "workflow"

async function processOrderWorkflow(orderId: string) {
"use workflow"
await setAttribute("orderId", orderId) // [!code highlight]
}
```

## Unsetting an attribute

Pass `undefined` as the value to remove a previously-set attribute:

```typescript lineNumbers
import { setAttribute } from "workflow"

async function checkoutWorkflow() {
"use workflow"
await setAttribute("phase", "init")
// ... later, after the work finishes:
await setAttribute("phase", undefined) // [!code highlight]
}
```

## Setting attributes from a step

`setAttribute` works the same way inside a step function. The only difference is that the event log records the step's `stepId` and `attempt` number against the change, so observability can show "set by step `processOrder` (attempt 2)".

```typescript lineNumbers
import { setAttribute } from "workflow"

async function processOrderStep(orderId: string) {
"use step"
await setAttribute("orderId", orderId) // [!code highlight]
// ... do the actual work
}
```

If the step retries, the new attempt re-emits whatever `setAttribute` calls the step makes. The event log shows both attempts; the run's current attribute snapshot reflects the most-recent write.

## Setting many attributes at once

If you have several attributes to set at the same point in time, prefer [`setAttributes`](/docs/api-reference/workflow/set-attributes) β€” it batches all the changes into a single event for slightly lower overhead and a cleaner event log.

```typescript lineNumbers
import { setAttribute, setAttributes } from "workflow"

async function startStep() {
"use step"
// Three separate events:
await setAttribute("orderId", "ord_1")
await setAttribute("region", "us-east-1")
await setAttribute("stepKind", "process")

// One event with three changes:
await setAttributes({
orderId: "ord_1",
region: "us-east-1",
stepKind: "process",
})
}
```

## Limits and validation

V1 enforces these limits β€” violations throw [`FatalError`](/docs/api-reference/workflow/fatal-error):

- `key`: 1–256 characters, must not start with `$` (the `$`-prefix is reserved for future system keys).
- `value`: ≀ 256 bytes UTF-8 (or `undefined` to unset).
- ≀ 64 attributes per run.

## See also

- [Attributes guide](/docs/foundations/attributes) β€” concepts, use cases, and the search/filter story.
- [`setAttributes`](/docs/api-reference/workflow/set-attributes) β€” batch helper.
- [`getAttribute`](/docs/api-reference/workflow/get-attribute) β€” read a single attribute.
- [`getAttributes`](/docs/api-reference/workflow/get-attributes) β€” read all attributes.
110 changes: 110 additions & 0 deletions docs/content/docs/api-reference/workflow/set-attributes.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
title: setAttributes
description: Set multiple attributes on the current workflow run in a single batched event.
type: reference
preRelease: true
summary: Use setAttributes to record several key-value attributes at once with merge semantics.
prerequisites:
- /docs/foundations/workflows-and-steps
- /docs/foundations/attributes
related:
- /docs/foundations/attributes
- /docs/api-reference/workflow/set-attribute
- /docs/api-reference/workflow/get-attributes
---

Sets multiple attributes on the current workflow run in a single batched event. Use this whenever you have several attributes to write at the same point in time β€” it produces one event with multiple changes, instead of one event per attribute.

```typescript lineNumbers
import { setAttributes } from "workflow"

async function processOrderStep(orderId: string) {
"use step"
await setAttributes({ // [!code highlight]
orderId, // [!code highlight]
region: "us-east-1", // [!code highlight]
stepKind: "process", // [!code highlight]
}) // [!code highlight]
}
```

## Merge semantics

`setAttributes` is **additive**: only the keys you pass are touched. Other attributes already on the run remain unchanged.

```typescript lineNumbers
import { setAttributes } from "workflow"

async function fanOutStep() {
"use step"
await setAttributes({ a: "1", b: "2" })
// run.attributes is now { a: "1", b: "2" }

await setAttributes({ b: "two", c: "3" })
// run.attributes is now { a: "1", b: "two", c: "3" }
// - `a` is preserved (not in the second call)
// - `b` is overwritten
// - `c` is added
}
```

To clear an attribute, pass `undefined` as its value β€” the same convention as [`setAttribute`](/docs/api-reference/workflow/set-attribute):

```typescript lineNumbers
import { setAttributes } from "workflow"

async function cleanupStep() {
"use step"
await setAttributes({
phase: "done",
region: undefined, // [!code highlight] β€” removes `region`
})
}
```

## Empty record is a no-op

Calling `setAttributes({})` does nothing β€” no event is emitted. This makes it safe to compute attribute updates conditionally without special-casing the empty path.

```typescript lineNumbers
import { setAttributes } from "workflow"

async function maybeStep(updates: Record<string, string | undefined>) {
"use step"
await setAttributes(updates) // safe even if `updates` is {}
}
```

## When to prefer `setAttribute`

For one-off single-key writes, [`setAttribute`](/docs/api-reference/workflow/set-attribute) reads more naturally:

```typescript lineNumbers
import { setAttribute, setAttributes } from "workflow"

async function exampleWorkflow() {
"use workflow"
// Single key β€” prefer setAttribute:
await setAttribute("phase", "init")

// Multiple keys at once β€” prefer setAttributes:
await setAttributes({ tenantId: "t_1", region: "us-east-1" })
}
```

Under the hood, both produce the same event type (`attr_set`); `setAttribute(k, v)` is shorthand for `setAttributes({ [k]: v })`.

## Limits and validation

V1 enforces these limits across the merged result β€” violations throw [`FatalError`](/docs/api-reference/workflow/fatal-error):

- Each `key`: 1–256 characters, must not start with `$` (reserved).
- Each `value`: ≀ 256 bytes UTF-8 (or `undefined` to unset).
- ≀ 64 attributes per run **after** the merge is applied.

## See also

- [Attributes guide](/docs/foundations/attributes) β€” concepts, use cases, and the search/filter story.
- [`setAttribute`](/docs/api-reference/workflow/set-attribute) β€” single-key write.
- [`getAttribute`](/docs/api-reference/workflow/get-attribute) β€” read a single attribute.
- [`getAttributes`](/docs/api-reference/workflow/get-attributes) β€” read all attributes.
Loading
Loading