nestjs-temporal-core 2.0.8 → 3.0.1
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 +114 -563
- package/dist/client/temporal-client.module.d.ts +4 -2
- package/dist/client/temporal-client.module.js +59 -78
- package/dist/client/temporal-client.module.js.map +1 -1
- package/dist/client/temporal-client.service.d.ts +4 -3
- package/dist/client/temporal-client.service.js +43 -27
- package/dist/client/temporal-client.service.js.map +1 -1
- package/dist/client/temporal-schedule.service.d.ts +8 -2
- package/dist/client/temporal-schedule.service.js +86 -65
- package/dist/client/temporal-schedule.service.js.map +1 -1
- package/dist/constants.d.ts +171 -32
- package/dist/constants.js +164 -19
- package/dist/constants.js.map +1 -1
- package/dist/decorators/communication.decorators.d.ts +5 -0
- package/dist/decorators/communication.decorators.js +66 -0
- package/dist/decorators/communication.decorators.js.map +1 -0
- package/dist/decorators/core.decorators.d.ts +6 -0
- package/dist/decorators/core.decorators.js +87 -0
- package/dist/decorators/core.decorators.js.map +1 -0
- package/dist/decorators/index.d.ts +5 -6
- package/dist/decorators/index.js +5 -6
- package/dist/decorators/index.js.map +1 -1
- package/dist/decorators/parameter.decorators.d.ts +2 -0
- package/dist/decorators/parameter.decorators.js +29 -0
- package/dist/decorators/parameter.decorators.js.map +1 -0
- package/dist/decorators/scheduling.decorators.d.ts +4 -0
- package/dist/decorators/scheduling.decorators.js +37 -0
- package/dist/decorators/scheduling.decorators.js.map +1 -0
- package/dist/decorators/workflow-starter.decorator.d.ts +2 -0
- package/dist/decorators/workflow-starter.decorator.js +14 -0
- package/dist/decorators/workflow-starter.decorator.js.map +1 -0
- package/dist/discovery/index.d.ts +2 -0
- package/dist/discovery/index.js +19 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/schedule-manager.service.d.ts +36 -0
- package/dist/discovery/schedule-manager.service.js +215 -0
- package/dist/discovery/schedule-manager.service.js.map +1 -0
- package/dist/discovery/workflow-discovery.service.d.ts +36 -0
- package/dist/discovery/workflow-discovery.service.js +216 -0
- package/dist/discovery/workflow-discovery.service.js.map +1 -0
- package/dist/index.d.ts +15 -8
- package/dist/index.js +27 -11
- package/dist/index.js.map +1 -1
- package/dist/interfaces/core.interface.d.ts +112 -0
- package/dist/interfaces/{base.interface.js → core.interface.js} +1 -1
- package/dist/interfaces/core.interface.js.map +1 -0
- package/dist/interfaces/discovery.interface.d.ts +61 -0
- package/dist/interfaces/{client.interface.js → discovery.interface.js} +1 -1
- package/dist/interfaces/discovery.interface.js.map +1 -0
- package/dist/interfaces/index.d.ts +4 -4
- package/dist/interfaces/index.js +4 -4
- package/dist/interfaces/index.js.map +1 -1
- package/dist/interfaces/scheduling.interface.d.ts +17 -0
- package/dist/interfaces/{temporal.interface.js → scheduling.interface.js} +1 -1
- package/dist/interfaces/scheduling.interface.js.map +1 -0
- package/dist/interfaces/worker.interface.d.ts +20 -17
- package/dist/interfaces/workflow.interface.d.ts +41 -1
- package/dist/temporal.module.d.ts +17 -1
- package/dist/temporal.module.js +120 -53
- package/dist/temporal.module.js.map +1 -1
- package/dist/temporal.service.d.ts +50 -8
- package/dist/temporal.service.js +166 -18
- package/dist/temporal.service.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/worker/index.d.ts +1 -1
- package/dist/worker/index.js +1 -1
- package/dist/worker/index.js.map +1 -1
- package/dist/worker/temporal-metadata.accessor.d.ts +21 -6
- package/dist/worker/temporal-metadata.accessor.js +153 -22
- package/dist/worker/temporal-metadata.accessor.js.map +1 -1
- package/dist/worker/temporal-worker.module.d.ts +1 -1
- package/dist/worker/temporal-worker.module.js +6 -7
- package/dist/worker/temporal-worker.module.js.map +1 -1
- package/dist/worker/worker-manager.service.d.ts +24 -7
- package/dist/worker/worker-manager.service.js +218 -85
- package/dist/worker/worker-manager.service.js.map +1 -1
- package/package.json +50 -18
- package/dist/decorators/activity-method.decorator.d.ts +0 -2
- package/dist/decorators/activity-method.decorator.js +0 -35
- package/dist/decorators/activity-method.decorator.js.map +0 -1
- package/dist/decorators/activity.decorator.d.ts +0 -2
- package/dist/decorators/activity.decorator.js +0 -14
- package/dist/decorators/activity.decorator.js.map +0 -1
- package/dist/decorators/query-method.decorator.d.ts +0 -1
- package/dist/decorators/query-method.decorator.js +0 -17
- package/dist/decorators/query-method.decorator.js.map +0 -1
- package/dist/decorators/signal-method.decorator.d.ts +0 -1
- package/dist/decorators/signal-method.decorator.js +0 -17
- package/dist/decorators/signal-method.decorator.js.map +0 -1
- package/dist/decorators/workflow-method.decorator.d.ts +0 -2
- package/dist/decorators/workflow-method.decorator.js +0 -26
- package/dist/decorators/workflow-method.decorator.js.map +0 -1
- package/dist/decorators/workflow.decorator.d.ts +0 -2
- package/dist/decorators/workflow.decorator.js +0 -16
- package/dist/decorators/workflow.decorator.js.map +0 -1
- package/dist/interfaces/base.interface.d.ts +0 -13
- package/dist/interfaces/base.interface.js.map +0 -1
- package/dist/interfaces/client.interface.d.ts +0 -30
- package/dist/interfaces/client.interface.js.map +0 -1
- package/dist/interfaces/temporal.interface.d.ts +0 -33
- package/dist/interfaces/temporal.interface.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,49 +1,50 @@
|
|
|
1
1
|
# NestJS Temporal Core
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A comprehensive NestJS integration for [Temporal.io](https://temporal.io/) that provides seamless worker and client support with auto-discovery, declarative scheduling, and enterprise-ready features for building reliable distributed applications.
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/nestjs-temporal-core)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](http://www.typescriptlang.org/)
|
|
8
|
+
|
|
9
|
+
## 📚 Documentation
|
|
10
|
+
|
|
11
|
+
### Quick Links
|
|
12
|
+
- **[🚀 Getting Started](./docs/getting-started.md)** - Installation, basic setup, and first workflow
|
|
13
|
+
- **[⚙️ Configuration](./docs/configuration.md)** - Complete configuration reference and examples
|
|
14
|
+
- **[📖 API Reference](./docs/api-reference.md)** - Detailed API documentation for all services and decorators
|
|
15
|
+
- **[🍳 Examples & Recipes](./docs/examples.md)** - Practical examples and common patterns
|
|
4
16
|
|
|
5
17
|
## Overview
|
|
6
18
|
|
|
7
|
-
NestJS Temporal Core makes it easy to integrate Temporal.io with your NestJS applications. Temporal is a durable execution system for reliable microservices and workflow orchestration.
|
|
19
|
+
NestJS Temporal Core makes it easy to integrate Temporal.io with your NestJS applications using familiar decorator patterns. Temporal is a durable execution system for reliable microservices and workflow orchestration.
|
|
8
20
|
|
|
9
|
-
## Features
|
|
21
|
+
## ✨ Features
|
|
10
22
|
|
|
11
23
|
- 🚀 **Easy NestJS Integration** - Simple module registration with unified configuration
|
|
24
|
+
- 🎯 **Auto-Discovery** - Automatic discovery of workflow controllers and scheduled workflows
|
|
12
25
|
- 🔄 **Complete Lifecycle Management** - Automatic worker initialization and graceful shutdown
|
|
13
|
-
-
|
|
14
|
-
-
|
|
26
|
+
- 📋 **Declarative Decorators** - NestJS-style `@WorkflowController`, `@Cron`, `@Interval`, and more
|
|
27
|
+
- 🕐 **Smart Scheduling** - Built-in cron and interval-based workflow scheduling with management
|
|
28
|
+
- 🔌 **Connection Management** - Simplified connection handling with TLS and Temporal Cloud support
|
|
15
29
|
- 🔒 **Type Safety** - Clean, strongly typed interfaces for all Temporal concepts
|
|
16
|
-
- 📡 **Client
|
|
17
|
-
- 📊 **Worker Management** -
|
|
18
|
-
-
|
|
30
|
+
- 📡 **Enhanced Client** - Methods for starting, signaling, and querying workflows with auto-discovery
|
|
31
|
+
- 📊 **Worker Management** - Advanced worker lifecycle control, monitoring, and health checks
|
|
32
|
+
- 🏭 **Production Ready** - Environment-aware configuration, health monitoring, and graceful degradation
|
|
19
33
|
|
|
20
|
-
##
|
|
34
|
+
## 🚀 Quick Start
|
|
35
|
+
|
|
36
|
+
### Installation
|
|
21
37
|
|
|
22
38
|
```bash
|
|
23
39
|
npm install nestjs-temporal-core @temporalio/client @temporalio/worker @temporalio/workflow
|
|
24
40
|
```
|
|
25
41
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
### 1. Enable Shutdown Hooks
|
|
29
|
-
|
|
30
|
-
First, make sure to enable shutdown hooks in your `main.ts` file:
|
|
31
|
-
|
|
32
|
-
```typescript
|
|
33
|
-
async function bootstrap() {
|
|
34
|
-
const app = await NestFactory.create(AppModule);
|
|
35
|
-
app.enableShutdownHooks();
|
|
36
|
-
await app.listen(3000);
|
|
37
|
-
}
|
|
38
|
-
bootstrap();
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### 2. Register the Module
|
|
42
|
+
### Basic Setup
|
|
42
43
|
|
|
43
44
|
```typescript
|
|
45
|
+
// app.module.ts
|
|
44
46
|
import { Module } from '@nestjs/common';
|
|
45
47
|
import { TemporalModule } from 'nestjs-temporal-core';
|
|
46
|
-
import { EmailActivities } from './activities/email.activities';
|
|
47
48
|
|
|
48
49
|
@Module({
|
|
49
50
|
imports: [
|
|
@@ -65,591 +66,141 @@ import { EmailActivities } from './activities/email.activities';
|
|
|
65
66
|
export class AppModule {}
|
|
66
67
|
```
|
|
67
68
|
|
|
68
|
-
###
|
|
69
|
-
|
|
70
|
-
```typescript
|
|
71
|
-
import { Activity, ActivityMethod } from 'nestjs-temporal-core';
|
|
72
|
-
|
|
73
|
-
@Activity()
|
|
74
|
-
export class EmailActivities {
|
|
75
|
-
@ActivityMethod()
|
|
76
|
-
async sendWelcomeEmail(to: string): Promise<boolean> {
|
|
77
|
-
// Implementation
|
|
78
|
-
console.log(`Sending welcome email to ${to}`);
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
@ActivityMethod('sendPromoEmail')
|
|
83
|
-
async sendPromotion(to: string, promoCode: string): Promise<boolean> {
|
|
84
|
-
// Implementation
|
|
85
|
-
console.log(`Sending promo ${promoCode} to ${to}`);
|
|
86
|
-
return true;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### 4. Define Workflows
|
|
92
|
-
|
|
93
|
-
Create a workflow file in your workflows directory:
|
|
94
|
-
|
|
95
|
-
```typescript
|
|
96
|
-
// workflows/email-workflow.ts
|
|
97
|
-
import { proxyActivities } from '@temporalio/workflow';
|
|
98
|
-
|
|
99
|
-
// Activities interface
|
|
100
|
-
interface EmailActivities {
|
|
101
|
-
sendWelcomeEmail(to: string): Promise<boolean>;
|
|
102
|
-
sendPromoEmail(to: string, promoCode: string): Promise<boolean>;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const activities = proxyActivities<EmailActivities>({
|
|
106
|
-
startToCloseTimeout: '30s',
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
export async function sendWelcomeWorkflow(email: string): Promise<boolean> {
|
|
110
|
-
return await activities.sendWelcomeEmail(email);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export async function sendPromoWorkflow(email: string, promoCode: string): Promise<boolean> {
|
|
114
|
-
return await activities.sendPromoEmail(email, promoCode);
|
|
115
|
-
}
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
### 5. Use the Temporal Service
|
|
69
|
+
### Create a Workflow Controller
|
|
119
70
|
|
|
120
71
|
```typescript
|
|
121
|
-
import {
|
|
122
|
-
import { TemporalService } from 'nestjs-temporal-core';
|
|
72
|
+
import { WorkflowController, WorkflowMethod, Cron, Signal, Query } from 'nestjs-temporal-core';
|
|
123
73
|
|
|
124
|
-
@
|
|
125
|
-
export class
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
{
|
|
135
|
-
workflowId: `welcome-${email}-${Date.now()}`,
|
|
136
|
-
},
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
return workflowId;
|
|
74
|
+
@WorkflowController({ taskQueue: 'orders' })
|
|
75
|
+
export class OrderWorkflowController {
|
|
76
|
+
private status = 'pending';
|
|
77
|
+
|
|
78
|
+
@WorkflowMethod()
|
|
79
|
+
async processOrder(orderId: string, customerId: string): Promise<string> {
|
|
80
|
+
this.status = 'processing';
|
|
81
|
+
// Workflow logic here
|
|
82
|
+
this.status = 'completed';
|
|
83
|
+
return this.status;
|
|
140
84
|
}
|
|
141
85
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
retry: {
|
|
150
|
-
maximumAttempts: 3,
|
|
151
|
-
},
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
return workflowId;
|
|
86
|
+
@Cron('0 8 * * *', {
|
|
87
|
+
scheduleId: 'daily-order-report',
|
|
88
|
+
description: 'Generate daily order report'
|
|
89
|
+
})
|
|
90
|
+
@WorkflowMethod()
|
|
91
|
+
async generateDailyReport(): Promise<void> {
|
|
92
|
+
console.log('Generating daily order report...');
|
|
155
93
|
}
|
|
156
|
-
}
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
## Advanced Features
|
|
160
94
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
import { Injectable } from '@nestjs/common';
|
|
165
|
-
import { TemporalService } from 'nestjs-temporal-core';
|
|
166
|
-
|
|
167
|
-
@Injectable()
|
|
168
|
-
export class OrderService {
|
|
169
|
-
constructor(private readonly temporalService: TemporalService) {}
|
|
170
|
-
|
|
171
|
-
async addItemToOrder(orderId: string, item: string): Promise<void> {
|
|
172
|
-
// Signal a running workflow
|
|
173
|
-
await this.temporalService.getClient().signalWorkflow(orderId, 'addItem', [item]);
|
|
95
|
+
@Signal('addItem')
|
|
96
|
+
async addItemToOrder(item: any): Promise<void> {
|
|
97
|
+
console.log('Item added to order:', item);
|
|
174
98
|
}
|
|
175
99
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
return
|
|
100
|
+
@Query('getStatus')
|
|
101
|
+
getOrderStatus(): string {
|
|
102
|
+
return this.status;
|
|
179
103
|
}
|
|
180
104
|
}
|
|
181
105
|
```
|
|
182
106
|
|
|
183
|
-
###
|
|
107
|
+
### Use the Service
|
|
184
108
|
|
|
185
109
|
```typescript
|
|
186
110
|
import { Injectable } from '@nestjs/common';
|
|
187
111
|
import { TemporalService } from 'nestjs-temporal-core';
|
|
188
112
|
|
|
189
113
|
@Injectable()
|
|
190
|
-
export class
|
|
114
|
+
export class OrderService {
|
|
191
115
|
constructor(private readonly temporalService: TemporalService) {}
|
|
192
116
|
|
|
193
|
-
async
|
|
194
|
-
const
|
|
195
|
-
'
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
'reports-queue',
|
|
199
|
-
['daily-summary'],
|
|
117
|
+
async processOrder(orderId: string, customerId: string): Promise<string> {
|
|
118
|
+
const { workflowId } = await this.temporalService.startWorkflow(
|
|
119
|
+
'processOrder',
|
|
120
|
+
[orderId, customerId],
|
|
121
|
+
{ workflowId: `order-${orderId}` }
|
|
200
122
|
);
|
|
201
123
|
|
|
202
|
-
return
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
async pauseReporting(): Promise<void> {
|
|
206
|
-
await this.temporalService
|
|
207
|
-
.getScheduleService()
|
|
208
|
-
.pauseSchedule('daily-report', 'Paused for maintenance');
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
async resumeReporting(): Promise<void> {
|
|
212
|
-
await this.temporalService.getScheduleService().resumeSchedule('daily-report');
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
## Configuration Options
|
|
218
|
-
|
|
219
|
-
### Async Configuration
|
|
220
|
-
|
|
221
|
-
```typescript
|
|
222
|
-
import { Module } from '@nestjs/common';
|
|
223
|
-
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
224
|
-
import { TemporalModule } from 'nestjs-temporal-core';
|
|
225
|
-
import { EmailActivities } from './activities/email.activities';
|
|
226
|
-
|
|
227
|
-
@Module({
|
|
228
|
-
imports: [
|
|
229
|
-
ConfigModule.forRoot(),
|
|
230
|
-
TemporalModule.registerAsync({
|
|
231
|
-
imports: [ConfigModule],
|
|
232
|
-
inject: [ConfigService],
|
|
233
|
-
useFactory: (configService: ConfigService) => ({
|
|
234
|
-
connection: {
|
|
235
|
-
address: configService.get('TEMPORAL_ADDRESS'),
|
|
236
|
-
namespace: configService.get('TEMPORAL_NAMESPACE'),
|
|
237
|
-
apiKey: configService.get('TEMPORAL_API_KEY'),
|
|
238
|
-
},
|
|
239
|
-
taskQueue: configService.get('TEMPORAL_TASK_QUEUE'),
|
|
240
|
-
worker: {
|
|
241
|
-
workflowsPath: './dist/workflows',
|
|
242
|
-
activityClasses: [EmailActivities],
|
|
243
|
-
},
|
|
244
|
-
|
|
245
|
-
isGlobal: true,
|
|
246
|
-
}),
|
|
247
|
-
}),
|
|
248
|
-
],
|
|
249
|
-
})
|
|
250
|
-
export class AppModule {}
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### Secure Connection with TLS
|
|
254
|
-
|
|
255
|
-
```typescript
|
|
256
|
-
TemporalModule.register({
|
|
257
|
-
connection: {
|
|
258
|
-
address: 'temporal.example.com:7233',
|
|
259
|
-
namespace: 'production',
|
|
260
|
-
tls: {
|
|
261
|
-
// Simple boolean for default TLS
|
|
262
|
-
// tls: true,
|
|
263
|
-
|
|
264
|
-
// Or detailed configuration
|
|
265
|
-
serverName: 'temporal.example.com',
|
|
266
|
-
clientCertPair: {
|
|
267
|
-
crt: fs.readFileSync('./certs/client.crt'),
|
|
268
|
-
key: fs.readFileSync('./certs/client.key'),
|
|
269
|
-
ca: fs.readFileSync('./certs/ca.crt'),
|
|
270
|
-
},
|
|
271
|
-
},
|
|
272
|
-
// For Temporal Cloud
|
|
273
|
-
apiKey: process.env.TEMPORAL_API_KEY,
|
|
274
|
-
},
|
|
275
|
-
// ...other options
|
|
276
|
-
});
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
## API Reference
|
|
282
|
-
|
|
283
|
-
### Core Modules
|
|
284
|
-
|
|
285
|
-
- `TemporalModule` - Unified module for both client and worker functionality
|
|
286
|
-
- `TemporalClientModule` - Client-only module for workflow operations
|
|
287
|
-
- `TemporalWorkerModule` - Worker-only module for running activities
|
|
288
|
-
|
|
289
|
-
### Decorators
|
|
290
|
-
|
|
291
|
-
- `@Activity(options?)` - Marks a class as a Temporal activity
|
|
292
|
-
- `@ActivityMethod(options?)` - Marks a method as an activity implementation
|
|
293
|
-
- `@Workflow(options)` - Marks a class as a Temporal workflow
|
|
294
|
-
- `@WorkflowMethod(options?)` - Marks the primary workflow execution method
|
|
295
|
-
- `@SignalMethod(name?)` - Marks a method as a signal handler
|
|
296
|
-
- `@QueryMethod(name?)` - Marks a method as a query handler
|
|
297
|
-
|
|
298
|
-
### Services
|
|
299
|
-
|
|
300
|
-
#### TemporalService
|
|
301
|
-
|
|
302
|
-
- `getClient()` - Get the client service
|
|
303
|
-
- `getScheduleService()` - Get the schedule service
|
|
304
|
-
- `getWorkerManager()` - Get the worker manager (if available)
|
|
305
|
-
- `startWorkflow()` - Simplified method to start a workflow
|
|
306
|
-
- `hasWorker()` - Check if worker functionality is available
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
#### TemporalClientService
|
|
310
|
-
|
|
311
|
-
- `startWorkflow()` - Start a new workflow execution
|
|
312
|
-
- `signalWorkflow()` - Send a signal to a running workflow
|
|
313
|
-
- `queryWorkflow()` - Query a running workflow
|
|
314
|
-
- `terminateWorkflow()` - Terminate a running workflow
|
|
315
|
-
- `cancelWorkflow()` - Request cancellation of a workflow
|
|
316
|
-
- `getWorkflowHandle()` - Get a handle to manage a workflow
|
|
317
|
-
- `describeWorkflow()` - Get workflow execution details
|
|
318
|
-
- `listWorkflows()` - List workflows matching a query
|
|
319
|
-
|
|
320
|
-
#### TemporalScheduleService
|
|
321
|
-
|
|
322
|
-
- `createCronWorkflow()` - Create a workflow scheduled by cron expression
|
|
323
|
-
- `createIntervalWorkflow()` - Create a workflow scheduled by time interval
|
|
324
|
-
- `pauseSchedule()` - Pause a schedule
|
|
325
|
-
- `resumeSchedule()` - Resume a paused schedule
|
|
326
|
-
- `deleteSchedule()` - Delete a schedule
|
|
327
|
-
- `triggerNow()` - Trigger an immediate execution
|
|
328
|
-
- `listSchedules()` - List all schedules
|
|
329
|
-
|
|
330
|
-
#### WorkerManager
|
|
331
|
-
|
|
332
|
-
- `startWorker()` - Manually start the worker
|
|
333
|
-
- `shutdown()` - Gracefully shutdown the worker
|
|
334
|
-
- `getWorker()` - Get the underlying worker instance
|
|
335
|
-
|
|
336
|
-
## Project Structure
|
|
337
|
-
|
|
338
|
-
When integrating Temporal with your NestJS application, organizing your code properly helps maintain separation of concerns and follows NestJS conventions. Here's a recommended project structure:
|
|
339
|
-
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
```
|
|
343
|
-
src/
|
|
344
|
-
├── temporal/
|
|
345
|
-
│ ├── activities/
|
|
346
|
-
│ │ ├── email.activities.ts
|
|
347
|
-
│ │ ├── payment.activities.ts
|
|
348
|
-
│ │ └── index.ts
|
|
349
|
-
│ ├── workflows/
|
|
350
|
-
│ │ ├── email-workflows.ts
|
|
351
|
-
│ │ ├── payment-workflows.ts
|
|
352
|
-
│ │ └── index.ts
|
|
353
|
-
│ ├── interfaces/
|
|
354
|
-
│ │ ├── email.interfaces.ts
|
|
355
|
-
│ │ └── payment.interfaces.ts
|
|
356
|
-
│ └── temporal.module.ts
|
|
357
|
-
├── modules/
|
|
358
|
-
│ ├── email/
|
|
359
|
-
│ │ ├── email.service.ts
|
|
360
|
-
│ │ ├── email.controller.ts
|
|
361
|
-
│ │ └── email.module.ts
|
|
362
|
-
│ └── payment/
|
|
363
|
-
│ ├── payment.service.ts
|
|
364
|
-
│ ├── payment.controller.ts
|
|
365
|
-
│ └── payment.module.ts
|
|
366
|
-
└── app.module.ts
|
|
367
|
-
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
### Key Files and Their Purpose
|
|
371
|
-
|
|
372
|
-
1. **Activities (src/temporal/activities/)**:
|
|
373
|
-
|
|
374
|
-
- Contains activity classes decorated with `@Activity()`
|
|
375
|
-
- Each activity class should group related functionality
|
|
376
|
-
|
|
377
|
-
2. **Workflows (src/temporal/workflows/)**:
|
|
378
|
-
|
|
379
|
-
- Contains workflow definitions that orchestrate activities
|
|
380
|
-
- Workflows should be in separate files based on domain
|
|
381
|
-
|
|
382
|
-
3. **Interfaces (src/temporal/interfaces/)**:
|
|
383
|
-
|
|
384
|
-
- TypeScript interfaces that define activity and workflow parameters/returns
|
|
385
|
-
- Helps maintain type safety between activities and workflows
|
|
386
|
-
|
|
387
|
-
4. **Temporal Module (src/temporal/temporal.module.ts)**:
|
|
388
|
-
|
|
389
|
-
- Centralizes Temporal configuration
|
|
390
|
-
- Imports and registers all activities
|
|
391
|
-
|
|
392
|
-
5. **Business Services (src/modules/\*/)**:
|
|
393
|
-
- Inject the TemporalService
|
|
394
|
-
- Use it to start workflows and interact with Temporal
|
|
395
|
-
|
|
396
|
-
## Integration Examples
|
|
397
|
-
|
|
398
|
-
### Activity Definition
|
|
399
|
-
|
|
400
|
-
```typescript
|
|
401
|
-
// src/temporal/activities/email.activities.ts
|
|
402
|
-
import { Activity, ActivityMethod } from 'nestjs-temporal-core';
|
|
403
|
-
import { Injectable } from '@nestjs/common';
|
|
404
|
-
import { EmailService } from '../../modules/email/email.service';
|
|
405
|
-
|
|
406
|
-
@Injectable()
|
|
407
|
-
@Activity()
|
|
408
|
-
export class EmailActivities {
|
|
409
|
-
constructor(private readonly emailService: EmailService) {}
|
|
410
|
-
|
|
411
|
-
@ActivityMethod()
|
|
412
|
-
async sendWelcomeEmail(to: string, name: string): Promise<boolean> {
|
|
413
|
-
await this.emailService.sendEmail({
|
|
414
|
-
to,
|
|
415
|
-
subject: 'Welcome!',
|
|
416
|
-
body: `Hello ${name}, welcome to our platform!`,
|
|
417
|
-
});
|
|
418
|
-
return true;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
@ActivityMethod()
|
|
422
|
-
async sendPasswordReset(to: string, resetToken: string): Promise<boolean> {
|
|
423
|
-
await this.emailService.sendEmail({
|
|
424
|
-
to,
|
|
425
|
-
subject: 'Password Reset',
|
|
426
|
-
body: `Please use this token to reset your password: ${resetToken}`,
|
|
427
|
-
});
|
|
428
|
-
return true;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
```
|
|
432
|
-
|
|
433
|
-
```typescript
|
|
434
|
-
// src/temporal/activities/index.ts
|
|
435
|
-
export * from './email.activities';
|
|
436
|
-
export * from './payment.activities';
|
|
437
|
-
// Export all other activity classes
|
|
438
|
-
```
|
|
439
|
-
|
|
440
|
-
### Workflow Definition
|
|
441
|
-
|
|
442
|
-
```typescript
|
|
443
|
-
// src/temporal/workflows/email-workflows.ts
|
|
444
|
-
import { proxyActivities } from '@temporalio/workflow';
|
|
445
|
-
|
|
446
|
-
// Define the interface of activities this workflow will use
|
|
447
|
-
export interface EmailActivities {
|
|
448
|
-
sendWelcomeEmail(to: string, name: string): Promise<boolean>;
|
|
449
|
-
sendPasswordReset(to: string, resetToken: string): Promise<boolean>;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
// Create a proxy to the activities
|
|
453
|
-
const activities = proxyActivities<EmailActivities>({
|
|
454
|
-
startToCloseTimeout: '30 seconds',
|
|
455
|
-
});
|
|
456
|
-
|
|
457
|
-
// Welcome workflow with retry logic
|
|
458
|
-
export async function welcomeUserWorkflow(email: string, name: string): Promise<boolean> {
|
|
459
|
-
let attempts = 0;
|
|
460
|
-
const maxAttempts = 3;
|
|
461
|
-
|
|
462
|
-
while (attempts < maxAttempts) {
|
|
463
|
-
try {
|
|
464
|
-
return await activities.sendWelcomeEmail(email, name);
|
|
465
|
-
} catch (error) {
|
|
466
|
-
attempts++;
|
|
467
|
-
if (attempts >= maxAttempts) {
|
|
468
|
-
throw error;
|
|
469
|
-
}
|
|
470
|
-
// Wait before retrying
|
|
471
|
-
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
472
|
-
}
|
|
124
|
+
return workflowId;
|
|
473
125
|
}
|
|
474
|
-
|
|
475
|
-
return false;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
// Password reset workflow
|
|
479
|
-
export async function passwordResetWorkflow(email: string, resetToken: string): Promise<boolean> {
|
|
480
|
-
return await activities.sendPasswordReset(email, resetToken);
|
|
481
126
|
}
|
|
482
127
|
```
|
|
483
128
|
|
|
484
|
-
|
|
129
|
+
## 📖 Core Concepts
|
|
485
130
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
import { proxyActivities } from '@temporalio/workflow';
|
|
131
|
+
### Workflow Controllers
|
|
132
|
+
New NestJS-style controllers for defining workflows with auto-discovery and declarative scheduling.
|
|
489
133
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
emailReportToAdmins(reportUrl: string): Promise<boolean>;
|
|
493
|
-
}
|
|
134
|
+
### Activities
|
|
135
|
+
Reusable business logic components that can be called from workflows.
|
|
494
136
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
});
|
|
137
|
+
### Scheduling
|
|
138
|
+
Built-in support for cron and interval-based workflow scheduling using decorators.
|
|
498
139
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
const reportUrl = await activities.generateDailyReport();
|
|
502
|
-
await activities.emailReportToAdmins(reportUrl);
|
|
503
|
-
}
|
|
504
|
-
```
|
|
140
|
+
### Auto-Discovery
|
|
141
|
+
Automatic detection and registration of workflow controllers and scheduled workflows.
|
|
505
142
|
|
|
506
|
-
|
|
143
|
+
## 🏗️ Architecture
|
|
507
144
|
|
|
508
|
-
```typescript
|
|
509
|
-
// src/temporal/temporal.module.ts
|
|
510
|
-
import { Module } from '@nestjs/common';
|
|
511
|
-
import { TemporalModule } from 'nestjs-temporal-core';
|
|
512
|
-
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
513
|
-
import * as path from 'path';
|
|
514
|
-
import { EmailActivities, PaymentActivities } from './activities';
|
|
515
|
-
import { EmailModule } from '../modules/email/email.module';
|
|
516
|
-
import { PaymentModule } from '../modules/payment/payment.module';
|
|
517
|
-
|
|
518
|
-
@Module({
|
|
519
|
-
imports: [
|
|
520
|
-
EmailModule,
|
|
521
|
-
PaymentModule,
|
|
522
|
-
TemporalModule.registerAsync({
|
|
523
|
-
imports: [ConfigModule],
|
|
524
|
-
inject: [ConfigService],
|
|
525
|
-
useFactory: (configService: ConfigService) => ({
|
|
526
|
-
connection: {
|
|
527
|
-
address: configService.get('TEMPORAL_ADDRESS', 'localhost:7233'),
|
|
528
|
-
namespace: configService.get('TEMPORAL_NAMESPACE', 'default'),
|
|
529
|
-
},
|
|
530
|
-
taskQueue: configService.get('TEMPORAL_TASK_QUEUE', 'my-app-queue'),
|
|
531
|
-
worker: {
|
|
532
|
-
workflowsPath: path.resolve(__dirname, 'workflows'),
|
|
533
|
-
activityClasses: [EmailActivities, PaymentActivities],
|
|
534
|
-
autoStart: true,
|
|
535
|
-
},
|
|
536
|
-
isGlobal: true,
|
|
537
|
-
}),
|
|
538
|
-
}),
|
|
539
|
-
],
|
|
540
|
-
providers: [EmailActivities, PaymentActivities],
|
|
541
|
-
exports: [TemporalModule],
|
|
542
|
-
})
|
|
543
|
-
export class TemporalAppModule {}
|
|
544
145
|
```
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
@Injectable()
|
|
554
|
-
export class EmailService {
|
|
555
|
-
constructor(private readonly temporalService: TemporalService) {}
|
|
556
|
-
|
|
557
|
-
// Your actual email sending functionality
|
|
558
|
-
async sendEmail(options: { to: string; subject: string; body: string }): Promise<void> {
|
|
559
|
-
// Implementation...
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
// Triggering a Temporal workflow
|
|
563
|
-
async sendWelcomeEmail(email: string, name: string): Promise<string> {
|
|
564
|
-
const { workflowId } = await this.temporalService.startWorkflow(
|
|
565
|
-
'welcomeUserWorkflow',
|
|
566
|
-
[email, name],
|
|
567
|
-
'my-app-queue',
|
|
568
|
-
{ workflowId: `welcome-${email}-${Date.now()}` },
|
|
569
|
-
);
|
|
570
|
-
|
|
571
|
-
return workflowId;
|
|
572
|
-
}
|
|
573
|
-
}
|
|
146
|
+
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
|
|
147
|
+
│ NestJS App │ │ Temporal Server │ │ Worker Process │
|
|
148
|
+
│ │ │ │ │ │
|
|
149
|
+
│ ┌─────────────┐ │ │ ┌──────────────┐ │ │ ┌─────────────┐ │
|
|
150
|
+
│ │ Controllers │ │───▶│ │ Workflows │ │───▶│ │ Activities │ │
|
|
151
|
+
│ │ Services │ │ │ │ Schedules │ │ │ │ Workers │ │
|
|
152
|
+
│ └─────────────┘ │ │ └──────────────┘ │ │ └─────────────┘ │
|
|
153
|
+
└─────────────────┘ └──────────────────┘ └─────────────────┘
|
|
574
154
|
```
|
|
575
155
|
|
|
576
|
-
|
|
156
|
+
## 🎯 Use Cases
|
|
577
157
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
constructor(private readonly temporalService: TemporalService) {}
|
|
586
|
-
|
|
587
|
-
async onModuleInit() {
|
|
588
|
-
// Set up scheduled workflows when the module initializes
|
|
589
|
-
await this.setupDailyReport();
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
private async setupDailyReport() {
|
|
593
|
-
try {
|
|
594
|
-
// Check if the schedule already exists
|
|
595
|
-
const schedules = await this.temporalService.getScheduleService().listSchedules();
|
|
596
|
-
|
|
597
|
-
if (!schedules.some((s) => s.scheduleId === 'daily-report')) {
|
|
598
|
-
// Create a new schedule
|
|
599
|
-
await this.temporalService.getScheduleService().createCronWorkflow(
|
|
600
|
-
'daily-report',
|
|
601
|
-
'dailyReportWorkflow',
|
|
602
|
-
'0 8 * * *', // Run every day at 8 AM
|
|
603
|
-
'my-app-queue',
|
|
604
|
-
[], // No arguments needed for this workflow
|
|
605
|
-
'Daily business report generation',
|
|
606
|
-
);
|
|
607
|
-
|
|
608
|
-
console.log('Daily report schedule created');
|
|
609
|
-
}
|
|
610
|
-
} catch (error) {
|
|
611
|
-
console.error('Failed to set up daily report schedule:', error);
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
```
|
|
158
|
+
- **Order Processing** - Reliable order fulfillment with compensation
|
|
159
|
+
- **Payment Processing** - Multi-step payment flows with retries
|
|
160
|
+
- **Data Pipelines** - Long-running data processing workflows
|
|
161
|
+
- **Scheduled Jobs** - Cron-based and interval-based background tasks
|
|
162
|
+
- **Saga Patterns** - Distributed transaction management
|
|
163
|
+
- **Human Tasks** - Workflows requiring human intervention
|
|
164
|
+
- **Microservice Orchestration** - Coordinating multiple services
|
|
616
165
|
|
|
617
|
-
##
|
|
166
|
+
## 🌟 What's New in v3.0
|
|
618
167
|
|
|
619
|
-
|
|
168
|
+
- **🎮 Workflow Controllers** - NestJS-style workflow definition
|
|
169
|
+
- **📅 Declarative Scheduling** - `@Cron` and `@Interval` decorators
|
|
170
|
+
- **🔍 Auto-Discovery** - Automatic workflow and schedule detection
|
|
171
|
+
- **📊 Enhanced Monitoring** - Built-in health checks and metrics
|
|
172
|
+
- **🏭 Production Features** - Worker presets, graceful shutdown, error handling
|
|
173
|
+
- **🔧 Better Developer Experience** - Improved APIs and TypeScript support
|
|
620
174
|
|
|
621
|
-
|
|
622
|
-
- Set appropriate timeouts for expected durations
|
|
623
|
-
- Use dependency injection within activity classes
|
|
175
|
+
## 📦 Packages
|
|
624
176
|
|
|
625
|
-
|
|
177
|
+
| Package | Version | Description |
|
|
178
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------ |
|
|
179
|
+
| `nestjs-temporal-core` | [](https://www.npmjs.com/package/nestjs-temporal-core) | Main integration package |
|
|
180
|
+
| `@temporalio/client` | [](https://www.npmjs.com/package/@temporalio/client) | Temporal client library |
|
|
181
|
+
| `@temporalio/worker` | [](https://www.npmjs.com/package/@temporalio/worker) | Temporal worker library |
|
|
182
|
+
| `@temporalio/workflow` | [](https://www.npmjs.com/package/@temporalio/workflow) | Workflow runtime library |
|
|
626
183
|
|
|
627
|
-
|
|
628
|
-
- Use signals for external events
|
|
629
|
-
- Use queries for retrieving workflow state
|
|
630
|
-
- Separate workflows by domain/function
|
|
184
|
+
## 🤝 Community
|
|
631
185
|
|
|
632
|
-
|
|
186
|
+
- **GitHub Discussions** - Ask questions and share ideas
|
|
187
|
+
- **Issues** - Report bugs and request features
|
|
188
|
+
- **Pull Requests** - Contribute to the project
|
|
633
189
|
|
|
634
|
-
|
|
635
|
-
- Configure appropriate timeouts for activities and workflows
|
|
636
|
-
- Implement proper error handling
|
|
190
|
+
## 📄 License
|
|
637
191
|
|
|
638
|
-
|
|
192
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
639
193
|
|
|
640
|
-
|
|
641
|
-
- Configure proper worker shutdown grace periods
|
|
642
|
-
- Consider using OnModuleInit to set up schedules
|
|
194
|
+
## 👨💻 Author
|
|
643
195
|
|
|
644
|
-
|
|
645
|
-
- Implement proper TLS security for production environments
|
|
646
|
-
- Use namespaces to isolate different environments
|
|
647
|
-
- Use API keys for Temporal Cloud authentication
|
|
196
|
+
**Harsh M** - [GitHub](https://github.com/harsh-simform)
|
|
648
197
|
|
|
649
|
-
##
|
|
198
|
+
## 🙏 Acknowledgments
|
|
650
199
|
|
|
651
|
-
|
|
200
|
+
- [Temporal.io](https://temporal.io/) - For the amazing workflow engine
|
|
201
|
+
- [NestJS](https://nestjs.com/) - For the incredible framework
|
|
202
|
+
- [TypeScript](https://www.typescriptlang.org/) - For making JavaScript enjoyable
|
|
652
203
|
|
|
653
|
-
|
|
204
|
+
---
|
|
654
205
|
|
|
655
|
-
|
|
206
|
+
**[📚 Continue to Getting Started →](./docs/getting-started.md)**
|