@io-orkes/conductor-javascript 2.4.1-beta → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +383 -908
- package/dist/index.d.mts +2610 -167
- package/dist/index.d.ts +2610 -167
- package/dist/index.js +14197 -3339
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +15302 -4486
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -5
package/README.md
CHANGED
|
@@ -1,1086 +1,561 @@
|
|
|
1
|
-
#
|
|
1
|
+
# JavaScript/TypeScript SDK for Conductor
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://github.com/conductor-oss/javascript-sdk/actions/workflows/pull_request.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@io-orkes/conductor-javascript)
|
|
5
|
+
[](LICENSE)
|
|
4
6
|
|
|
5
|
-
[Conductor](https://www.conductor-oss.org/)
|
|
7
|
+
TypeScript/JavaScript SDK for [Conductor](https://www.conductor-oss.org/) (OSS and Orkes Conductor) — an orchestration platform for building distributed applications, AI agents, and workflow-driven microservices. Define workflows as code, run workers anywhere, and let Conductor handle retries, state management, and observability.
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## ⭐ Conductor OSS
|
|
10
|
-
|
|
11
|
-
Show support for the Conductor OSS. Please help spread the awareness by starring Conductor repo.
|
|
9
|
+
If you find [Conductor](https://github.com/conductor-oss/conductor) useful, please consider giving it a star on GitHub — it helps the project grow.
|
|
12
10
|
|
|
13
11
|
[](https://GitHub.com/conductor-oss/conductor/)
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
- [Workflows](#workflows)
|
|
33
|
-
- [The WorkflowExecutor and TaskClient](#the-workflowexecutor-and-taskclient)
|
|
34
|
-
- [Quick Start: Creating a Workflow](#quick-start-creating-a-workflow)
|
|
35
|
-
- [Step 1: Define Your Workflow Structure](#step-1-define-your-workflow-structure)
|
|
36
|
-
- [Step 2: Use Task Generators to Build Your Task List](#step-2-use-task-generators-to-build-your-task-list)
|
|
37
|
-
- [Step 3: Register and Start Your Workflow](#step-3-register-and-start-your-workflow)
|
|
38
|
-
- [Step 4: Manage and Monitor Execution](#step-4-manage-and-monitor-execution)
|
|
39
|
-
- [Use TaskClient to Monitor and Debug Tasks](#use-taskclient-to-monitor-and-debug-tasks)
|
|
40
|
-
- [Workers](#workers)
|
|
41
|
-
- [The TaskManager](#the-taskmanager)
|
|
42
|
-
- [Quick Start: Building a Worker](#quick-start-building-a-worker)
|
|
43
|
-
- [Step 1: Define the Worker's Logic](#step-1-define-the-workers-logic)
|
|
44
|
-
- [Step 2: Handle Task Outcomes and Errors](#step-2-handle-task-outcomes-and-errors)
|
|
45
|
-
- [Step 3: Run the Worker with TaskManager](#step-3-run-the-worker-with-taskmanager)
|
|
46
|
-
- [Worker Design Principles](#worker-design-principles)
|
|
47
|
-
- [Scheduling](#scheduling)
|
|
48
|
-
- [The SchedulerClient](#the-schedulerclient)
|
|
49
|
-
- [Quick Start: Scheduling a Workflow](#quick-start-scheduling-a-workflow)
|
|
50
|
-
- [Step 1: Create a SchedulerClient](#step-1-create-a-schedulerclient)
|
|
51
|
-
- [Step 2: Define the Schedule](#step-2-define-the-schedule)
|
|
52
|
-
- [Step 3: Manage the Schedule](#step-3-manage-the-schedule)
|
|
53
|
-
- [Service Registry](#service-registry)
|
|
54
|
-
- [The ServiceRegistryClient](#the-serviceregistryclient)
|
|
55
|
-
- [Quick Start: Using the Service Registry](#quick-start-using-the-service-registry)
|
|
56
|
-
- [Step 1: Create a ServiceRegistryClient](#step-1-create-a-serviceregistryclient)
|
|
57
|
-
- [Step 2: Register a Service](#step-2-register-a-service)
|
|
58
|
-
- [Step 3: Manage Services](#step-3-manage-services)
|
|
59
|
-
- [Metadata](#metadata)
|
|
60
|
-
- [The MetadataClient](#the-metadataclient)
|
|
61
|
-
- [Quick Start: Managing Metadata](#quick-start-managing-metadata)
|
|
62
|
-
- [Step 1: Create a MetadataClient](#step-1-create-a-metadataclient)
|
|
63
|
-
- [Step 2: Define and Register a Task](#step-2-define-and-register-a-task)
|
|
64
|
-
- [Step 3: Define and Register a Workflow](#step-3-define-and-register-a-workflow)
|
|
65
|
-
- [Events](#events)
|
|
66
|
-
- [The EventClient](#the-eventclient)
|
|
67
|
-
- [Quick Start: Using Event Handlers](#quick-start-using-event-handlers)
|
|
68
|
-
- [Step 1: Create an EventClient](#step-1-create-an-eventclient)
|
|
69
|
-
- [Step 2: Register an Event Handler](#step-2-register-an-event-handler)
|
|
70
|
-
- [Step 3: Publish Events](#step-3-publish-events)
|
|
71
|
-
- [Step 4: Monitor Event Processing](#step-4-monitor-event-processing)
|
|
72
|
-
- [Step 5: Manage Event Handlers](#step-5-manage-event-handlers)
|
|
73
|
-
- [Applications](#applications)
|
|
74
|
-
- [The ApplicationClient](#the-applicationclient)
|
|
75
|
-
- [Quick Start: Managing Applications](#quick-start-managing-applications)
|
|
76
|
-
- [Step 1: Create an ApplicationClient](#step-1-create-an-applicationclient)
|
|
77
|
-
- [Step 2: Create an Application](#step-2-create-an-application)
|
|
78
|
-
- [Step 3: Generate Access Keys](#step-3-generate-access-keys)
|
|
79
|
-
- [Step 4: Manage Application Roles](#step-4-manage-application-roles)
|
|
80
|
-
- [Step 5: Manage Applications](#step-5-manage-applications)
|
|
81
|
-
- [Human Tasks](#human-tasks)
|
|
82
|
-
- [The HumanExecutor and TemplateClient](#the-humanexecutor-and-templateclient)
|
|
83
|
-
- [Quick Start: Creating and Managing a Human Task](#quick-start-creating-and-managing-a-human-task)
|
|
84
|
-
- [Step 1: Create API Clients](#step-1-create-api-clients)
|
|
85
|
-
- [Step 2: Register a Form Template](#step-2-register-a-form-template)
|
|
86
|
-
- [Step 3: Create a Workflow with a Human Task](#step-3-create-a-workflow-with-a-human-task)
|
|
87
|
-
- [Step 4: Find and Complete the Task](#step-4-find-and-complete-the-task)
|
|
88
|
-
|
|
89
|
-
## Installation
|
|
90
|
-
|
|
91
|
-
Install the SDK using npm or yarn:
|
|
92
|
-
|
|
93
|
-
```bash
|
|
94
|
-
npm install @io-orkes/conductor-javascript
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
or
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
yarn add @io-orkes/conductor-javascript
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
## Quick Start
|
|
104
|
-
|
|
105
|
-
Here's a simple example to get you started:
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
import {
|
|
109
|
-
orkesConductorClient,
|
|
110
|
-
WorkflowExecutor,
|
|
111
|
-
TaskManager,
|
|
112
|
-
simpleTask,
|
|
113
|
-
workflow
|
|
114
|
-
} from "@io-orkes/conductor-javascript";
|
|
115
|
-
|
|
116
|
-
// 1. Create client
|
|
117
|
-
const client = await orkesConductorClient({
|
|
118
|
-
serverUrl: "https://play.orkes.io/api",
|
|
119
|
-
keyId: "your-key-id",
|
|
120
|
-
keySecret: "your-key-secret"
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
// 2. Create workflow executor
|
|
124
|
-
const executor = new WorkflowExecutor(client);
|
|
13
|
+
<!-- TOC -->
|
|
14
|
+
* [Start Conductor server](#start-conductor-server)
|
|
15
|
+
* [Install the SDK](#install-the-sdk)
|
|
16
|
+
* [60-Second Quickstart](#60-second-quickstart)
|
|
17
|
+
* [What You Can Build](#what-you-can-build)
|
|
18
|
+
* [Workers](#workers)
|
|
19
|
+
* [Monitoring Workers](#monitoring-workers)
|
|
20
|
+
* [Managing Workflow Executions](#managing-workflow-executions)
|
|
21
|
+
* [Troubleshooting](#troubleshooting)
|
|
22
|
+
* [Examples](#examples)
|
|
23
|
+
* [API Journey Examples](#api-journey-examples)
|
|
24
|
+
* [AI & LLM Workflows](#ai--llm-workflows)
|
|
25
|
+
* [Documentation](#documentation)
|
|
26
|
+
* [Support](#support)
|
|
27
|
+
* [Frequently Asked Questions](#frequently-asked-questions)
|
|
28
|
+
* [License](#license)
|
|
29
|
+
<!-- TOC -->
|
|
125
30
|
|
|
126
|
-
|
|
127
|
-
const myWorkflow = workflow("hello_world", [
|
|
128
|
-
simpleTask("greet_task", "greeting_task", { message: "Hello World!" })
|
|
129
|
-
]);
|
|
31
|
+
## Start Conductor server
|
|
130
32
|
|
|
131
|
-
|
|
132
|
-
await executor.registerWorkflow(true, myWorkflow);
|
|
33
|
+
If you don't already have a Conductor server running, pick one:
|
|
133
34
|
|
|
134
|
-
|
|
135
|
-
const executionId = await executor.startWorkflow({
|
|
136
|
-
name: "hello_world",
|
|
137
|
-
version: 1,
|
|
138
|
-
input: { name: "Developer" }
|
|
139
|
-
});
|
|
35
|
+
**Docker (recommended, includes UI):**
|
|
140
36
|
|
|
141
|
-
|
|
37
|
+
```shell
|
|
38
|
+
docker run -p 8080:8080 conductoross/conductor:latest
|
|
142
39
|
```
|
|
143
40
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
### Access Control Setup
|
|
147
|
-
|
|
148
|
-
The SDK supports authentication using API keys. See [Access Control](https://orkes.io/content/docs/getting-started/concepts/access-control) for more details on role-based access control with Conductor and generating API keys.
|
|
149
|
-
|
|
150
|
-
### Configuration Options
|
|
151
|
-
|
|
152
|
-
```typescript
|
|
153
|
-
import { OrkesApiConfig, orkesConductorClient } from "@io-orkes/conductor-javascript";
|
|
41
|
+
The UI will be available at `http://localhost:8080` and the API at `http://localhost:8080/api`.
|
|
154
42
|
|
|
155
|
-
|
|
156
|
-
serverUrl: "https://play.orkes.io/api", // Required: server api url
|
|
157
|
-
keyId: "your-key-id", // Required for server with auth: authentication key
|
|
158
|
-
keySecret: "your-key-secret", // Required for server with auth: authentication secret
|
|
159
|
-
refreshTokenInterval: 0, // Optional: token refresh interval in ms (default: 30 minutes, 0 = no refresh)
|
|
160
|
-
maxHttp2Connections: 1 // Optional: max HTTP2 connections (default: 1)
|
|
161
|
-
};
|
|
43
|
+
**MacOS / Linux (one-liner):**
|
|
162
44
|
|
|
163
|
-
|
|
45
|
+
```shell
|
|
46
|
+
curl -sSL https://raw.githubusercontent.com/conductor-oss/conductor/main/conductor_server.sh | sh
|
|
164
47
|
```
|
|
165
48
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
You can configure client using environment variables:
|
|
49
|
+
**Conductor CLI:**
|
|
169
50
|
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
CONDUCTOR_AUTH_SECRET=your-key-secret
|
|
174
|
-
CONDUCTOR_REFRESH_TOKEN_INTERVAL=0
|
|
175
|
-
CONDUCTOR_MAX_HTTP2_CONNECTIONS=1
|
|
51
|
+
```shell
|
|
52
|
+
npm install -g @conductor-oss/conductor-cli
|
|
53
|
+
conductor server start
|
|
176
54
|
```
|
|
177
|
-
Environment variables are prioritized over config variables.
|
|
178
55
|
|
|
179
|
-
|
|
56
|
+
## Install the SDK
|
|
180
57
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
```typescript
|
|
184
|
-
const client = await orkesConductorClient(config, fetch);
|
|
58
|
+
```shell
|
|
59
|
+
npm install @io-orkes/conductor-javascript
|
|
185
60
|
```
|
|
186
61
|
|
|
187
|
-
##
|
|
188
|
-
|
|
189
|
-
### What are Tasks?
|
|
190
|
-
|
|
191
|
-
Tasks are individual units of work in Conductor workflows. Each task performs a specific operation, such as making an HTTP call, transforming data, executing custom business logic, or waiting for human approval. Tasks can be executed automatically by Conductor's built-in workers or by custom workers you implement.
|
|
62
|
+
## 60-Second Quickstart
|
|
192
63
|
|
|
193
|
-
|
|
64
|
+
**Step 1: Create a workflow**
|
|
194
65
|
|
|
195
|
-
Workflows are
|
|
196
|
-
|
|
197
|
-
### What are Workers?
|
|
198
|
-
|
|
199
|
-
Workers are applications that poll Conductor for tasks and execute them. Conductor has built-in workers for common operations (HTTP calls, data transforms, etc.), and you can implement custom workers to execute your business-specific logic. This SDK provides tools to build and manage custom workers.
|
|
200
|
-
|
|
201
|
-
### What is the Scheduler?
|
|
202
|
-
The scheduler allows you to schedule workflows to run at specific times or intervals, enabling automated workflow execution based on time-based triggers.
|
|
203
|
-
|
|
204
|
-
## Task Types
|
|
205
|
-
|
|
206
|
-
Conductor provides various task types to build workflows. Understanding which tasks require custom workers and which are managed by Conductor is essential for effective workflow design. Tasks in Conductor are divided into two main categories based on **who executes them**:
|
|
207
|
-
|
|
208
|
-
### System Tasks - Managed by Conductor Server
|
|
209
|
-
|
|
210
|
-
System tasks are fully managed by Conductor. No custom workers needed - just reference them in your workflow and they execute automatically.
|
|
211
|
-
|
|
212
|
-
**Available System Tasks:**
|
|
213
|
-
- **HTTP** - Make HTTP/REST API calls
|
|
214
|
-
- **Inline** - Execute JavaScript expressions
|
|
215
|
-
- **JSON JQ Transform** - Transform JSON data using JQ expressions
|
|
216
|
-
- **Kafka Publish** - Publish messages to Kafka topics
|
|
217
|
-
- **Event** - Publish events to eventing systems
|
|
218
|
-
- **Switch** - Conditional branching based on input
|
|
219
|
-
- **Fork-Join** - Execute tasks in parallel and wait for completion
|
|
220
|
-
- **Dynamic Fork** - Dynamically create parallel task executions
|
|
221
|
-
- **Join** - Join point for forked tasks
|
|
222
|
-
- **Sub-Workflow** - Execute another workflow as a task
|
|
223
|
-
- **Do-While** - Loop execution with conditions
|
|
224
|
-
- **Set Variable** - Set workflow variables
|
|
225
|
-
- **Wait** - Pause workflow for a specified duration
|
|
226
|
-
- **Terminate** - End workflow with success or failure
|
|
227
|
-
- **Human** - Pause workflow until a person completes an action (approval, form submission, etc.). Managed via the `HumanExecutor` API. See [Human Tasks](#human-tasks) section for details.
|
|
228
|
-
|
|
229
|
-
### SIMPLE Tasks - Require Custom Workers
|
|
230
|
-
|
|
231
|
-
SIMPLE tasks execute **your custom business logic**. You must implement workers to handle these tasks.
|
|
232
|
-
|
|
233
|
-
**When to use:**
|
|
234
|
-
- Custom business logic specific to your application
|
|
235
|
-
- Integration with internal systems and databases
|
|
236
|
-
- File processing, data validation, notifications
|
|
237
|
-
- Any functionality not provided by system tasks
|
|
238
|
-
|
|
239
|
-
**How they work:**
|
|
240
|
-
1. Define a SIMPLE task in your workflow
|
|
241
|
-
2. Implement a worker that polls Conductor for this task type
|
|
242
|
-
3. Worker executes your custom logic when task is assigned
|
|
243
|
-
4. Worker reports results back to Conductor
|
|
244
|
-
5. Workflow continues based on task result
|
|
245
|
-
|
|
246
|
-
See the [Workers](#workers) section for implementation details.
|
|
247
|
-
|
|
248
|
-
## Workflows
|
|
249
|
-
|
|
250
|
-
Workflows are the heart of Conductor, orchestrating tasks to perform complex processes. This guide walks you through the entire lifecycle of a workflow, from creation to monitoring.
|
|
251
|
-
|
|
252
|
-
### The WorkflowExecutor and TaskClient
|
|
253
|
-
|
|
254
|
-
- **`WorkflowExecutor`**: The primary tool for managing the workflow lifecycle (e.g., registering, starting, and stopping). For a complete method reference, see the [WorkflowExecutor API Reference](docs/api-reference/workflow-executor.md).
|
|
255
|
-
- **`TaskClient`**: Used for searching and retrieving details of individual tasks within a workflow execution. For a complete method reference, see the [TaskClient API Reference](docs/api-reference/task-client.md).
|
|
256
|
-
|
|
257
|
-
### Quick Start: Creating a Workflow
|
|
258
|
-
|
|
259
|
-
#### Step 1: Define Your Workflow Structure
|
|
260
|
-
|
|
261
|
-
A workflow definition is a blueprint for your process. It outlines the workflow's properties and the sequence of tasks.
|
|
66
|
+
Workflows are definitions that reference task types. We'll build a workflow called `greetings` that runs one worker task and returns its output.
|
|
262
67
|
|
|
263
68
|
```typescript
|
|
264
|
-
|
|
265
|
-
name: "order_fulfillment",
|
|
266
|
-
version: 1,
|
|
267
|
-
description: "Process and fulfill customer orders",
|
|
268
|
-
ownerEmail: "team@example.com",
|
|
269
|
-
tasks: [
|
|
270
|
-
// Tasks will be added in the next step
|
|
271
|
-
],
|
|
272
|
-
inputParameters: ["orderId", "customerId", "productId", "quantity"],
|
|
273
|
-
outputParameters: {
|
|
274
|
-
status: "${route_order_ref.output.status}",
|
|
275
|
-
fulfillmentId: "${fulfill_order_ref.output.fulfillmentId}"
|
|
276
|
-
},
|
|
277
|
-
timeoutSeconds: 3600,
|
|
278
|
-
timeoutPolicy: "ALERT_ONLY"
|
|
279
|
-
};
|
|
280
|
-
```
|
|
69
|
+
import { ConductorWorkflow, simpleTask } from "@io-orkes/conductor-javascript";
|
|
281
70
|
|
|
282
|
-
|
|
71
|
+
const workflow = new ConductorWorkflow(executor, "greetings")
|
|
72
|
+
.add(simpleTask("greet_ref", "greet", { name: "${workflow.input.name}" }))
|
|
73
|
+
.outputParameters({ result: "${greet_ref.output.result}" });
|
|
283
74
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
```typescript
|
|
287
|
-
import { simpleTask, httpTask, switchTask } from "@io-orkes/conductor-javascript";
|
|
288
|
-
|
|
289
|
-
const tasks = [
|
|
290
|
-
// Task 1: A custom task to validate the order
|
|
291
|
-
simpleTask(
|
|
292
|
-
"validate_order_ref",
|
|
293
|
-
"validate_order",
|
|
294
|
-
{
|
|
295
|
-
orderId: "${workflow.input.orderId}",
|
|
296
|
-
customerId: "${workflow.input.customerId}"
|
|
297
|
-
}
|
|
298
|
-
),
|
|
299
|
-
|
|
300
|
-
// Task 2: An HTTP task to check inventory
|
|
301
|
-
httpTask(
|
|
302
|
-
"check_inventory_ref",
|
|
303
|
-
{
|
|
304
|
-
uri: "https://api.inventory.com/check",
|
|
305
|
-
method: "POST",
|
|
306
|
-
body: {
|
|
307
|
-
productId: "${workflow.input.productId}",
|
|
308
|
-
quantity: "${workflow.input.quantity}"
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
),
|
|
312
|
-
|
|
313
|
-
// Task 3: A switch task for conditional logic
|
|
314
|
-
switchTask(
|
|
315
|
-
"route_order_ref",
|
|
316
|
-
"${check_inventory_ref.output.inStock}",
|
|
317
|
-
{
|
|
318
|
-
"true": [
|
|
319
|
-
simpleTask("fulfill_order_ref", "fulfill_order", {})
|
|
320
|
-
],
|
|
321
|
-
"false": [
|
|
322
|
-
simpleTask("backorder_ref", "create_backorder", {})
|
|
323
|
-
]
|
|
324
|
-
}
|
|
325
|
-
)
|
|
326
|
-
];
|
|
327
|
-
|
|
328
|
-
// Add the tasks to your workflow definition
|
|
329
|
-
workflowDef.tasks = tasks;
|
|
75
|
+
await workflow.register();
|
|
330
76
|
```
|
|
331
77
|
|
|
332
|
-
**
|
|
333
|
-
- **`taskReferenceName`**: A unique identifier for a task instance within a workflow. Used for data flow (e.g., `${check_inventory_ref.output.inStock}`).
|
|
334
|
-
- **Input Parameters**: Use `${workflow.input.fieldName}` to access initial workflow inputs and `${task_ref.output.fieldName}` to access outputs from previous tasks.
|
|
335
|
-
- **Task Generators**: Helper functions like `simpleTask`, `httpTask`, etc., that create task definitions. For a complete list, see the [Task Generators Reference](docs/api-reference/task-generators.md).
|
|
336
|
-
|
|
337
|
-
#### Step 3: Register and Start Your Workflow
|
|
78
|
+
**Step 2: Write a worker**
|
|
338
79
|
|
|
339
|
-
|
|
80
|
+
Workers are TypeScript functions decorated with `@worker` that poll Conductor for tasks and execute them.
|
|
340
81
|
|
|
341
82
|
```typescript
|
|
342
|
-
import {
|
|
343
|
-
|
|
344
|
-
// Create WorkflowExecutor instance
|
|
345
|
-
const executor = new WorkflowExecutor(client);
|
|
346
|
-
|
|
347
|
-
// Register the workflow definition (overwrite if it exists)
|
|
348
|
-
await executor.registerWorkflow(true, workflowDef);
|
|
349
|
-
|
|
350
|
-
// Start a workflow execution
|
|
351
|
-
const executionId = await executor.startWorkflow({
|
|
352
|
-
name: "order_fulfillment",
|
|
353
|
-
version: 1,
|
|
354
|
-
input: {
|
|
355
|
-
orderId: "ORDER-123",
|
|
356
|
-
customerId: "CUST-456",
|
|
357
|
-
productId: "PROD-789",
|
|
358
|
-
quantity: 2
|
|
359
|
-
}
|
|
360
|
-
});
|
|
83
|
+
import { worker } from "@io-orkes/conductor-javascript";
|
|
361
84
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
##### Check Workflow Status
|
|
370
|
-
|
|
371
|
-
Retrieve the current status and output of a running workflow.
|
|
372
|
-
|
|
373
|
-
```typescript
|
|
374
|
-
const status = await executor.getWorkflowStatus(
|
|
375
|
-
executionId,
|
|
376
|
-
true, // includeOutput
|
|
377
|
-
true // includeVariables
|
|
378
|
-
);
|
|
379
|
-
console.log(`Workflow status is: ${status.status}`);
|
|
85
|
+
@worker({ taskDefName: "greet" })
|
|
86
|
+
async function greet(task: Task) {
|
|
87
|
+
return {
|
|
88
|
+
status: "COMPLETED",
|
|
89
|
+
outputData: { result: `Hello ${task.inputData.name}` },
|
|
90
|
+
};
|
|
91
|
+
}
|
|
380
92
|
```
|
|
381
93
|
|
|
382
|
-
|
|
94
|
+
**Step 3: Run your first workflow app**
|
|
383
95
|
|
|
384
|
-
|
|
96
|
+
Create a `quickstart.ts` with the following:
|
|
385
97
|
|
|
386
98
|
```typescript
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
##### Search for Workflows
|
|
99
|
+
import {
|
|
100
|
+
OrkesClients,
|
|
101
|
+
ConductorWorkflow,
|
|
102
|
+
TaskHandler,
|
|
103
|
+
worker,
|
|
104
|
+
simpleTask,
|
|
105
|
+
} from "@io-orkes/conductor-javascript";
|
|
106
|
+
import type { Task } from "@io-orkes/conductor-javascript";
|
|
398
107
|
|
|
399
|
-
|
|
108
|
+
// A worker is any TypeScript function.
|
|
109
|
+
@worker({ taskDefName: "greet" })
|
|
110
|
+
async function greet(task: Task) {
|
|
111
|
+
return {
|
|
112
|
+
status: "COMPLETED" as const,
|
|
113
|
+
outputData: { result: `Hello ${task.inputData.name}` },
|
|
114
|
+
};
|
|
115
|
+
}
|
|
400
116
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
"status:RUNNING AND workflowType:order_fulfillment",
|
|
406
|
-
"*",
|
|
407
|
-
"startTime:DESC"
|
|
408
|
-
);
|
|
409
|
-
```
|
|
117
|
+
async function main() {
|
|
118
|
+
// Configure the SDK (reads CONDUCTOR_SERVER_URL / CONDUCTOR_AUTH_* from env).
|
|
119
|
+
const clients = await OrkesClients.from();
|
|
120
|
+
const executor = clients.getWorkflowClient();
|
|
410
121
|
|
|
411
|
-
|
|
122
|
+
// Build a workflow with the fluent builder.
|
|
123
|
+
const workflow = new ConductorWorkflow(executor, "greetings")
|
|
124
|
+
.add(simpleTask("greet_ref", "greet", { name: "${workflow.input.name}" }))
|
|
125
|
+
.outputParameters({ result: "${greet_ref.output.result}" });
|
|
412
126
|
|
|
413
|
-
|
|
127
|
+
await workflow.register();
|
|
414
128
|
|
|
415
|
-
|
|
416
|
-
|
|
129
|
+
// Start polling for tasks (auto-discovers @worker decorated functions).
|
|
130
|
+
const handler = new TaskHandler({
|
|
131
|
+
client: clients.getClient(),
|
|
132
|
+
scanForDecorated: true,
|
|
133
|
+
});
|
|
134
|
+
await handler.startWorkers();
|
|
417
135
|
|
|
418
|
-
|
|
136
|
+
// Run the workflow and get the result.
|
|
137
|
+
const run = await workflow.execute({ name: "Conductor" });
|
|
138
|
+
console.log(`result: ${run.output?.result}`);
|
|
419
139
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
0,
|
|
423
|
-
100,
|
|
424
|
-
"startTime:DESC",
|
|
425
|
-
"*",
|
|
426
|
-
`status:FAILED AND workflowId:${executionId}`
|
|
427
|
-
);
|
|
140
|
+
await handler.stopWorkers();
|
|
141
|
+
}
|
|
428
142
|
|
|
429
|
-
|
|
430
|
-
const taskDetails = await taskClient.getTask(failedTasks.results[0].taskId);
|
|
143
|
+
main();
|
|
431
144
|
```
|
|
432
145
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
## Workers
|
|
436
|
-
|
|
437
|
-
Workers are background processes that execute tasks in your workflows. Think of them as specialized functions that:
|
|
438
|
-
|
|
439
|
-
1. **Poll** the Conductor server for tasks.
|
|
440
|
-
2. **Execute** your business logic when a task is assigned.
|
|
441
|
-
3. **Report** the results back to the Conductor server.
|
|
146
|
+
Run it:
|
|
442
147
|
|
|
443
|
-
|
|
148
|
+
```shell
|
|
149
|
+
export CONDUCTOR_SERVER_URL=http://localhost:8080
|
|
150
|
+
npx ts-node quickstart.ts
|
|
444
151
|
```
|
|
445
|
-
Workflow → Creates Tasks → Workers Poll for Tasks → Execute Logic → Return Results → Workflow Continues
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
The `TaskManager` class in this SDK simplifies the process of creating and managing workers.
|
|
449
152
|
|
|
450
|
-
###
|
|
153
|
+
> ### Using Orkes Conductor / Remote Server?
|
|
154
|
+
> Export your authentication credentials:
|
|
155
|
+
>
|
|
156
|
+
> ```shell
|
|
157
|
+
> export CONDUCTOR_SERVER_URL="https://your-cluster.orkesconductor.io/api"
|
|
158
|
+
> export CONDUCTOR_AUTH_KEY="your-key"
|
|
159
|
+
> export CONDUCTOR_AUTH_SECRET="your-secret"
|
|
160
|
+
> ```
|
|
451
161
|
|
|
452
|
-
|
|
162
|
+
That's it — you defined a worker, built a workflow, and executed it. Open the Conductor UI (default: [http://localhost:8080](http://localhost:8080)) to see the execution.
|
|
453
163
|
|
|
454
|
-
|
|
164
|
+
## What You Can Build
|
|
455
165
|
|
|
456
|
-
|
|
166
|
+
The SDK provides typed builders for common orchestration patterns. Here's a taste of what you can wire together:
|
|
457
167
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
A worker is an object that defines a `taskDefName` (which must match the task name in your workflow) and an `execute` function containing your business logic.
|
|
168
|
+
**HTTP calls from workflows** — call any API without writing a worker ([kitchensink.ts](examples/kitchensink.ts)):
|
|
461
169
|
|
|
462
170
|
```typescript
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
// 2. Implement the execution logic
|
|
470
|
-
execute: async (task) => {
|
|
471
|
-
const { to, subject, body } = task.inputData;
|
|
472
|
-
|
|
473
|
-
console.log(`Sending email to ${to}: ${subject}`);
|
|
474
|
-
await emailService.send(to, subject, body); // Your business logic
|
|
475
|
-
|
|
476
|
-
// 3. Return a result (covered in the next step)
|
|
477
|
-
return {
|
|
478
|
-
status: "COMPLETED",
|
|
479
|
-
outputData: { sent: true, timestamp: new Date().toISOString() }
|
|
480
|
-
};
|
|
481
|
-
}
|
|
482
|
-
};
|
|
171
|
+
httpTask("call_api", {
|
|
172
|
+
uri: "https://api.example.com/orders/${workflow.input.orderId}",
|
|
173
|
+
method: "POST",
|
|
174
|
+
body: { items: "${workflow.input.items}" },
|
|
175
|
+
headers: { "Authorization": "Bearer ${workflow.input.token}" },
|
|
176
|
+
})
|
|
483
177
|
```
|
|
484
178
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
The `execute` function must return an object indicating the task's outcome.
|
|
488
|
-
|
|
489
|
-
**✅ On Success:**
|
|
490
|
-
Return a `COMPLETED` status and any relevant output data.
|
|
179
|
+
**Wait between tasks** — pause a workflow for a duration or until a timestamp ([kitchensink.ts](examples/kitchensink.ts)):
|
|
491
180
|
|
|
492
181
|
```typescript
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
};
|
|
182
|
+
.add(simpleTask("step1_ref", "process_order", {...}))
|
|
183
|
+
.add(waitTaskDuration("cool_down", "10s")) // wait 10 seconds
|
|
184
|
+
.add(simpleTask("step2_ref", "send_confirmation", {...}))
|
|
497
185
|
```
|
|
498
186
|
|
|
499
|
-
|
|
500
|
-
You can control the retry behavior. `FAILED` allows for retries, while `FAILED_WITH_TERMINAL_ERROR` stops the workflow immediately.
|
|
187
|
+
**Parallel execution (fork/join)** — fan out to multiple branches and join ([fork-join.ts](examples/advanced/fork-join.ts)):
|
|
501
188
|
|
|
502
189
|
```typescript
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
logs: [{ log: `Error executing task: ${error.message}` }]
|
|
509
|
-
};
|
|
510
|
-
}
|
|
190
|
+
workflow.fork([
|
|
191
|
+
[simpleTask("email_ref", "send_email", {})],
|
|
192
|
+
[simpleTask("sms_ref", "send_sms", {})],
|
|
193
|
+
[simpleTask("push_ref", "send_push", {})],
|
|
194
|
+
])
|
|
511
195
|
```
|
|
512
196
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
The `TaskManager` is responsible for polling Conductor, managing task execution, and reporting back results. You can run a single worker or multiple workers with one manager.
|
|
197
|
+
**Conditional branching** — route based on input values ([kitchensink.ts](examples/kitchensink.ts)):
|
|
516
198
|
|
|
517
199
|
```typescript
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
// Create the TaskManager
|
|
524
|
-
const manager = new TaskManager(client, workers, {
|
|
525
|
-
options: {
|
|
526
|
-
concurrency: 5, // Process up to 5 tasks concurrently
|
|
527
|
-
pollInterval: 100, // Poll every 100ms
|
|
528
|
-
}
|
|
529
|
-
});
|
|
530
|
-
|
|
531
|
-
// Start polling for tasks
|
|
532
|
-
await manager.startPolling();
|
|
533
|
-
console.log("Worker is running!");
|
|
200
|
+
switchTask("route_ref", "${workflow.input.tier}", {
|
|
201
|
+
premium: [simpleTask("fast_ref", "fast_track", {})],
|
|
202
|
+
standard: [simpleTask("normal_ref", "standard_process", {})],
|
|
203
|
+
})
|
|
534
204
|
```
|
|
535
205
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
### Worker Design Principles
|
|
539
|
-
|
|
540
|
-
When designing workers, it's best to follow these principles:
|
|
541
|
-
|
|
542
|
-
- **Stateless**: Workers should not rely on local state.
|
|
543
|
-
- **Idempotent**: The same task input should always produce the same result.
|
|
544
|
-
- **Single Responsibility**: Each worker should be responsible for one specific task type.
|
|
545
|
-
|
|
546
|
-
## Scheduling
|
|
547
|
-
|
|
548
|
-
The Conductor Scheduler allows you to run workflows at specific times or intervals, defined by a CRON expression. This is useful for tasks like nightly data processing, weekly reports, or any time-based automation.
|
|
549
|
-
|
|
550
|
-
### The SchedulerClient
|
|
551
|
-
|
|
552
|
-
The `SchedulerClient` is used to create, manage, and delete workflow schedules. For a complete method reference, see the [SchedulerClient API Reference](docs/api-reference/scheduler-client.md).
|
|
553
|
-
|
|
554
|
-
### Quick Start: Scheduling a Workflow
|
|
555
|
-
|
|
556
|
-
Here’s how to schedule a workflow in three steps:
|
|
557
|
-
|
|
558
|
-
#### Step 1: Create a SchedulerClient
|
|
559
|
-
|
|
560
|
-
First, create an instance of the `SchedulerClient`:
|
|
206
|
+
**Sub-workflows** — compose workflows from smaller workflows ([sub-workflows.ts](examples/advanced/sub-workflows.ts)):
|
|
561
207
|
|
|
562
208
|
```typescript
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
209
|
+
const child = new ConductorWorkflow(executor, "payment_flow").add(...);
|
|
210
|
+
const parent = new ConductorWorkflow(executor, "order_flow")
|
|
211
|
+
.add(child.toSubWorkflowTask("pay_ref"));
|
|
566
212
|
```
|
|
567
213
|
|
|
568
|
-
|
|
214
|
+
All of these are type-safe, composable, and registered to the server as JSON — workers can be in any language.
|
|
569
215
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
```typescript
|
|
573
|
-
// Schedule a workflow to run every day at 9 AM
|
|
574
|
-
await scheduler.saveSchedule({
|
|
575
|
-
name: "daily_report_schedule",
|
|
576
|
-
cronExpression: "0 0 9 * * ?", // Everyday at 9am
|
|
577
|
-
startWorkflowRequest: {
|
|
578
|
-
name: "generate_daily_report",
|
|
579
|
-
version: 1,
|
|
580
|
-
input: {
|
|
581
|
-
reportType: "SALES",
|
|
582
|
-
period: "DAILY"
|
|
583
|
-
},
|
|
584
|
-
},
|
|
585
|
-
});
|
|
586
|
-
```
|
|
587
|
-
|
|
588
|
-
**Cron Expression Format:**
|
|
589
|
-
- Standard cron format: `second minute hour day month dayOfWeek`
|
|
590
|
-
- Examples:
|
|
591
|
-
- `"0 0 9 * * ?"` - Every day at 9 AM
|
|
592
|
-
- `"0 */30 * * * ?"` - Every 30 minutes
|
|
593
|
-
- `"0 0 0 1 * ?"` - First day of every month at midnight
|
|
594
|
-
- `"0 0 12 ? * MON-FRI"` - Weekdays at noon
|
|
595
|
-
|
|
596
|
-
#### Step 3: Manage the Schedule
|
|
597
|
-
|
|
598
|
-
You can easily manage your schedules:
|
|
599
|
-
|
|
600
|
-
```typescript
|
|
601
|
-
// Pause a schedule
|
|
602
|
-
await scheduler.pauseSchedule("daily_report_schedule");
|
|
603
|
-
|
|
604
|
-
// Resume a paused schedule
|
|
605
|
-
await scheduler.resumeSchedule("daily_report_schedule");
|
|
606
|
-
|
|
607
|
-
// Delete a schedule
|
|
608
|
-
await scheduler.deleteSchedule("daily_report_schedule");
|
|
609
|
-
```
|
|
610
|
-
|
|
611
|
-
For a complete method reference, see the [SchedulerClient API Reference](docs/api-reference/scheduler-client.md).
|
|
612
|
-
|
|
613
|
-
## Service Registry
|
|
614
|
-
|
|
615
|
-
The Service Registry in Conductor allows you to manage and discover microservices. It also provides built-in circuit breaker functionality to improve the resilience of your distributed system.
|
|
616
|
-
|
|
617
|
-
### The ServiceRegistryClient
|
|
618
|
-
|
|
619
|
-
The `ServiceRegistryClient` is used to register, manage, and discover services. For a complete method reference, see the [ServiceRegistryClient API Reference](docs/api-reference/service-registry-client.md).
|
|
620
|
-
|
|
621
|
-
### Quick Start: Using the Service Registry
|
|
622
|
-
|
|
623
|
-
Here’s how to get started with the `ServiceRegistryClient`:
|
|
624
|
-
|
|
625
|
-
#### Step 1: Create a ServiceRegistryClient
|
|
216
|
+
## Workers
|
|
626
217
|
|
|
627
|
-
|
|
218
|
+
Workers are TypeScript functions that execute Conductor tasks. Decorate any function with `@worker` to register it as a worker (auto-discovered by `TaskHandler`) and use it as a workflow task.
|
|
628
219
|
|
|
629
220
|
```typescript
|
|
630
|
-
import {
|
|
221
|
+
import { worker, TaskHandler } from "@io-orkes/conductor-javascript";
|
|
631
222
|
|
|
632
|
-
|
|
633
|
-
|
|
223
|
+
@worker({ taskDefName: "greet", concurrency: 5, pollInterval: 100 })
|
|
224
|
+
async function greet(task: Task) {
|
|
225
|
+
return {
|
|
226
|
+
status: "COMPLETED",
|
|
227
|
+
outputData: { result: `Hello ${task.inputData.name}` },
|
|
228
|
+
};
|
|
229
|
+
}
|
|
634
230
|
|
|
635
|
-
|
|
231
|
+
@worker({ taskDefName: "process_payment", domain: "payments" })
|
|
232
|
+
async function processPayment(task: Task) {
|
|
233
|
+
const result = await paymentGateway.charge(task.inputData.customerId, task.inputData.amount);
|
|
234
|
+
return { status: "COMPLETED", outputData: { transactionId: result.id } };
|
|
235
|
+
}
|
|
636
236
|
|
|
637
|
-
|
|
237
|
+
// Auto-discover and start all decorated workers
|
|
238
|
+
const handler = new TaskHandler({ client, scanForDecorated: true });
|
|
239
|
+
await handler.startWorkers();
|
|
638
240
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
await
|
|
642
|
-
|
|
643
|
-
type: "HTTP",
|
|
644
|
-
serviceURI: "https://api.example.com/users",
|
|
645
|
-
circuitBreakerConfig: {
|
|
646
|
-
failureRateThreshold: 50.0,
|
|
647
|
-
slidingWindowSize: 10,
|
|
648
|
-
minimumNumberOfCalls: 5,
|
|
649
|
-
waitDurationInOpenState: 60000, // 1 minute
|
|
650
|
-
},
|
|
241
|
+
// Graceful shutdown
|
|
242
|
+
process.on("SIGTERM", async () => {
|
|
243
|
+
await handler.stopWorkers();
|
|
244
|
+
process.exit(0);
|
|
651
245
|
});
|
|
652
246
|
```
|
|
653
247
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
You can easily manage your registered services:
|
|
248
|
+
**Worker configuration:**
|
|
657
249
|
|
|
658
250
|
```typescript
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
//
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
await serviceRegistry.removeService("user-service");
|
|
251
|
+
@worker({
|
|
252
|
+
taskDefName: "my_task", // Required: task name
|
|
253
|
+
concurrency: 5, // Max concurrent tasks (default: 1)
|
|
254
|
+
pollInterval: 100, // Polling interval in ms (default: 100)
|
|
255
|
+
domain: "production", // Task domain for multi-tenancy
|
|
256
|
+
workerId: "worker-123", // Unique worker identifier
|
|
257
|
+
})
|
|
667
258
|
```
|
|
668
259
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
## Metadata
|
|
672
|
-
|
|
673
|
-
In Conductor, "metadata" refers to the definitions of your tasks and workflows. Before you can execute a workflow, you must register its definition with Conductor. The `MetadataClient` provides the tools to manage these definitions.
|
|
674
|
-
|
|
675
|
-
### The MetadataClient
|
|
260
|
+
**Environment variable overrides** (no code changes needed):
|
|
676
261
|
|
|
677
|
-
|
|
262
|
+
```shell
|
|
263
|
+
# Global (all workers)
|
|
264
|
+
export CONDUCTOR_WORKER_ALL_POLL_INTERVAL=500
|
|
265
|
+
export CONDUCTOR_WORKER_ALL_CONCURRENCY=10
|
|
678
266
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
#### Step 1: Create a MetadataClient
|
|
684
|
-
|
|
685
|
-
First, create an instance of the `MetadataClient`:
|
|
686
|
-
|
|
687
|
-
```typescript
|
|
688
|
-
import { MetadataClient, taskDefinition, workflowDef } from "@io-orkes/conductor-javascript";
|
|
689
|
-
|
|
690
|
-
const metadataClient = new MetadataClient(client);
|
|
267
|
+
# Per-worker override
|
|
268
|
+
export CONDUCTOR_WORKER_SEND_EMAIL_CONCURRENCY=20
|
|
269
|
+
export CONDUCTOR_WORKER_PROCESS_PAYMENT_DOMAIN=payments
|
|
691
270
|
```
|
|
692
271
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
Create a task definition and register it. The `taskDefinition` factory provides sensible defaults for optional fields.
|
|
272
|
+
**NonRetryableException** — mark failures as terminal to prevent retries:
|
|
696
273
|
|
|
697
274
|
```typescript
|
|
698
|
-
|
|
699
|
-
const taskDef = taskDefinition({
|
|
700
|
-
name: "my_sdk_task",
|
|
701
|
-
description: "A task created via the SDK",
|
|
702
|
-
ownerEmail: "dev@example.com",
|
|
703
|
-
retryCount: 3,
|
|
704
|
-
});
|
|
275
|
+
import { NonRetryableException } from "@io-orkes/conductor-javascript";
|
|
705
276
|
|
|
706
|
-
|
|
707
|
-
|
|
277
|
+
@worker({ taskDefName: "validate_order" })
|
|
278
|
+
async function validateOrder(task: Task) {
|
|
279
|
+
const order = await getOrder(task.inputData.orderId);
|
|
280
|
+
if (!order) {
|
|
281
|
+
throw new NonRetryableException("Order not found"); // FAILED_WITH_TERMINAL_ERROR
|
|
282
|
+
}
|
|
283
|
+
return { status: "COMPLETED", outputData: { validated: true } };
|
|
284
|
+
}
|
|
708
285
|
```
|
|
709
286
|
|
|
710
|
-
|
|
287
|
+
- `throw new Error()` → Task status: `FAILED` (will retry)
|
|
288
|
+
- `throw new NonRetryableException()` → Task status: `FAILED_WITH_TERMINAL_ERROR` (no retry)
|
|
711
289
|
|
|
712
|
-
|
|
290
|
+
**Long-running tasks with TaskContext** — return `IN_PROGRESS` to keep a task alive while an external process completes. Conductor will call back after the specified interval ([task-context.ts](examples/task-context.ts)):
|
|
713
291
|
|
|
714
292
|
```typescript
|
|
715
|
-
|
|
716
|
-
const wf = {
|
|
717
|
-
name: "my_sdk_workflow",
|
|
718
|
-
version: 1,
|
|
719
|
-
ownerEmail: "dev@example.com",
|
|
720
|
-
tasks: [{
|
|
721
|
-
name: "my_sdk_task",
|
|
722
|
-
taskReferenceName: "my_sdk_task_ref",
|
|
723
|
-
type: "SIMPLE",
|
|
724
|
-
}],
|
|
725
|
-
inputParameters: [],
|
|
726
|
-
timeoutSeconds: 0,
|
|
727
|
-
};
|
|
728
|
-
|
|
729
|
-
// Register the workflow definition
|
|
730
|
-
await metadataClient.registerWorkflowDef(wf);
|
|
731
|
-
```
|
|
732
|
-
|
|
733
|
-
For a complete method reference, see the [MetadataClient API Reference](docs/api-reference/metadata-client.md).
|
|
734
|
-
|
|
735
|
-
## Events
|
|
736
|
-
|
|
737
|
-
Event handlers in Conductor allow you to automatically trigger actions (like starting workflows) when events are received. This enables event-driven workflows and integrations with external systems.
|
|
293
|
+
import { worker, getTaskContext } from "@io-orkes/conductor-javascript";
|
|
738
294
|
|
|
739
|
-
|
|
295
|
+
@worker({ taskDefName: "process_video" })
|
|
296
|
+
async function processVideo(task: Task) {
|
|
297
|
+
const ctx = getTaskContext();
|
|
298
|
+
ctx?.addLog("Starting video processing...");
|
|
740
299
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
Here's how to set up event-driven workflows:
|
|
746
|
-
|
|
747
|
-
#### Step 1: Create an EventClient
|
|
748
|
-
|
|
749
|
-
First, create an instance of the `EventClient`:
|
|
750
|
-
|
|
751
|
-
```typescript
|
|
752
|
-
import { EventClient } from "@io-orkes/conductor-javascript";
|
|
300
|
+
if (!isComplete(task.inputData)) {
|
|
301
|
+
ctx?.setCallbackAfter(30); // check again in 30 seconds
|
|
302
|
+
return { status: "IN_PROGRESS", callbackAfterSeconds: 30 };
|
|
303
|
+
}
|
|
753
304
|
|
|
754
|
-
|
|
305
|
+
return { status: "COMPLETED", outputData: { url: "..." } };
|
|
306
|
+
}
|
|
755
307
|
```
|
|
756
308
|
|
|
757
|
-
|
|
309
|
+
`TaskContext` is also available for one-shot workers — use `ctx?.addLog()` to stream logs visible in the Conductor UI.
|
|
758
310
|
|
|
759
|
-
|
|
311
|
+
**Event listeners** for observability:
|
|
760
312
|
|
|
761
313
|
```typescript
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
{
|
|
769
|
-
action: "start_workflow",
|
|
770
|
-
start_workflow: {
|
|
771
|
-
name: "fulfill_order",
|
|
772
|
-
version: 1,
|
|
773
|
-
input: {
|
|
774
|
-
orderId: "${event.orderId}",
|
|
775
|
-
customerId: "${event.customerId}",
|
|
776
|
-
},
|
|
777
|
-
},
|
|
314
|
+
const handler = new TaskHandler({
|
|
315
|
+
client,
|
|
316
|
+
scanForDecorated: true,
|
|
317
|
+
eventListeners: [{
|
|
318
|
+
onTaskExecutionCompleted(event) {
|
|
319
|
+
metrics.histogram("task_duration_ms", event.durationMs, { task_type: event.taskType });
|
|
778
320
|
},
|
|
779
|
-
|
|
321
|
+
onTaskUpdateFailure(event) {
|
|
322
|
+
alertOps({ severity: "CRITICAL", message: `Task update failed`, taskId: event.taskId });
|
|
323
|
+
},
|
|
324
|
+
}],
|
|
780
325
|
});
|
|
781
326
|
```
|
|
782
327
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
When an event occurs, publish it to Conductor. All active handlers registered for that event will be triggered:
|
|
328
|
+
**Organize workers across files** with module imports:
|
|
786
329
|
|
|
787
330
|
```typescript
|
|
788
|
-
await
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
customerId: "CUST-456",
|
|
792
|
-
amount: "99.99",
|
|
793
|
-
timestamp: Date.now().toString(),
|
|
331
|
+
const handler = await TaskHandler.create({
|
|
332
|
+
client,
|
|
333
|
+
importModules: ["./workers/orderWorkers", "./workers/paymentWorkers"],
|
|
794
334
|
});
|
|
335
|
+
await handler.startWorkers();
|
|
795
336
|
```
|
|
796
337
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
You can monitor event handlers and their execution history:
|
|
800
|
-
|
|
801
|
-
```typescript
|
|
802
|
-
// Get all handlers for a specific event
|
|
803
|
-
const handlers = await eventClient.getEventHandlersForEvent("order.created");
|
|
338
|
+
**Legacy TaskManager API** continues to work with full backward compatibility. New projects should use `@worker` + `TaskHandler` above.
|
|
804
339
|
|
|
805
|
-
|
|
806
|
-
const executions = await eventClient.getEventExecutions("order_created_handler");
|
|
340
|
+
## Monitoring Workers
|
|
807
341
|
|
|
808
|
-
|
|
809
|
-
const messages = await eventClient.getEventMessages("order.created");
|
|
810
|
-
```
|
|
342
|
+
Enable Prometheus metrics with the built-in `MetricsCollector`:
|
|
811
343
|
|
|
812
|
-
|
|
344
|
+
```typescript
|
|
345
|
+
import { MetricsCollector, MetricsServer, TaskHandler } from "@io-orkes/conductor-javascript";
|
|
813
346
|
|
|
814
|
-
|
|
347
|
+
const metrics = new MetricsCollector();
|
|
348
|
+
const server = new MetricsServer(metrics, 9090);
|
|
349
|
+
await server.start();
|
|
815
350
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
active: false, // Deactivate
|
|
821
|
-
// ... other fields
|
|
351
|
+
const handler = new TaskHandler({
|
|
352
|
+
client,
|
|
353
|
+
eventListeners: [metrics],
|
|
354
|
+
scanForDecorated: true,
|
|
822
355
|
});
|
|
823
|
-
|
|
824
|
-
//
|
|
825
|
-
|
|
356
|
+
await handler.startWorkers();
|
|
357
|
+
// GET http://localhost:9090/metrics — Prometheus text format
|
|
358
|
+
// GET http://localhost:9090/health — {"status":"UP"}
|
|
826
359
|
```
|
|
827
360
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
Event handlers support various actions:
|
|
831
|
-
- `start_workflow` - Start a workflow execution
|
|
832
|
-
- `complete_task` - Complete a specific task
|
|
833
|
-
- `fail_task` - Fail a specific task
|
|
834
|
-
- `terminate_workflow` - Terminate a workflow
|
|
835
|
-
- `update_workflow_variables` - Update workflow variables
|
|
836
|
-
|
|
837
|
-
For a complete method reference, see the [EventClient API Reference](docs/api-reference/event-client.md).
|
|
838
|
-
|
|
839
|
-
## Applications
|
|
361
|
+
Collects 18 metric types: poll counts, execution durations, error rates, output sizes, and more — with p50/p75/p90/p95/p99 quantiles. See [METRICS.md](METRICS.md) for the full reference.
|
|
840
362
|
|
|
841
|
-
|
|
363
|
+
## Managing Workflow Executions
|
|
842
364
|
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
The `ApplicationClient` manages applications, access keys, and roles. For a complete method reference, see the [ApplicationClient API Reference](docs/api-reference/application-client.md).
|
|
846
|
-
|
|
847
|
-
### Quick Start: Managing Applications
|
|
848
|
-
|
|
849
|
-
Here's how to create and manage applications in Conductor:
|
|
850
|
-
|
|
851
|
-
#### Step 1: Create an ApplicationClient
|
|
852
|
-
|
|
853
|
-
First, create an instance of the `ApplicationClient`:
|
|
365
|
+
Once a workflow is registered (see [What You Can Build](#what-you-can-build)), you can run and manage it through the full lifecycle:
|
|
854
366
|
|
|
855
367
|
```typescript
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
const appClient = new ApplicationClient(client);
|
|
859
|
-
```
|
|
860
|
-
|
|
861
|
-
#### Step 2: Create an Application
|
|
862
|
-
|
|
863
|
-
Create a new application to represent your service or integration:
|
|
864
|
-
|
|
865
|
-
```typescript
|
|
866
|
-
// Create a new application
|
|
867
|
-
const app = await appClient.createApplication("payment-service");
|
|
868
|
-
console.log(`Created application: ${app.id}`);
|
|
869
|
-
```
|
|
870
|
-
|
|
871
|
-
#### Step 3: Generate Access Keys
|
|
368
|
+
const executor = clients.getWorkflowClient();
|
|
872
369
|
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
const accessKey = await appClient.createAccessKey(app.id);
|
|
878
|
-
console.log(`Key ID: ${accessKey.id}`);
|
|
879
|
-
console.log(`Key Secret: ${accessKey.secret}`); // Save this immediately!
|
|
880
|
-
|
|
881
|
-
// The secret is only shown once - store it securely
|
|
882
|
-
// Use these credentials to create authenticated clients
|
|
883
|
-
const authenticatedClient = await orkesConductorClient({
|
|
884
|
-
serverUrl: "https://play.orkes.io/api",
|
|
885
|
-
keyId: accessKey.id,
|
|
886
|
-
keySecret: accessKey.secret
|
|
370
|
+
// Start (async — returns immediately)
|
|
371
|
+
const workflowId = await executor.startWorkflow({
|
|
372
|
+
name: "order_flow",
|
|
373
|
+
input: { orderId: "ORDER-123" },
|
|
887
374
|
});
|
|
888
|
-
```
|
|
889
|
-
|
|
890
|
-
#### Step 4: Manage Application Roles
|
|
891
|
-
|
|
892
|
-
Grant the application permissions by adding roles:
|
|
893
|
-
|
|
894
|
-
```typescript
|
|
895
|
-
import { ApplicationRole } from "@io-orkes/conductor-javascript";
|
|
896
375
|
|
|
897
|
-
//
|
|
898
|
-
await
|
|
899
|
-
await appClient.addApplicationRole(app.id, "WORKER");
|
|
376
|
+
// Execute (sync — waits for completion)
|
|
377
|
+
const result = await workflow.execute({ orderId: "123" });
|
|
900
378
|
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
379
|
+
// Lifecycle management
|
|
380
|
+
await executor.pause(workflowId);
|
|
381
|
+
await executor.resume(workflowId);
|
|
382
|
+
await executor.terminate(workflowId, "cancelled by user");
|
|
383
|
+
await executor.restart(workflowId);
|
|
384
|
+
await executor.retry(workflowId);
|
|
905
385
|
|
|
906
|
-
|
|
386
|
+
// Signal a running WAIT task
|
|
387
|
+
await executor.signal(workflowId, TaskResultStatusEnum.COMPLETED, { approved: true });
|
|
907
388
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
- `UNRESTRICTED_WORKER` - Can execute any task without restrictions
|
|
912
|
-
- `METADATA_MANAGER` - Manage workflow and task definitions
|
|
913
|
-
- `APPLICATION_MANAGER` - Manage applications and access keys
|
|
914
|
-
- `APPLICATION_CREATOR` - Can create new applications
|
|
915
|
-
- `USER` - Standard user access
|
|
916
|
-
- `USER_READ_ONLY` - Read-only access to resources
|
|
917
|
-
- `METADATA_API` - API access to metadata operations
|
|
918
|
-
- `PROMPT_MANAGER` - Can manage AI prompts and templates
|
|
389
|
+
// Search workflows
|
|
390
|
+
const results = await executor.search("workflowType = 'order_flow' AND status = 'RUNNING'");
|
|
391
|
+
```
|
|
919
392
|
|
|
920
|
-
|
|
393
|
+
See [workflow-ops.ts](examples/workflow-ops.ts) for a runnable example covering all lifecycle operations.
|
|
921
394
|
|
|
922
|
-
|
|
395
|
+
## Troubleshooting
|
|
923
396
|
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
397
|
+
- **Worker stops polling or crashes:** `TaskHandler` monitors and restarts worker polling loops by default. Expose a health check using `handler.running` and `handler.runningWorkerCount`. If you enable metrics, alert on `worker_restart_total`.
|
|
398
|
+
- **HTTP/2 connection errors:** The SDK uses Undici for HTTP/2 when available. If your environment has unstable long-lived connections, the SDK falls back to HTTP/1.1 automatically. You can also provide a custom fetch function: `orkesConductorClient(config, myFetch)`.
|
|
399
|
+
- **Task stuck in SCHEDULED:** Ensure your worker is polling for the correct `taskDefName`. Workers must be started before the workflow is executed.
|
|
400
|
+
|
|
401
|
+
## Examples
|
|
402
|
+
|
|
403
|
+
See the [Examples Guide](examples/README.md) for the full catalog. Key examples:
|
|
404
|
+
|
|
405
|
+
| Example | Description | Run |
|
|
406
|
+
|---------|-------------|-----|
|
|
407
|
+
| [workers-e2e.ts](examples/workers-e2e.ts) | End-to-end: 3 chained workers with verification | `npx ts-node examples/workers-e2e.ts` |
|
|
408
|
+
| [quickstart.ts](examples/quickstart.ts) | 60-second intro: @worker + workflow + execute | `npx ts-node examples/quickstart.ts` |
|
|
409
|
+
| [kitchensink.ts](examples/kitchensink.ts) | All major task types in one workflow | `npx ts-node examples/kitchensink.ts` |
|
|
410
|
+
| [workflow-ops.ts](examples/workflow-ops.ts) | Lifecycle: pause, resume, terminate, retry, search | `npx ts-node examples/workflow-ops.ts` |
|
|
411
|
+
| [test-workflows.ts](examples/test-workflows.ts) | Unit testing with mock outputs (no workers) | `npx ts-node examples/test-workflows.ts` |
|
|
412
|
+
| [metrics.ts](examples/metrics.ts) | Prometheus metrics + HTTP server on :9090 | `npx ts-node examples/metrics.ts` |
|
|
413
|
+
| [express-worker-service.ts](examples/express-worker-service.ts) | Express.js + workers in one process | `npx ts-node examples/express-worker-service.ts` |
|
|
414
|
+
| [function-calling.ts](examples/agentic-workflows/function-calling.ts) | LLM dynamically picks which worker to call | `npx ts-node examples/agentic-workflows/function-calling.ts` |
|
|
415
|
+
| [fork-join.ts](examples/advanced/fork-join.ts) | Parallel branches with join synchronization | `npx ts-node examples/advanced/fork-join.ts` |
|
|
416
|
+
| [sub-workflows.ts](examples/advanced/sub-workflows.ts) | Workflow composition with sub-workflows | `npx ts-node examples/advanced/sub-workflows.ts` |
|
|
417
|
+
| [human-tasks.ts](examples/advanced/human-tasks.ts) | Human-in-the-loop: claim, update, complete | `npx ts-node examples/advanced/human-tasks.ts` |
|
|
418
|
+
|
|
419
|
+
## API Journey Examples
|
|
420
|
+
|
|
421
|
+
End-to-end examples covering all APIs for each domain:
|
|
422
|
+
|
|
423
|
+
| Example | APIs | Run |
|
|
424
|
+
|---------|------|-----|
|
|
425
|
+
| [authorization.ts](examples/api-journeys/authorization.ts) | Authorization APIs (17 calls) | `npx ts-node examples/api-journeys/authorization.ts` |
|
|
426
|
+
| [metadata.ts](examples/api-journeys/metadata.ts) | Metadata APIs (21 calls) | `npx ts-node examples/api-journeys/metadata.ts` |
|
|
427
|
+
| [prompts.ts](examples/api-journeys/prompts.ts) | Prompt APIs (9 calls) | `npx ts-node examples/api-journeys/prompts.ts` |
|
|
428
|
+
| [schedules.ts](examples/api-journeys/schedules.ts) | Schedule APIs (13 calls) | `npx ts-node examples/api-journeys/schedules.ts` |
|
|
429
|
+
| [secrets.ts](examples/api-journeys/secrets.ts) | Secret APIs (12 calls) | `npx ts-node examples/api-journeys/secrets.ts` |
|
|
430
|
+
| [integrations.ts](examples/api-journeys/integrations.ts) | Integration APIs (22 calls) | `npx ts-node examples/api-journeys/integrations.ts` |
|
|
431
|
+
| [schemas.ts](examples/api-journeys/schemas.ts) | Schema APIs (10 calls) | `npx ts-node examples/api-journeys/schemas.ts` |
|
|
432
|
+
| [applications.ts](examples/api-journeys/applications.ts) | Application APIs (20 calls) | `npx ts-node examples/api-journeys/applications.ts` |
|
|
433
|
+
| [event-handlers.ts](examples/api-journeys/event-handlers.ts) | Event Handler APIs (18 calls) | `npx ts-node examples/api-journeys/event-handlers.ts` |
|
|
928
434
|
|
|
929
|
-
|
|
930
|
-
const myApp = await appClient.getApplication(app.id);
|
|
931
|
-
console.log(`Application name: ${myApp.name}`);
|
|
435
|
+
## AI & LLM Workflows
|
|
932
436
|
|
|
933
|
-
|
|
934
|
-
await appClient.updateApplication(app.id, "payment-service-v2");
|
|
437
|
+
Conductor supports AI-native workflows including agentic tool calling, RAG pipelines, and multi-agent orchestration. The SDK provides typed builders for all LLM task types:
|
|
935
438
|
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
439
|
+
| Builder | Description |
|
|
440
|
+
|---------|-------------|
|
|
441
|
+
| `llmChatCompleteTask` | LLM chat completion (OpenAI, Anthropic, etc.) |
|
|
442
|
+
| `llmTextCompleteTask` | Text completion |
|
|
443
|
+
| `llmGenerateEmbeddingsTask` | Generate vector embeddings |
|
|
444
|
+
| `llmIndexDocumentTask` | Index a document into a vector store |
|
|
445
|
+
| `llmIndexTextTask` | Index text into a vector store |
|
|
446
|
+
| `llmSearchIndexTask` | Search a vector index |
|
|
447
|
+
| `llmSearchEmbeddingsTask` | Search by embedding similarity |
|
|
448
|
+
| `llmStoreEmbeddingsTask` | Store pre-computed embeddings |
|
|
449
|
+
| `llmQueryEmbeddingsTask` | Query embeddings |
|
|
450
|
+
| `generateImageTask` | Generate images |
|
|
451
|
+
| `generateAudioTask` | Generate audio |
|
|
452
|
+
| `callMcpToolTask` | Call an MCP tool |
|
|
453
|
+
| `listMcpToolsTask` | List available MCP tools |
|
|
939
454
|
|
|
940
|
-
|
|
941
|
-
await appClient.toggleAccessKeyStatus(app.id, accessKey.id);
|
|
455
|
+
**Example: LLM chat workflow**
|
|
942
456
|
|
|
943
|
-
|
|
944
|
-
|
|
457
|
+
```typescript
|
|
458
|
+
import { ConductorWorkflow, llmChatCompleteTask, Role } from "@io-orkes/conductor-javascript";
|
|
945
459
|
|
|
946
|
-
|
|
947
|
-
|
|
460
|
+
const workflow = new ConductorWorkflow(executor, "ai_chat")
|
|
461
|
+
.add(llmChatCompleteTask("chat_ref", "openai", "gpt-4o", {
|
|
462
|
+
messages: [{ role: Role.USER, message: "${workflow.input.question}" }],
|
|
463
|
+
temperature: 0.7,
|
|
464
|
+
maxTokens: 500,
|
|
465
|
+
}))
|
|
466
|
+
.outputParameters({ answer: "${chat_ref.output.result}" });
|
|
948
467
|
|
|
949
|
-
|
|
950
|
-
await
|
|
468
|
+
await workflow.register();
|
|
469
|
+
const run = await workflow.execute({ question: "What is Conductor?" });
|
|
470
|
+
console.log(run.output?.answer);
|
|
951
471
|
```
|
|
952
472
|
|
|
953
|
-
**
|
|
473
|
+
**Agentic Workflows**
|
|
954
474
|
|
|
955
|
-
|
|
475
|
+
Build AI agents where LLMs dynamically select and call TypeScript workers as tools.
|
|
476
|
+
See [examples/agentic-workflows/](examples/agentic-workflows/) for all examples.
|
|
956
477
|
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
])
|
|
964
|
-
|
|
965
|
-
// Get application tags
|
|
966
|
-
const tags = await appClient.getApplicationTags(app.id);
|
|
967
|
-
|
|
968
|
-
// Delete specific tags
|
|
969
|
-
await appClient.deleteApplicationTag(app.id, {
|
|
970
|
-
key: "cost-center",
|
|
971
|
-
value: "engineering"
|
|
972
|
-
});
|
|
973
|
-
```
|
|
478
|
+
| Example | Description |
|
|
479
|
+
|---------|-------------|
|
|
480
|
+
| [llm-chat.ts](examples/agentic-workflows/llm-chat.ts) | Automated multi-turn conversation between two LLMs |
|
|
481
|
+
| [llm-chat-human-in-loop.ts](examples/agentic-workflows/llm-chat-human-in-loop.ts) | Interactive chat with WAIT tasks for human input |
|
|
482
|
+
| [function-calling.ts](examples/agentic-workflows/function-calling.ts) | LLM dynamically picks which worker function to call |
|
|
483
|
+
| [mcp-weather-agent.ts](examples/agentic-workflows/mcp-weather-agent.ts) | MCP tool discovery and invocation for real-time data |
|
|
484
|
+
| [multiagent-chat.ts](examples/agentic-workflows/multiagent-chat.ts) | Multi-agent debate: optimist vs skeptic with moderator |
|
|
974
485
|
|
|
975
|
-
|
|
486
|
+
**RAG and Vector DB Workflows**
|
|
976
487
|
|
|
977
|
-
|
|
488
|
+
| Example | Description |
|
|
489
|
+
|---------|-------------|
|
|
490
|
+
| [rag-workflow.ts](examples/advanced/rag-workflow.ts) | End-to-end RAG: document indexing → semantic search → LLM answer |
|
|
491
|
+
| [vector-db.ts](examples/advanced/vector-db.ts) | Vector DB operations: embedding generation, storage, search |
|
|
978
492
|
|
|
979
|
-
|
|
493
|
+
## Documentation
|
|
980
494
|
|
|
981
|
-
|
|
495
|
+
| Document | Description |
|
|
496
|
+
|----------|-------------|
|
|
497
|
+
| [SDK Development Guide](SDK_DEVELOPMENT.md) | Architecture, patterns, pitfalls, testing |
|
|
498
|
+
| [Metrics Reference](METRICS.md) | All 18 Prometheus metrics with descriptions |
|
|
499
|
+
| [Breaking Changes](BREAKING_CHANGES.md) | v3.x migration guide |
|
|
500
|
+
| [Workflow Management](docs/api-reference/workflow-executor.md) | Start, pause, resume, terminate, retry, search, signal |
|
|
501
|
+
| [Task Management](docs/api-reference/task-client.md) | Task operations, logs, queue management |
|
|
502
|
+
| [Metadata](docs/api-reference/metadata-client.md) | Task & workflow definitions, tags, rate limits |
|
|
503
|
+
| [Scheduling](docs/api-reference/scheduler-client.md) | Workflow scheduling with CRON expressions |
|
|
504
|
+
| [Authorization](docs/api-reference/authorization-client.md) | Users, groups, permissions |
|
|
505
|
+
| [Applications](docs/api-reference/application-client.md) | Application management, access keys, roles |
|
|
506
|
+
| [Events](docs/api-reference/event-client.md) | Event handlers, event-driven workflows |
|
|
507
|
+
| [Human Tasks](docs/api-reference/human-executor.md) | Human-in-the-loop workflows, form templates |
|
|
508
|
+
| [Service Registry](docs/api-reference/service-registry-client.md) | Service discovery, circuit breakers |
|
|
509
|
+
| [Secrets](docs/api-reference/secret-client.md) | Secret storage and management |
|
|
510
|
+
| [Prompts](docs/api-reference/prompt-client.md) | AI/LLM prompt templates |
|
|
511
|
+
| [Integrations](docs/api-reference/integration-client.md) | AI/LLM provider integrations |
|
|
512
|
+
| [Schemas](docs/api-reference/schema-client.md) | JSON/Avro/Protobuf schema management |
|
|
982
513
|
|
|
983
|
-
|
|
514
|
+
## Support
|
|
984
515
|
|
|
985
|
-
-
|
|
986
|
-
-
|
|
516
|
+
- [Open an issue (SDK)](https://github.com/conductor-oss/javascript-sdk/issues) for SDK bugs, questions, and feature requests
|
|
517
|
+
- [Open an issue (Conductor server)](https://github.com/conductor-oss/conductor/issues) for Conductor OSS server issues
|
|
518
|
+
- [Join the Conductor Slack](https://join.slack.com/t/orkes-conductor/shared_invite/zt-2vdbx239s-Eacdyqya9giNLHfrCavfaA) for community discussion and help
|
|
519
|
+
- [Orkes Community Forum](https://community.orkes.io/) for Q&A
|
|
987
520
|
|
|
988
|
-
|
|
521
|
+
## Frequently Asked Questions
|
|
989
522
|
|
|
990
|
-
|
|
523
|
+
**Is this the same as Netflix Conductor?**
|
|
991
524
|
|
|
992
|
-
|
|
525
|
+
Yes. Conductor OSS is the continuation of the original [Netflix Conductor](https://github.com/Netflix/conductor) repository after Netflix contributed the project to the open-source foundation.
|
|
993
526
|
|
|
994
|
-
|
|
527
|
+
**Is this project actively maintained?**
|
|
995
528
|
|
|
996
|
-
|
|
997
|
-
import { HumanExecutor, TemplateClient } from "@io-orkes/conductor-javascript";
|
|
529
|
+
Yes. [Orkes](https://orkes.io) is the primary maintainer and offers an enterprise SaaS platform for Conductor across all major cloud providers.
|
|
998
530
|
|
|
999
|
-
|
|
1000
|
-
const humanExecutor = new HumanExecutor(client);
|
|
1001
|
-
```
|
|
531
|
+
**Can Conductor scale to handle my workload?**
|
|
1002
532
|
|
|
1003
|
-
|
|
533
|
+
Conductor was built at Netflix to handle massive scale and has been battle-tested in production environments processing millions of workflows. It scales horizontally to meet virtually any demand.
|
|
1004
534
|
|
|
1005
|
-
|
|
535
|
+
**What Node.js versions are supported?**
|
|
1006
536
|
|
|
1007
|
-
|
|
1008
|
-
const formTemplate = {
|
|
1009
|
-
name: "simple_approval_form",
|
|
1010
|
-
version: 1,
|
|
1011
|
-
description: "A simple form for approvals",
|
|
1012
|
-
formTemplate: {
|
|
1013
|
-
name: "Approval Form",
|
|
1014
|
-
fields: [{
|
|
1015
|
-
name: "approved",
|
|
1016
|
-
type: "boolean",
|
|
1017
|
-
required: true,
|
|
1018
|
-
label: "Approve Request",
|
|
1019
|
-
}],
|
|
1020
|
-
},
|
|
1021
|
-
};
|
|
1022
|
-
|
|
1023
|
-
await templateClient.registerTemplate(formTemplate);
|
|
1024
|
-
```
|
|
537
|
+
Node.js 18 and above.
|
|
1025
538
|
|
|
1026
|
-
|
|
539
|
+
**Should I use `@worker` decorator or the legacy `TaskManager`?**
|
|
1027
540
|
|
|
1028
|
-
|
|
541
|
+
Use `@worker` + `TaskHandler` for all new projects. It provides auto-discovery, cleaner code, and better TypeScript integration. The legacy `TaskManager` API is maintained for backward compatibility.
|
|
1029
542
|
|
|
1030
|
-
|
|
1031
|
-
import { humanTask } from "@io-orkes/conductor-javascript";
|
|
1032
|
-
|
|
1033
|
-
// Define the human task
|
|
1034
|
-
const approvalTask = humanTask(
|
|
1035
|
-
"human_approval_ref",
|
|
1036
|
-
"human_approval_task",
|
|
1037
|
-
{ template: "simple_approval_form" }
|
|
1038
|
-
);
|
|
1039
|
-
|
|
1040
|
-
// Define the workflow
|
|
1041
|
-
const approvalWorkflow = {
|
|
1042
|
-
name: "human_approval_workflow",
|
|
1043
|
-
version: 1,
|
|
1044
|
-
tasks: [approvalTask],
|
|
1045
|
-
inputParameters: [],
|
|
1046
|
-
ownerEmail: "dev@example.com",
|
|
1047
|
-
};
|
|
1048
|
-
|
|
1049
|
-
// Register and start the workflow
|
|
1050
|
-
await executor.registerWorkflow(true, approvalWorkflow);
|
|
1051
|
-
const executionId = await executor.startWorkflow({
|
|
1052
|
-
name: "human_approval_workflow",
|
|
1053
|
-
version: 1,
|
|
1054
|
-
});
|
|
1055
|
-
```
|
|
543
|
+
**Can I mix workers written in different languages?**
|
|
1056
544
|
|
|
1057
|
-
|
|
545
|
+
Yes. A single workflow can have workers written in TypeScript, Python, Java, Go, or any other supported language. Workers communicate through the Conductor server, not directly with each other.
|
|
1058
546
|
|
|
1059
|
-
|
|
547
|
+
**How do I run workers in production?**
|
|
1060
548
|
|
|
1061
|
-
|
|
1062
|
-
// Search for pending tasks for a user
|
|
1063
|
-
const pendingTasks = await humanExecutor.search({
|
|
1064
|
-
states: ["PENDING"],
|
|
1065
|
-
// assignees: [{ userType: "EXTERNAL_USER", user: "user@example.com" }],
|
|
1066
|
-
});
|
|
549
|
+
Workers are standard Node.js processes. Deploy them as you would any Node.js application — in containers, VMs, or serverless. Workers poll the Conductor server for tasks, so no inbound ports need to be opened.
|
|
1067
550
|
|
|
1068
|
-
|
|
1069
|
-
const taskId = pendingTasks.results[0].taskId;
|
|
551
|
+
**How do I test workflows without running a full Conductor server?**
|
|
1070
552
|
|
|
1071
|
-
|
|
1072
|
-
await humanExecutor.claimTaskAsExternalUser(taskId, "user@example.com");
|
|
553
|
+
The SDK provides `testWorkflow()` on `WorkflowExecutor` that uses Conductor's `POST /api/workflow/test` endpoint to evaluate workflows with mock task outputs.
|
|
1073
554
|
|
|
1074
|
-
|
|
1075
|
-
await humanExecutor.completeTask(taskId, {
|
|
1076
|
-
output: {
|
|
1077
|
-
approved: true,
|
|
1078
|
-
comments: "Looks good, approved."
|
|
1079
|
-
}
|
|
1080
|
-
});
|
|
555
|
+
**Does the SDK support HTTP/2?**
|
|
1081
556
|
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
557
|
+
Yes. When the optional `undici` package is installed (`npm install undici`), the SDK automatically uses HTTP/2 with connection pooling for better performance.
|
|
558
|
+
|
|
559
|
+
## License
|
|
1085
560
|
|
|
1086
|
-
|
|
561
|
+
Apache 2.0
|