@io-orkes/conductor-javascript 2.1.5 → 2.2.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 +803 -30
- package/dist/index.d.mts +2739 -1931
- package/dist/index.d.ts +2739 -1931
- package/dist/index.js +25653 -2755
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +25668 -2731
- package/dist/index.mjs.map +1 -1
- package/package.json +37 -31
package/README.md
CHANGED
|
@@ -1,55 +1,828 @@
|
|
|
1
|
-
# Conductor OSS
|
|
1
|
+
# Conductor OSS JavaScript/TypeScript SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A comprehensive TypeScript/JavaScript client for [Conductor OSS](https://github.com/conductor-oss/conductor), enabling developers to build, orchestrate, and monitor distributed workflows with ease.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[Conductor](https://www.conductor-oss.org/) is the leading open-source orchestration platform allowing developers to build highly scalable distributed applications.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
2. [Create and run task workers](workers_sdk.md)
|
|
9
|
-
3. [Create workflows using code](workflow_sdk.md)
|
|
10
|
-
|
|
11
|
-
### Setup Conductor Javascript Package
|
|
7
|
+
Check out the [official documentation for Conductor](https://orkes.io/content).
|
|
12
8
|
|
|
13
|
-
|
|
9
|
+
## ⭐ Conductor OSS
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
Show support for the Conductor OSS. Please help spread the awareness by starring Conductor repo.
|
|
12
|
+
|
|
13
|
+
[](https://GitHub.com/conductor-oss/conductor/)
|
|
14
|
+
|
|
15
|
+
## Table of Contents
|
|
16
|
+
|
|
17
|
+
- [Installation](#installation)
|
|
18
|
+
- [Quick Start](#quick-start)
|
|
19
|
+
- [Authentication & Configuration](#authentication--configuration)
|
|
20
|
+
- [Access Control Setup](#access-control-setup)
|
|
21
|
+
- [Configuration Options](#configuration-options)
|
|
22
|
+
- [Environment Variables](#environment-variables)
|
|
23
|
+
- [Custom Fetch Function](#custom-fetch-function)
|
|
24
|
+
- [Core Concepts](#core-concepts)
|
|
25
|
+
- [What are Tasks?](#what-are-tasks)
|
|
26
|
+
- [What are Workflows?](#what-are-workflows)
|
|
27
|
+
- [What are Workers?](#what-are-workers)
|
|
28
|
+
- [What is the Scheduler?](#what-is-the-scheduler)
|
|
29
|
+
- [Task Types](#task-types)
|
|
30
|
+
- [System Tasks - Managed by Conductor Server](#system-tasks---managed-by-conductor-server)
|
|
31
|
+
- [SIMPLE Tasks - Require Custom Workers](#simple-tasks---require-custom-workers)
|
|
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
|
+
- [Human Tasks](#human-tasks)
|
|
66
|
+
- [The HumanExecutor and TemplateClient](#the-humanexecutor-and-templateclient)
|
|
67
|
+
- [Quick Start: Creating and Managing a Human Task](#quick-start-creating-and-managing-a-human-task)
|
|
68
|
+
- [Step 1: Create API Clients](#step-1-create-api-clients)
|
|
69
|
+
- [Step 2: Register a Form Template](#step-2-register-a-form-template)
|
|
70
|
+
- [Step 3: Create a Workflow with a Human Task](#step-3-create-a-workflow-with-a-human-task)
|
|
71
|
+
- [Step 4: Find and Complete the Task](#step-4-find-and-complete-the-task)
|
|
72
|
+
|
|
73
|
+
## Installation
|
|
74
|
+
|
|
75
|
+
Install the SDK using npm or yarn:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npm install @io-orkes/conductor-javascript
|
|
17
79
|
```
|
|
80
|
+
|
|
18
81
|
or
|
|
19
82
|
|
|
20
|
-
```
|
|
83
|
+
```bash
|
|
21
84
|
yarn add @io-orkes/conductor-javascript
|
|
22
85
|
```
|
|
23
86
|
|
|
24
|
-
##
|
|
87
|
+
## Quick Start
|
|
25
88
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
89
|
+
Here's a simple example to get you started:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import {
|
|
93
|
+
orkesConductorClient,
|
|
94
|
+
WorkflowExecutor,
|
|
95
|
+
TaskManager,
|
|
96
|
+
simpleTask,
|
|
97
|
+
workflow
|
|
98
|
+
} from "@io-orkes/conductor-javascript";
|
|
99
|
+
|
|
100
|
+
// 1. Create client
|
|
101
|
+
const client = await orkesConductorClient({
|
|
102
|
+
serverUrl: "https://play.orkes.io/api",
|
|
103
|
+
keyId: "your-key-id",
|
|
104
|
+
keySecret: "your-key-secret"
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// 2. Create workflow executor
|
|
108
|
+
const executor = new WorkflowExecutor(client);
|
|
109
|
+
|
|
110
|
+
// 3. Define a simple workflow
|
|
111
|
+
const myWorkflow = workflow("hello_world", [
|
|
112
|
+
simpleTask("greet_task", "greeting_task", { message: "Hello World!" })
|
|
113
|
+
]);
|
|
114
|
+
|
|
115
|
+
// 4. Register workflow
|
|
116
|
+
await executor.registerWorkflow(true, myWorkflow);
|
|
117
|
+
|
|
118
|
+
// 5. Start workflow execution
|
|
119
|
+
const executionId = await executor.startWorkflow({
|
|
120
|
+
name: "hello_world",
|
|
121
|
+
version: 1,
|
|
122
|
+
input: { name: "Developer" }
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
console.log(`Workflow started with ID: ${executionId}`);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Authentication & Configuration
|
|
30
129
|
|
|
31
130
|
### Access Control Setup
|
|
32
|
-
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 for your environment.
|
|
33
131
|
|
|
34
|
-
|
|
132
|
+
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.
|
|
133
|
+
|
|
134
|
+
### Configuration Options
|
|
35
135
|
|
|
36
136
|
```typescript
|
|
37
|
-
/**
|
|
38
|
-
* Application keys generated from the Application menu > Create Application
|
|
39
|
-
* then edit and create Access Keys
|
|
40
|
-
*
|
|
41
|
-
*/
|
|
42
137
|
import { OrkesApiConfig, orkesConductorClient } from "@io-orkes/conductor-javascript";
|
|
43
138
|
|
|
44
139
|
const config: Partial<OrkesApiConfig> = {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
140
|
+
serverUrl: "https://play.orkes.io/api", // Required: server api url
|
|
141
|
+
keyId: "your-key-id", // Required for server with auth: authentication key
|
|
142
|
+
keySecret: "your-key-secret", // Required for server with auth: authentication secret
|
|
143
|
+
refreshTokenInterval: 0, // Optional: token refresh interval in ms (default: 30 minutes, 0 = no refresh)
|
|
144
|
+
maxHttp2Connections: 1 // Optional: max HTTP2 connections (default: 1)
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const client = await orkesConductorClient(config);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Environment Variables
|
|
151
|
+
|
|
152
|
+
You can configure client using environment variables:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
CONDUCTOR_SERVER_URL=https://play.orkes.io/api
|
|
156
|
+
CONDUCTOR_AUTH_KEY=your-key-id
|
|
157
|
+
CONDUCTOR_AUTH_SECRET=your-key-secret
|
|
158
|
+
CONDUCTOR_REFRESH_TOKEN_INTERVAL=0
|
|
159
|
+
CONDUCTOR_MAX_HTTP2_CONNECTIONS=1
|
|
160
|
+
```
|
|
161
|
+
Environment variables are prioritized over config variables.
|
|
162
|
+
|
|
163
|
+
### Custom Fetch Function
|
|
164
|
+
|
|
165
|
+
You can provide a custom fetch function for SDK HTTP requests:
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
const client = await orkesConductorClient(config, fetch);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Core Concepts
|
|
172
|
+
|
|
173
|
+
### What are Tasks?
|
|
174
|
+
|
|
175
|
+
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.
|
|
176
|
+
|
|
177
|
+
### What are Workflows?
|
|
178
|
+
|
|
179
|
+
Workflows are the main orchestration units in Conductor. They define a sequence of tasks and their dependencies, creating automated business processes. Workflows coordinate task execution, handle failures, manage retries, and ensure your business logic flows correctly from start to finish.
|
|
180
|
+
|
|
181
|
+
### What are Workers?
|
|
182
|
+
|
|
183
|
+
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.
|
|
184
|
+
|
|
185
|
+
### What is the Scheduler?
|
|
186
|
+
The scheduler allows you to schedule workflows to run at specific times or intervals, enabling automated workflow execution based on time-based triggers.
|
|
187
|
+
|
|
188
|
+
## Task Types
|
|
189
|
+
|
|
190
|
+
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**:
|
|
191
|
+
|
|
192
|
+
### System Tasks - Managed by Conductor Server
|
|
193
|
+
|
|
194
|
+
System tasks are fully managed by Conductor. No custom workers needed - just reference them in your workflow and they execute automatically.
|
|
195
|
+
|
|
196
|
+
**Available System Tasks:**
|
|
197
|
+
- **HTTP** - Make HTTP/REST API calls
|
|
198
|
+
- **Inline** - Execute JavaScript expressions
|
|
199
|
+
- **JSON JQ Transform** - Transform JSON data using JQ expressions
|
|
200
|
+
- **Kafka Publish** - Publish messages to Kafka topics
|
|
201
|
+
- **Event** - Publish events to eventing systems
|
|
202
|
+
- **Switch** - Conditional branching based on input
|
|
203
|
+
- **Fork-Join** - Execute tasks in parallel and wait for completion
|
|
204
|
+
- **Dynamic Fork** - Dynamically create parallel task executions
|
|
205
|
+
- **Join** - Join point for forked tasks
|
|
206
|
+
- **Sub-Workflow** - Execute another workflow as a task
|
|
207
|
+
- **Do-While** - Loop execution with conditions
|
|
208
|
+
- **Set Variable** - Set workflow variables
|
|
209
|
+
- **Wait** - Pause workflow for a specified duration
|
|
210
|
+
- **Terminate** - End workflow with success or failure
|
|
211
|
+
- **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.
|
|
212
|
+
|
|
213
|
+
### SIMPLE Tasks - Require Custom Workers
|
|
214
|
+
|
|
215
|
+
SIMPLE tasks execute **your custom business logic**. You must implement workers to handle these tasks.
|
|
216
|
+
|
|
217
|
+
**When to use:**
|
|
218
|
+
- Custom business logic specific to your application
|
|
219
|
+
- Integration with internal systems and databases
|
|
220
|
+
- File processing, data validation, notifications
|
|
221
|
+
- Any functionality not provided by system tasks
|
|
222
|
+
|
|
223
|
+
**How they work:**
|
|
224
|
+
1. Define a SIMPLE task in your workflow
|
|
225
|
+
2. Implement a worker that polls Conductor for this task type
|
|
226
|
+
3. Worker executes your custom logic when task is assigned
|
|
227
|
+
4. Worker reports results back to Conductor
|
|
228
|
+
5. Workflow continues based on task result
|
|
229
|
+
|
|
230
|
+
See the [Workers](#workers) section for implementation details.
|
|
231
|
+
|
|
232
|
+
## Workflows
|
|
233
|
+
|
|
234
|
+
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.
|
|
235
|
+
|
|
236
|
+
### The WorkflowExecutor and TaskClient
|
|
237
|
+
|
|
238
|
+
- **`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).
|
|
239
|
+
- **`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).
|
|
240
|
+
|
|
241
|
+
### Quick Start: Creating a Workflow
|
|
242
|
+
|
|
243
|
+
#### Step 1: Define Your Workflow Structure
|
|
244
|
+
|
|
245
|
+
A workflow definition is a blueprint for your process. It outlines the workflow's properties and the sequence of tasks.
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
const workflowDef = {
|
|
249
|
+
name: "order_fulfillment",
|
|
250
|
+
version: 1,
|
|
251
|
+
description: "Process and fulfill customer orders",
|
|
252
|
+
ownerEmail: "team@example.com",
|
|
253
|
+
tasks: [
|
|
254
|
+
// Tasks will be added in the next step
|
|
255
|
+
],
|
|
256
|
+
inputParameters: ["orderId", "customerId", "productId", "quantity"],
|
|
257
|
+
outputParameters: {
|
|
258
|
+
status: "${route_order_ref.output.status}",
|
|
259
|
+
fulfillmentId: "${fulfill_order_ref.output.fulfillmentId}"
|
|
260
|
+
},
|
|
261
|
+
timeoutSeconds: 3600,
|
|
262
|
+
timeoutPolicy: "ALERT_ONLY"
|
|
263
|
+
};
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
#### Step 2: Use Task Generators to Build Your Task List
|
|
267
|
+
|
|
268
|
+
Use **Task Generators** to populate the `tasks` array. These helper functions simplify the creation of different task types.
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
import { simpleTask, httpTask, switchTask } from "@io-orkes/conductor-javascript";
|
|
272
|
+
|
|
273
|
+
const tasks = [
|
|
274
|
+
// Task 1: A custom task to validate the order
|
|
275
|
+
simpleTask(
|
|
276
|
+
"validate_order_ref",
|
|
277
|
+
"validate_order",
|
|
278
|
+
{
|
|
279
|
+
orderId: "${workflow.input.orderId}",
|
|
280
|
+
customerId: "${workflow.input.customerId}"
|
|
281
|
+
}
|
|
282
|
+
),
|
|
283
|
+
|
|
284
|
+
// Task 2: An HTTP task to check inventory
|
|
285
|
+
httpTask(
|
|
286
|
+
"check_inventory_ref",
|
|
287
|
+
{
|
|
288
|
+
uri: "https://api.inventory.com/check",
|
|
289
|
+
method: "POST",
|
|
290
|
+
body: {
|
|
291
|
+
productId: "${workflow.input.productId}",
|
|
292
|
+
quantity: "${workflow.input.quantity}"
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
),
|
|
296
|
+
|
|
297
|
+
// Task 3: A switch task for conditional logic
|
|
298
|
+
switchTask(
|
|
299
|
+
"route_order_ref",
|
|
300
|
+
"${check_inventory_ref.output.inStock}",
|
|
301
|
+
{
|
|
302
|
+
"true": [
|
|
303
|
+
simpleTask("fulfill_order_ref", "fulfill_order", {})
|
|
304
|
+
],
|
|
305
|
+
"false": [
|
|
306
|
+
simpleTask("backorder_ref", "create_backorder", {})
|
|
307
|
+
]
|
|
308
|
+
}
|
|
309
|
+
)
|
|
310
|
+
];
|
|
311
|
+
|
|
312
|
+
// Add the tasks to your workflow definition
|
|
313
|
+
workflowDef.tasks = tasks;
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**Key Concepts:**
|
|
317
|
+
- **`taskReferenceName`**: A unique identifier for a task instance within a workflow. Used for data flow (e.g., `${check_inventory_ref.output.inStock}`).
|
|
318
|
+
- **Input Parameters**: Use `${workflow.input.fieldName}` to access initial workflow inputs and `${task_ref.output.fieldName}` to access outputs from previous tasks.
|
|
319
|
+
- **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).
|
|
320
|
+
|
|
321
|
+
#### Step 3: Register and Start Your Workflow
|
|
322
|
+
|
|
323
|
+
With the definition complete, register it with Conductor and start an execution.
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
import { WorkflowExecutor } from "@io-orkes/conductor-javascript";
|
|
327
|
+
|
|
328
|
+
// Create WorkflowExecutor instance
|
|
329
|
+
const executor = new WorkflowExecutor(client);
|
|
330
|
+
|
|
331
|
+
// Register the workflow definition (overwrite if it exists)
|
|
332
|
+
await executor.registerWorkflow(true, workflowDef);
|
|
333
|
+
|
|
334
|
+
// Start a workflow execution
|
|
335
|
+
const executionId = await executor.startWorkflow({
|
|
336
|
+
name: "order_fulfillment",
|
|
337
|
+
version: 1,
|
|
338
|
+
input: {
|
|
339
|
+
orderId: "ORDER-123",
|
|
340
|
+
customerId: "CUST-456",
|
|
341
|
+
productId: "PROD-789",
|
|
342
|
+
quantity: 2
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
console.log(`Workflow started with ID: ${executionId}`);
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
#### Step 4: Manage and Monitor Execution
|
|
350
|
+
|
|
351
|
+
Once a workflow is running, you can monitor its status, control its execution, and debug individual tasks.
|
|
352
|
+
|
|
353
|
+
##### Check Workflow Status
|
|
354
|
+
|
|
355
|
+
Retrieve the current status and output of a running workflow.
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
const status = await executor.getWorkflowStatus(
|
|
359
|
+
executionId,
|
|
360
|
+
true, // includeOutput
|
|
361
|
+
true // includeVariables
|
|
362
|
+
);
|
|
363
|
+
console.log(`Workflow status is: ${status.status}`);
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
##### Control Workflow Execution
|
|
367
|
+
|
|
368
|
+
You can pause, resume, or terminate workflows as needed.
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
// Pause a running workflow
|
|
372
|
+
await executor.pause(executionId);
|
|
373
|
+
|
|
374
|
+
// Resume a paused workflow
|
|
375
|
+
await executor.resume(executionId);
|
|
376
|
+
|
|
377
|
+
// Terminate a workflow
|
|
378
|
+
await executor.terminate(executionId, "Aborted due to customer cancellation");
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
##### Search for Workflows
|
|
382
|
+
|
|
383
|
+
Search for workflow executions based on various criteria.
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
const searchResults = await executor.search(
|
|
387
|
+
0,
|
|
388
|
+
10,
|
|
389
|
+
"status:RUNNING AND workflowType:order_fulfillment",
|
|
390
|
+
"*",
|
|
391
|
+
"startTime:DESC"
|
|
392
|
+
);
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
##### Use TaskClient to Monitor and Debug Tasks
|
|
396
|
+
|
|
397
|
+
For a deeper look into the tasks within a workflow, use the `TaskClient`.
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
import { TaskClient } from "@io-orkes/conductor-javascript";
|
|
401
|
+
|
|
402
|
+
const taskClient = new TaskClient(client);
|
|
403
|
+
|
|
404
|
+
// Find all failed tasks for a specific workflow run
|
|
405
|
+
const failedTasks = await taskClient.search(
|
|
406
|
+
0,
|
|
407
|
+
100,
|
|
408
|
+
"startTime:DESC",
|
|
409
|
+
"*",
|
|
410
|
+
`status:FAILED AND workflowId:${executionId}`
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
// Get details of a specific task by its ID
|
|
414
|
+
const taskDetails = await taskClient.getTask(failedTasks.results[0].taskId);
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
For a complete list of methods, see the [WorkflowExecutor API Reference](docs/api-reference/workflow-executor.md) and the [TaskClient API Reference](docs/api-reference/task-client.md).
|
|
418
|
+
|
|
419
|
+
## Workers
|
|
420
|
+
|
|
421
|
+
Workers are background processes that execute tasks in your workflows. Think of them as specialized functions that:
|
|
422
|
+
|
|
423
|
+
1. **Poll** the Conductor server for tasks.
|
|
424
|
+
2. **Execute** your business logic when a task is assigned.
|
|
425
|
+
3. **Report** the results back to the Conductor server.
|
|
426
|
+
|
|
427
|
+
**How Workers Fit In:**
|
|
428
|
+
```
|
|
429
|
+
Workflow → Creates Tasks → Workers Poll for Tasks → Execute Logic → Return Results → Workflow Continues
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
The `TaskManager` class in this SDK simplifies the process of creating and managing workers.
|
|
433
|
+
|
|
434
|
+
### The TaskManager
|
|
435
|
+
|
|
436
|
+
The `TaskManager` is the primary tool for managing workers. It handles polling, task execution, and result reporting, allowing you to run multiple workers concurrently. For a complete method reference, see the [TaskManager API Reference](docs/api-reference/task-manager.md).
|
|
437
|
+
|
|
438
|
+
### Quick Start: Building a Worker
|
|
439
|
+
|
|
440
|
+
Building a robust worker involves defining its logic, handling outcomes, and managing its execution.
|
|
441
|
+
|
|
442
|
+
#### Step 1: Define the Worker's Logic
|
|
443
|
+
|
|
444
|
+
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.
|
|
445
|
+
|
|
446
|
+
```typescript
|
|
447
|
+
import { ConductorWorker } from "@io-orkes/conductor-javascript";
|
|
448
|
+
|
|
449
|
+
const emailWorker: ConductorWorker = {
|
|
450
|
+
// 1. Specify the task name
|
|
451
|
+
taskDefName: "send_email",
|
|
452
|
+
|
|
453
|
+
// 2. Implement the execution logic
|
|
454
|
+
execute: async (task) => {
|
|
455
|
+
const { to, subject, body } = task.inputData;
|
|
456
|
+
|
|
457
|
+
console.log(`Sending email to ${to}: ${subject}`);
|
|
458
|
+
await emailService.send(to, subject, body); // Your business logic
|
|
459
|
+
|
|
460
|
+
// 3. Return a result (covered in the next step)
|
|
461
|
+
return {
|
|
462
|
+
status: "COMPLETED",
|
|
463
|
+
outputData: { sent: true, timestamp: new Date().toISOString() }
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
#### Step 2: Handle Task Outcomes and Errors
|
|
470
|
+
|
|
471
|
+
The `execute` function must return an object indicating the task's outcome.
|
|
472
|
+
|
|
473
|
+
**✅ On Success:**
|
|
474
|
+
Return a `COMPLETED` status and any relevant output data.
|
|
475
|
+
|
|
476
|
+
```typescript
|
|
477
|
+
return {
|
|
478
|
+
status: "COMPLETED",
|
|
479
|
+
outputData: { result: "success", data: processedData }
|
|
49
480
|
};
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
**❌ On Failure:**
|
|
484
|
+
You can control the retry behavior. `FAILED` allows for retries, while `FAILED_WITH_TERMINAL_ERROR` stops the workflow immediately.
|
|
485
|
+
|
|
486
|
+
```typescript
|
|
487
|
+
try {
|
|
488
|
+
// Risky operation
|
|
489
|
+
} catch (error) {
|
|
490
|
+
return {
|
|
491
|
+
status: "FAILED", // Allows for retries
|
|
492
|
+
logs: [{ log: `Error executing task: ${error.message}` }]
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
#### Step 3: Run the Worker with TaskManager
|
|
498
|
+
|
|
499
|
+
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.
|
|
500
|
+
|
|
501
|
+
```typescript
|
|
502
|
+
import { TaskManager } from "@io-orkes/conductor-javascript";
|
|
503
|
+
|
|
504
|
+
// You can pass a single worker or an array of workers
|
|
505
|
+
const workers = [emailWorker, anotherWorker, ...];
|
|
506
|
+
|
|
507
|
+
// Create the TaskManager
|
|
508
|
+
const manager = new TaskManager(client, workers, {
|
|
509
|
+
options: {
|
|
510
|
+
concurrency: 5, // Process up to 5 tasks concurrently
|
|
511
|
+
pollInterval: 100, // Poll every 100ms
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
// Start polling for tasks
|
|
516
|
+
await manager.startPolling();
|
|
517
|
+
console.log("Worker is running!");
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
For a complete method reference, see the [TaskManager API Reference](docs/api-reference/task-manager.md).
|
|
521
|
+
|
|
522
|
+
### Worker Design Principles
|
|
523
|
+
|
|
524
|
+
When designing workers, it's best to follow these principles:
|
|
525
|
+
|
|
526
|
+
- **Stateless**: Workers should not rely on local state.
|
|
527
|
+
- **Idempotent**: The same task input should always produce the same result.
|
|
528
|
+
- **Single Responsibility**: Each worker should be responsible for one specific task type.
|
|
529
|
+
|
|
530
|
+
## Scheduling
|
|
531
|
+
|
|
532
|
+
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.
|
|
533
|
+
|
|
534
|
+
### The SchedulerClient
|
|
535
|
+
|
|
536
|
+
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).
|
|
537
|
+
|
|
538
|
+
### Quick Start: Scheduling a Workflow
|
|
539
|
+
|
|
540
|
+
Here’s how to schedule a workflow in three steps:
|
|
541
|
+
|
|
542
|
+
#### Step 1: Create a SchedulerClient
|
|
543
|
+
|
|
544
|
+
First, create an instance of the `SchedulerClient`:
|
|
545
|
+
|
|
546
|
+
```typescript
|
|
547
|
+
import { SchedulerClient } from "@io-orkes/conductor-javascript";
|
|
548
|
+
|
|
549
|
+
const scheduler = new SchedulerClient(client);
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
#### Step 2: Define the Schedule
|
|
553
|
+
|
|
554
|
+
Next, define the schedule, specifying the workflow to run and the CRON expression for its timing.
|
|
555
|
+
|
|
556
|
+
```typescript
|
|
557
|
+
// Schedule a workflow to run every day at 9 AM
|
|
558
|
+
await scheduler.saveSchedule({
|
|
559
|
+
name: "daily_report_schedule",
|
|
560
|
+
cronExpression: "0 0 9 * * ?", // Everyday at 9am
|
|
561
|
+
startWorkflowRequest: {
|
|
562
|
+
name: "generate_daily_report",
|
|
563
|
+
version: 1,
|
|
564
|
+
input: {
|
|
565
|
+
reportType: "SALES",
|
|
566
|
+
period: "DAILY"
|
|
567
|
+
},
|
|
568
|
+
},
|
|
569
|
+
});
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
**Cron Expression Format:**
|
|
573
|
+
- Standard cron format: `second minute hour day month dayOfWeek`
|
|
574
|
+
- Examples:
|
|
575
|
+
- `"0 0 9 * * ?"` - Every day at 9 AM
|
|
576
|
+
- `"0 */30 * * * ?"` - Every 30 minutes
|
|
577
|
+
- `"0 0 0 1 * ?"` - First day of every month at midnight
|
|
578
|
+
- `"0 0 12 ? * MON-FRI"` - Weekdays at noon
|
|
579
|
+
|
|
580
|
+
#### Step 3: Manage the Schedule
|
|
581
|
+
|
|
582
|
+
You can easily manage your schedules:
|
|
583
|
+
|
|
584
|
+
```typescript
|
|
585
|
+
// Pause a schedule
|
|
586
|
+
await scheduler.pauseSchedule("daily_report_schedule");
|
|
587
|
+
|
|
588
|
+
// Resume a paused schedule
|
|
589
|
+
await scheduler.resumeSchedule("daily_report_schedule");
|
|
590
|
+
|
|
591
|
+
// Delete a schedule
|
|
592
|
+
await scheduler.deleteSchedule("daily_report_schedule");
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
For a complete method reference, see the [SchedulerClient API Reference](docs/api-reference/scheduler-client.md).
|
|
596
|
+
|
|
597
|
+
## Service Registry
|
|
598
|
+
|
|
599
|
+
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.
|
|
600
|
+
|
|
601
|
+
### The ServiceRegistryClient
|
|
602
|
+
|
|
603
|
+
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).
|
|
604
|
+
|
|
605
|
+
### Quick Start: Using the Service Registry
|
|
606
|
+
|
|
607
|
+
Here’s how to get started with the `ServiceRegistryClient`:
|
|
608
|
+
|
|
609
|
+
#### Step 1: Create a ServiceRegistryClient
|
|
610
|
+
|
|
611
|
+
First, create an instance of the `ServiceRegistryClient`:
|
|
612
|
+
|
|
613
|
+
```typescript
|
|
614
|
+
import { ServiceRegistryClient } from "@io-orkes/conductor-javascript";
|
|
615
|
+
|
|
616
|
+
const serviceRegistry = new ServiceRegistryClient(client);
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
#### Step 2: Register a Service
|
|
620
|
+
|
|
621
|
+
Next, register your service with Conductor. This example registers an HTTP service with a circuit breaker configuration.
|
|
622
|
+
|
|
623
|
+
```typescript
|
|
624
|
+
// Register a service with circuit breaker config
|
|
625
|
+
await serviceRegistry.addOrUpdateService({
|
|
626
|
+
name: "user-service",
|
|
627
|
+
type: "HTTP",
|
|
628
|
+
serviceURI: "https://api.example.com/users",
|
|
629
|
+
circuitBreakerConfig: {
|
|
630
|
+
failureRateThreshold: 50.0,
|
|
631
|
+
slidingWindowSize: 10,
|
|
632
|
+
minimumNumberOfCalls: 5,
|
|
633
|
+
waitDurationInOpenState: 60000, // 1 minute
|
|
634
|
+
},
|
|
635
|
+
});
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
#### Step 3: Manage Services
|
|
639
|
+
|
|
640
|
+
You can easily manage your registered services:
|
|
641
|
+
|
|
642
|
+
```typescript
|
|
643
|
+
// Get a list of all registered services
|
|
644
|
+
const services = await serviceRegistry.getRegisteredServices();
|
|
645
|
+
|
|
646
|
+
// Get details for a specific service
|
|
647
|
+
const service = await serviceRegistry.getService("user-service");
|
|
648
|
+
|
|
649
|
+
// Remove a service
|
|
650
|
+
await serviceRegistry.removeService("user-service");
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
For a complete method reference, see the [ServiceRegistryClient API Reference](docs/api-reference/service-registry-client.md).
|
|
654
|
+
|
|
655
|
+
## Metadata
|
|
656
|
+
|
|
657
|
+
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.
|
|
658
|
+
|
|
659
|
+
### The MetadataClient
|
|
660
|
+
|
|
661
|
+
The `MetadataClient` is used to register and manage task and workflow definitions. For a complete method reference, see the [MetadataClient API Reference](docs/api-reference/metadata-client.md).
|
|
662
|
+
|
|
663
|
+
### Quick Start: Managing Metadata
|
|
664
|
+
|
|
665
|
+
Here’s how to manage your task and workflow definitions:
|
|
666
|
+
|
|
667
|
+
#### Step 1: Create a MetadataClient
|
|
668
|
+
|
|
669
|
+
First, create an instance of the `MetadataClient`:
|
|
670
|
+
|
|
671
|
+
```typescript
|
|
672
|
+
import { MetadataClient, taskDefinition, workflowDef } from "@io-orkes/conductor-javascript";
|
|
673
|
+
|
|
674
|
+
const metadataClient = new MetadataClient(client);
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
#### Step 2: Define and Register a Task
|
|
678
|
+
|
|
679
|
+
Create a task definition and register it. The `taskDefinition` factory provides sensible defaults for optional fields.
|
|
680
|
+
|
|
681
|
+
```typescript
|
|
682
|
+
// Define a task
|
|
683
|
+
const taskDef = taskDefinition({
|
|
684
|
+
name: "my_sdk_task",
|
|
685
|
+
description: "A task created via the SDK",
|
|
686
|
+
ownerEmail: "dev@example.com",
|
|
687
|
+
retryCount: 3,
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
// Register the task definition
|
|
691
|
+
await metadataClient.registerTask(taskDef);
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
#### Step 3: Define and Register a Workflow
|
|
695
|
+
|
|
696
|
+
Define your workflow using the task you just registered, and then register the workflow definition.
|
|
697
|
+
|
|
698
|
+
```typescript
|
|
699
|
+
// Define a workflow that uses the task
|
|
700
|
+
const wf = {
|
|
701
|
+
name: "my_sdk_workflow",
|
|
702
|
+
version: 1,
|
|
703
|
+
ownerEmail: "dev@example.com",
|
|
704
|
+
tasks: [{
|
|
705
|
+
name: "my_sdk_task",
|
|
706
|
+
taskReferenceName: "my_sdk_task_ref",
|
|
707
|
+
type: "SIMPLE",
|
|
708
|
+
}],
|
|
709
|
+
inputParameters: [],
|
|
710
|
+
timeoutSeconds: 0,
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
// Register the workflow definition
|
|
714
|
+
await metadataClient.registerWorkflowDef(wf);
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
For a complete method reference, see the [MetadataClient API Reference](docs/api-reference/metadata-client.md).
|
|
718
|
+
|
|
719
|
+
## Human Tasks
|
|
720
|
+
|
|
721
|
+
Human tasks integrate human interaction into your automated workflows. They pause a workflow until a person provides input, such as an approval, a correction, or additional information.
|
|
722
|
+
|
|
723
|
+
Unlike other tasks, human tasks are managed through a dedicated API (`HumanExecutor`) and often involve UI forms (`TemplateClient`). Because they are a type of **system task**, you don't need to create a custom worker to handle them.
|
|
724
|
+
|
|
725
|
+
### The HumanExecutor and TemplateClient
|
|
726
|
+
|
|
727
|
+
- **`HumanExecutor`**: Manages the lifecycle of human tasks—searching, claiming, and completing them. For a complete method reference, see the [HumanExecutor API Reference](docs/api-reference/human-executor.md).
|
|
728
|
+
- **`TemplateClient`**: Manages the UI forms and templates that are presented to users. For a complete method reference, see the [TemplateClient API Reference](docs/api-reference/template-client.md).
|
|
729
|
+
|
|
730
|
+
### Quick Start: Creating and Managing a Human Task
|
|
731
|
+
|
|
732
|
+
This guide walks through creating a simple approval workflow.
|
|
733
|
+
|
|
734
|
+
#### Step 1: Create API Clients
|
|
735
|
+
|
|
736
|
+
You'll need a `TemplateClient` to manage UI forms and a `HumanExecutor` to interact with the tasks themselves.
|
|
737
|
+
|
|
738
|
+
```typescript
|
|
739
|
+
import { HumanExecutor, TemplateClient } from "@io-orkes/conductor-javascript";
|
|
740
|
+
|
|
741
|
+
const templateClient = new TemplateClient(client);
|
|
742
|
+
const humanExecutor = new HumanExecutor(client);
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
#### Step 2: Register a Form Template
|
|
746
|
+
|
|
747
|
+
Define and register a form that will be presented to the user.
|
|
748
|
+
|
|
749
|
+
```typescript
|
|
750
|
+
const formTemplate = {
|
|
751
|
+
name: "simple_approval_form",
|
|
752
|
+
version: 1,
|
|
753
|
+
description: "A simple form for approvals",
|
|
754
|
+
formTemplate: {
|
|
755
|
+
name: "Approval Form",
|
|
756
|
+
fields: [{
|
|
757
|
+
name: "approved",
|
|
758
|
+
type: "boolean",
|
|
759
|
+
required: true,
|
|
760
|
+
label: "Approve Request",
|
|
761
|
+
}],
|
|
762
|
+
},
|
|
763
|
+
};
|
|
764
|
+
|
|
765
|
+
await templateClient.registerTemplate(formTemplate);
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
#### Step 3: Create a Workflow with a Human Task
|
|
769
|
+
|
|
770
|
+
Now, define a workflow that uses the `humanTask` generator. The `taskDefinition` for the human task should specify the template to use.
|
|
771
|
+
|
|
772
|
+
```typescript
|
|
773
|
+
import { humanTask } from "@io-orkes/conductor-javascript";
|
|
774
|
+
|
|
775
|
+
// Define the human task
|
|
776
|
+
const approvalTask = humanTask(
|
|
777
|
+
"human_approval_ref",
|
|
778
|
+
"human_approval_task",
|
|
779
|
+
{ template: "simple_approval_form" }
|
|
780
|
+
);
|
|
781
|
+
|
|
782
|
+
// Define the workflow
|
|
783
|
+
const approvalWorkflow = {
|
|
784
|
+
name: "human_approval_workflow",
|
|
785
|
+
version: 1,
|
|
786
|
+
tasks: [approvalTask],
|
|
787
|
+
inputParameters: [],
|
|
788
|
+
ownerEmail: "dev@example.com",
|
|
789
|
+
};
|
|
790
|
+
|
|
791
|
+
// Register and start the workflow
|
|
792
|
+
await executor.registerWorkflow(true, approvalWorkflow);
|
|
793
|
+
const executionId = await executor.startWorkflow({
|
|
794
|
+
name: "human_approval_workflow",
|
|
795
|
+
version: 1,
|
|
796
|
+
});
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
#### Step 4: Find and Complete the Task
|
|
800
|
+
|
|
801
|
+
In a real application, your backend or UI would search for pending tasks and present them to the user.
|
|
802
|
+
|
|
803
|
+
```typescript
|
|
804
|
+
// Search for pending tasks for a user
|
|
805
|
+
const pendingTasks = await humanExecutor.search({
|
|
806
|
+
states: ["PENDING"],
|
|
807
|
+
// assignees: [{ userType: "EXTERNAL_USER", user: "user@example.com" }],
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
if (pendingTasks.results.length > 0) {
|
|
811
|
+
const taskId = pendingTasks.results[0].taskId;
|
|
812
|
+
|
|
813
|
+
// Claim the task
|
|
814
|
+
await humanExecutor.claimTaskAsExternalUser(taskId, "user@example.com");
|
|
50
815
|
|
|
51
|
-
|
|
816
|
+
// Complete the task with output
|
|
817
|
+
await humanExecutor.completeTask(taskId, {
|
|
818
|
+
output: {
|
|
819
|
+
approved: true,
|
|
820
|
+
comments: "Looks good, approved."
|
|
821
|
+
}
|
|
822
|
+
});
|
|
52
823
|
|
|
824
|
+
console.log(`Task ${taskId} completed.`);
|
|
825
|
+
}
|
|
53
826
|
```
|
|
54
827
|
|
|
55
|
-
|
|
828
|
+
For a complete list of methods, see the [HumanExecutor API Reference](docs/api-reference/human-executor.md) and the [TemplateClient API Reference](docs/api-reference/template-client.md).
|