nestjs-temporal-core 2.0.7 → 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 +124 -558
- 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 +51 -19
- 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,60 @@
|
|
|
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
|
|
16
|
+
- **[🏗️ Best Practices](./docs/best-practices.md)** - Production guidelines and optimization tips
|
|
17
|
+
- **[🔄 Migration Guide](./docs/migration.md)** - Upgrading from previous versions
|
|
18
|
+
- **[🔧 Troubleshooting](./docs/troubleshooting.md)** - Common issues and solutions
|
|
19
|
+
|
|
20
|
+
### Advanced Topics
|
|
21
|
+
- **[🏢 Enterprise Features](./docs/enterprise.md)** - Advanced features for production deployments
|
|
22
|
+
- **[📊 Monitoring & Health](./docs/monitoring.md)** - Health checks, metrics, and observability
|
|
23
|
+
- **[🔐 Security](./docs/security.md)** - TLS, authentication, and security best practices
|
|
24
|
+
- **[🧪 Testing](./docs/testing.md)** - Testing workflows and activities
|
|
25
|
+
- **[🐳 Deployment](./docs/deployment.md)** - Docker, Kubernetes, and cloud deployment guides
|
|
4
26
|
|
|
5
27
|
## Overview
|
|
6
28
|
|
|
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.
|
|
29
|
+
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
30
|
|
|
9
|
-
## Features
|
|
31
|
+
## ✨ Features
|
|
10
32
|
|
|
11
33
|
- 🚀 **Easy NestJS Integration** - Simple module registration with unified configuration
|
|
34
|
+
- 🎯 **Auto-Discovery** - Automatic discovery of workflow controllers and scheduled workflows
|
|
12
35
|
- 🔄 **Complete Lifecycle Management** - Automatic worker initialization and graceful shutdown
|
|
13
|
-
-
|
|
14
|
-
-
|
|
36
|
+
- 📋 **Declarative Decorators** - NestJS-style `@WorkflowController`, `@Cron`, `@Interval`, and more
|
|
37
|
+
- 🕐 **Smart Scheduling** - Built-in cron and interval-based workflow scheduling with management
|
|
38
|
+
- 🔌 **Connection Management** - Simplified connection handling with TLS and Temporal Cloud support
|
|
15
39
|
- 🔒 **Type Safety** - Clean, strongly typed interfaces for all Temporal concepts
|
|
16
|
-
- 📡 **Client
|
|
17
|
-
- 📊 **Worker Management** -
|
|
18
|
-
-
|
|
40
|
+
- 📡 **Enhanced Client** - Methods for starting, signaling, and querying workflows with auto-discovery
|
|
41
|
+
- 📊 **Worker Management** - Advanced worker lifecycle control, monitoring, and health checks
|
|
42
|
+
- 🏭 **Production Ready** - Environment-aware configuration, health monitoring, and graceful degradation
|
|
19
43
|
|
|
20
|
-
##
|
|
44
|
+
## 🚀 Quick Start
|
|
45
|
+
|
|
46
|
+
### Installation
|
|
21
47
|
|
|
22
48
|
```bash
|
|
23
49
|
npm install nestjs-temporal-core @temporalio/client @temporalio/worker @temporalio/workflow
|
|
24
50
|
```
|
|
25
51
|
|
|
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
|
|
52
|
+
### Basic Setup
|
|
42
53
|
|
|
43
54
|
```typescript
|
|
55
|
+
// app.module.ts
|
|
44
56
|
import { Module } from '@nestjs/common';
|
|
45
57
|
import { TemporalModule } from 'nestjs-temporal-core';
|
|
46
|
-
import { EmailActivities } from './activities/email.activities';
|
|
47
58
|
|
|
48
59
|
@Module({
|
|
49
60
|
imports: [
|
|
@@ -65,586 +76,141 @@ import { EmailActivities } from './activities/email.activities';
|
|
|
65
76
|
export class AppModule {}
|
|
66
77
|
```
|
|
67
78
|
|
|
68
|
-
###
|
|
79
|
+
### Create a Workflow Controller
|
|
69
80
|
|
|
70
81
|
```typescript
|
|
71
|
-
import {
|
|
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
|
-
}
|
|
82
|
+
import { WorkflowController, WorkflowMethod, Cron, Signal, Query } from 'nestjs-temporal-core';
|
|
81
83
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
@WorkflowController({ taskQueue: 'orders' })
|
|
85
|
+
export class OrderWorkflowController {
|
|
86
|
+
private status = 'pending';
|
|
87
|
+
|
|
88
|
+
@WorkflowMethod()
|
|
89
|
+
async processOrder(orderId: string, customerId: string): Promise<string> {
|
|
90
|
+
this.status = 'processing';
|
|
91
|
+
// Workflow logic here
|
|
92
|
+
this.status = 'completed';
|
|
93
|
+
return this.status;
|
|
87
94
|
}
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
95
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
|
119
|
-
|
|
120
|
-
```typescript
|
|
121
|
-
import { Injectable } from '@nestjs/common';
|
|
122
|
-
import { TemporalService } from 'nestjs-temporal-core';
|
|
123
|
-
|
|
124
|
-
@Injectable()
|
|
125
|
-
export class EmailService {
|
|
126
|
-
constructor(private readonly temporalService: TemporalService) {}
|
|
127
|
-
|
|
128
|
-
async sendWelcomeEmail(email: string): Promise<string> {
|
|
129
|
-
// Use the simplified API to start a workflow
|
|
130
|
-
const { workflowId } = await this.temporalService.startWorkflow(
|
|
131
|
-
'sendWelcomeWorkflow',
|
|
132
|
-
[email],
|
|
133
|
-
'my-task-queue',
|
|
134
|
-
{
|
|
135
|
-
workflowId: `welcome-${email}-${Date.now()}`,
|
|
136
|
-
},
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
return workflowId;
|
|
96
|
+
@Cron('0 8 * * *', {
|
|
97
|
+
scheduleId: 'daily-order-report',
|
|
98
|
+
description: 'Generate daily order report'
|
|
99
|
+
})
|
|
100
|
+
@WorkflowMethod()
|
|
101
|
+
async generateDailyReport(): Promise<void> {
|
|
102
|
+
console.log('Generating daily order report...');
|
|
140
103
|
}
|
|
141
104
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
.getClient()
|
|
146
|
-
.startWorkflow('sendPromoWorkflow', [email, promoCode], {
|
|
147
|
-
taskQueue: 'my-task-queue',
|
|
148
|
-
workflowId: `promo-${email}-${Date.now()}`,
|
|
149
|
-
retry: {
|
|
150
|
-
maximumAttempts: 3,
|
|
151
|
-
},
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
return workflowId;
|
|
105
|
+
@Signal('addItem')
|
|
106
|
+
async addItemToOrder(item: any): Promise<void> {
|
|
107
|
+
console.log('Item added to order:', item);
|
|
155
108
|
}
|
|
156
|
-
}
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
## Advanced Features
|
|
160
109
|
|
|
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]);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
async getOrderStatus(orderId: string): Promise<string> {
|
|
177
|
-
// Query a running workflow
|
|
178
|
-
return await this.temporalService.getClient().queryWorkflow(orderId, 'getStatus');
|
|
110
|
+
@Query('getStatus')
|
|
111
|
+
getOrderStatus(): string {
|
|
112
|
+
return this.status;
|
|
179
113
|
}
|
|
180
114
|
}
|
|
181
115
|
```
|
|
182
116
|
|
|
183
|
-
###
|
|
117
|
+
### Use the Service
|
|
184
118
|
|
|
185
119
|
```typescript
|
|
186
120
|
import { Injectable } from '@nestjs/common';
|
|
187
121
|
import { TemporalService } from 'nestjs-temporal-core';
|
|
188
122
|
|
|
189
123
|
@Injectable()
|
|
190
|
-
export class
|
|
124
|
+
export class OrderService {
|
|
191
125
|
constructor(private readonly temporalService: TemporalService) {}
|
|
192
126
|
|
|
193
|
-
async
|
|
194
|
-
const
|
|
195
|
-
'
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
'reports-queue',
|
|
199
|
-
['daily-summary'],
|
|
127
|
+
async processOrder(orderId: string, customerId: string): Promise<string> {
|
|
128
|
+
const { workflowId } = await this.temporalService.startWorkflow(
|
|
129
|
+
'processOrder',
|
|
130
|
+
[orderId, customerId],
|
|
131
|
+
{ workflowId: `order-${orderId}` }
|
|
200
132
|
);
|
|
201
133
|
|
|
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
|
-
src/
|
|
343
|
-
├── temporal/
|
|
344
|
-
│ ├── activities/
|
|
345
|
-
│ │ ├── email.activities.ts
|
|
346
|
-
│ │ ├── payment.activities.ts
|
|
347
|
-
│ │ └── index.ts
|
|
348
|
-
│ ├── workflows/
|
|
349
|
-
│ │ ├── email-workflows.ts
|
|
350
|
-
│ │ ├── payment-workflows.ts
|
|
351
|
-
│ │ └── index.ts
|
|
352
|
-
│ ├── interfaces/
|
|
353
|
-
│ │ ├── email.interfaces.ts
|
|
354
|
-
│ │ └── payment.interfaces.ts
|
|
355
|
-
│ └── temporal.module.ts
|
|
356
|
-
├── modules/
|
|
357
|
-
│ ├── email/
|
|
358
|
-
│ │ ├── email.service.ts
|
|
359
|
-
│ │ ├── email.controller.ts
|
|
360
|
-
│ │ └── email.module.ts
|
|
361
|
-
│ └── payment/
|
|
362
|
-
│ ├── payment.service.ts
|
|
363
|
-
│ ├── payment.controller.ts
|
|
364
|
-
│ └── payment.module.ts
|
|
365
|
-
└── app.module.ts
|
|
366
|
-
|
|
367
|
-
````
|
|
368
|
-
|
|
369
|
-
### Key Files and Their Purpose
|
|
370
|
-
|
|
371
|
-
1. **Activities (src/temporal/activities/)**:
|
|
372
|
-
- Contains activity classes decorated with `@Activity()`
|
|
373
|
-
- Each activity class should group related functionality
|
|
374
|
-
|
|
375
|
-
2. **Workflows (src/temporal/workflows/)**:
|
|
376
|
-
- Contains workflow definitions that orchestrate activities
|
|
377
|
-
- Workflows should be in separate files based on domain
|
|
378
|
-
|
|
379
|
-
3. **Interfaces (src/temporal/interfaces/)**:
|
|
380
|
-
- TypeScript interfaces that define activity and workflow parameters/returns
|
|
381
|
-
- Helps maintain type safety between activities and workflows
|
|
382
|
-
|
|
383
|
-
4. **Temporal Module (src/temporal/temporal.module.ts)**:
|
|
384
|
-
- Centralizes Temporal configuration
|
|
385
|
-
- Imports and registers all activities
|
|
386
|
-
|
|
387
|
-
5. **Business Services (src/modules/*/)**:
|
|
388
|
-
- Inject the TemporalService
|
|
389
|
-
- Use it to start workflows and interact with Temporal
|
|
390
|
-
|
|
391
|
-
## Integration Examples
|
|
392
|
-
|
|
393
|
-
### Activity Definition
|
|
394
|
-
|
|
395
|
-
```typescript
|
|
396
|
-
// src/temporal/activities/email.activities.ts
|
|
397
|
-
import { Activity, ActivityMethod } from 'nestjs-temporal-core';
|
|
398
|
-
import { Injectable } from '@nestjs/common';
|
|
399
|
-
import { EmailService } from '../../modules/email/email.service';
|
|
400
|
-
|
|
401
|
-
@Injectable()
|
|
402
|
-
@Activity()
|
|
403
|
-
export class EmailActivities {
|
|
404
|
-
constructor(private readonly emailService: EmailService) {}
|
|
405
|
-
|
|
406
|
-
@ActivityMethod()
|
|
407
|
-
async sendWelcomeEmail(to: string, name: string): Promise<boolean> {
|
|
408
|
-
await this.emailService.sendEmail({
|
|
409
|
-
to,
|
|
410
|
-
subject: 'Welcome!',
|
|
411
|
-
body: `Hello ${name}, welcome to our platform!`,
|
|
412
|
-
});
|
|
413
|
-
return true;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
@ActivityMethod()
|
|
417
|
-
async sendPasswordReset(to: string, resetToken: string): Promise<boolean> {
|
|
418
|
-
await this.emailService.sendEmail({
|
|
419
|
-
to,
|
|
420
|
-
subject: 'Password Reset',
|
|
421
|
-
body: `Please use this token to reset your password: ${resetToken}`,
|
|
422
|
-
});
|
|
423
|
-
return true;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
````
|
|
427
|
-
|
|
428
|
-
```typescript
|
|
429
|
-
// src/temporal/activities/index.ts
|
|
430
|
-
export * from './email.activities';
|
|
431
|
-
export * from './payment.activities';
|
|
432
|
-
// Export all other activity classes
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
### Workflow Definition
|
|
436
|
-
|
|
437
|
-
```typescript
|
|
438
|
-
// src/temporal/workflows/email-workflows.ts
|
|
439
|
-
import { proxyActivities } from '@temporalio/workflow';
|
|
440
|
-
|
|
441
|
-
// Define the interface of activities this workflow will use
|
|
442
|
-
export interface EmailActivities {
|
|
443
|
-
sendWelcomeEmail(to: string, name: string): Promise<boolean>;
|
|
444
|
-
sendPasswordReset(to: string, resetToken: string): Promise<boolean>;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// Create a proxy to the activities
|
|
448
|
-
const activities = proxyActivities<EmailActivities>({
|
|
449
|
-
startToCloseTimeout: '30 seconds',
|
|
450
|
-
});
|
|
451
|
-
|
|
452
|
-
// Welcome workflow with retry logic
|
|
453
|
-
export async function welcomeUserWorkflow(email: string, name: string): Promise<boolean> {
|
|
454
|
-
let attempts = 0;
|
|
455
|
-
const maxAttempts = 3;
|
|
456
|
-
|
|
457
|
-
while (attempts < maxAttempts) {
|
|
458
|
-
try {
|
|
459
|
-
return await activities.sendWelcomeEmail(email, name);
|
|
460
|
-
} catch (error) {
|
|
461
|
-
attempts++;
|
|
462
|
-
if (attempts >= maxAttempts) {
|
|
463
|
-
throw error;
|
|
464
|
-
}
|
|
465
|
-
// Wait before retrying
|
|
466
|
-
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
467
|
-
}
|
|
134
|
+
return workflowId;
|
|
468
135
|
}
|
|
469
|
-
|
|
470
|
-
return false;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
// Password reset workflow
|
|
474
|
-
export async function passwordResetWorkflow(email: string, resetToken: string): Promise<boolean> {
|
|
475
|
-
return await activities.sendPasswordReset(email, resetToken);
|
|
476
136
|
}
|
|
477
137
|
```
|
|
478
138
|
|
|
479
|
-
|
|
139
|
+
## 📖 Core Concepts
|
|
480
140
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
import { proxyActivities } from '@temporalio/workflow';
|
|
141
|
+
### Workflow Controllers
|
|
142
|
+
New NestJS-style controllers for defining workflows with auto-discovery and declarative scheduling.
|
|
484
143
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
emailReportToAdmins(reportUrl: string): Promise<boolean>;
|
|
488
|
-
}
|
|
144
|
+
### Activities
|
|
145
|
+
Reusable business logic components that can be called from workflows.
|
|
489
146
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
});
|
|
147
|
+
### Scheduling
|
|
148
|
+
Built-in support for cron and interval-based workflow scheduling using decorators.
|
|
493
149
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
const reportUrl = await activities.generateDailyReport();
|
|
497
|
-
await activities.emailReportToAdmins(reportUrl);
|
|
498
|
-
}
|
|
499
|
-
```
|
|
150
|
+
### Auto-Discovery
|
|
151
|
+
Automatic detection and registration of workflow controllers and scheduled workflows.
|
|
500
152
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
```typescript
|
|
504
|
-
// src/temporal/temporal.module.ts
|
|
505
|
-
import { Module } from '@nestjs/common';
|
|
506
|
-
import { TemporalModule } from 'nestjs-temporal-core';
|
|
507
|
-
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
508
|
-
import * as path from 'path';
|
|
509
|
-
import { EmailActivities, PaymentActivities } from './activities';
|
|
510
|
-
import { EmailModule } from '../modules/email/email.module';
|
|
511
|
-
import { PaymentModule } from '../modules/payment/payment.module';
|
|
153
|
+
## 🏗️ Architecture
|
|
512
154
|
|
|
513
|
-
@Module({
|
|
514
|
-
imports: [
|
|
515
|
-
EmailModule,
|
|
516
|
-
PaymentModule,
|
|
517
|
-
TemporalModule.registerAsync({
|
|
518
|
-
imports: [ConfigModule],
|
|
519
|
-
inject: [ConfigService],
|
|
520
|
-
useFactory: (configService: ConfigService) => ({
|
|
521
|
-
connection: {
|
|
522
|
-
address: configService.get('TEMPORAL_ADDRESS', 'localhost:7233'),
|
|
523
|
-
namespace: configService.get('TEMPORAL_NAMESPACE', 'default'),
|
|
524
|
-
},
|
|
525
|
-
taskQueue: configService.get('TEMPORAL_TASK_QUEUE', 'my-app-queue'),
|
|
526
|
-
worker: {
|
|
527
|
-
workflowsPath: path.resolve(__dirname, 'workflows'),
|
|
528
|
-
activityClasses: [EmailActivities, PaymentActivities],
|
|
529
|
-
autoStart: true,
|
|
530
|
-
},
|
|
531
|
-
isGlobal: true,
|
|
532
|
-
}),
|
|
533
|
-
}),
|
|
534
|
-
],
|
|
535
|
-
providers: [EmailActivities, PaymentActivities],
|
|
536
|
-
exports: [TemporalModule],
|
|
537
|
-
})
|
|
538
|
-
export class TemporalAppModule {}
|
|
539
155
|
```
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
@Injectable()
|
|
549
|
-
export class EmailService {
|
|
550
|
-
constructor(private readonly temporalService: TemporalService) {}
|
|
551
|
-
|
|
552
|
-
// Your actual email sending functionality
|
|
553
|
-
async sendEmail(options: { to: string; subject: string; body: string }): Promise<void> {
|
|
554
|
-
// Implementation...
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
// Triggering a Temporal workflow
|
|
558
|
-
async sendWelcomeEmail(email: string, name: string): Promise<string> {
|
|
559
|
-
const { workflowId } = await this.temporalService.startWorkflow(
|
|
560
|
-
'welcomeUserWorkflow',
|
|
561
|
-
[email, name],
|
|
562
|
-
'my-app-queue',
|
|
563
|
-
{ workflowId: `welcome-${email}-${Date.now()}` },
|
|
564
|
-
);
|
|
565
|
-
|
|
566
|
-
return workflowId;
|
|
567
|
-
}
|
|
568
|
-
}
|
|
156
|
+
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
|
|
157
|
+
│ NestJS App │ │ Temporal Server │ │ Worker Process │
|
|
158
|
+
│ │ │ │ │ │
|
|
159
|
+
│ ┌─────────────┐ │ │ ┌──────────────┐ │ │ ┌─────────────┐ │
|
|
160
|
+
│ │ Controllers │ │───▶│ │ Workflows │ │───▶│ │ Activities │ │
|
|
161
|
+
│ │ Services │ │ │ │ Schedules │ │ │ │ Workers │ │
|
|
162
|
+
│ └─────────────┘ │ │ └──────────────┘ │ │ └─────────────┘ │
|
|
163
|
+
└─────────────────┘ └──────────────────┘ └─────────────────┘
|
|
569
164
|
```
|
|
570
165
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
```typescript
|
|
574
|
-
// src/modules/reports/report.service.ts
|
|
575
|
-
import { Injectable, OnModuleInit } from '@nestjs/common';
|
|
576
|
-
import { TemporalService } from 'nestjs-temporal-core';
|
|
577
|
-
|
|
578
|
-
@Injectable()
|
|
579
|
-
export class ReportService implements OnModuleInit {
|
|
580
|
-
constructor(private readonly temporalService: TemporalService) {}
|
|
166
|
+
## 🎯 Use Cases
|
|
581
167
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
// Check if the schedule already exists
|
|
590
|
-
const schedules = await this.temporalService.getScheduleService().listSchedules();
|
|
591
|
-
|
|
592
|
-
if (!schedules.some((s) => s.scheduleId === 'daily-report')) {
|
|
593
|
-
// Create a new schedule
|
|
594
|
-
await this.temporalService.getScheduleService().createCronWorkflow(
|
|
595
|
-
'daily-report',
|
|
596
|
-
'dailyReportWorkflow',
|
|
597
|
-
'0 8 * * *', // Run every day at 8 AM
|
|
598
|
-
'my-app-queue',
|
|
599
|
-
[], // No arguments needed for this workflow
|
|
600
|
-
'Daily business report generation',
|
|
601
|
-
);
|
|
602
|
-
|
|
603
|
-
console.log('Daily report schedule created');
|
|
604
|
-
}
|
|
605
|
-
} catch (error) {
|
|
606
|
-
console.error('Failed to set up daily report schedule:', error);
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
```
|
|
168
|
+
- **Order Processing** - Reliable order fulfillment with compensation
|
|
169
|
+
- **Payment Processing** - Multi-step payment flows with retries
|
|
170
|
+
- **Data Pipelines** - Long-running data processing workflows
|
|
171
|
+
- **Scheduled Jobs** - Cron-based and interval-based background tasks
|
|
172
|
+
- **Saga Patterns** - Distributed transaction management
|
|
173
|
+
- **Human Tasks** - Workflows requiring human intervention
|
|
174
|
+
- **Microservice Orchestration** - Coordinating multiple services
|
|
611
175
|
|
|
612
|
-
##
|
|
176
|
+
## 🌟 What's New in v3.0
|
|
613
177
|
|
|
614
|
-
|
|
178
|
+
- **🎮 Workflow Controllers** - NestJS-style workflow definition
|
|
179
|
+
- **📅 Declarative Scheduling** - `@Cron` and `@Interval` decorators
|
|
180
|
+
- **🔍 Auto-Discovery** - Automatic workflow and schedule detection
|
|
181
|
+
- **📊 Enhanced Monitoring** - Built-in health checks and metrics
|
|
182
|
+
- **🏭 Production Features** - Worker presets, graceful shutdown, error handling
|
|
183
|
+
- **🔧 Better Developer Experience** - Improved APIs and TypeScript support
|
|
615
184
|
|
|
616
|
-
|
|
617
|
-
- Set appropriate timeouts for expected durations
|
|
618
|
-
- Use dependency injection within activity classes
|
|
185
|
+
## 📦 Packages
|
|
619
186
|
|
|
620
|
-
|
|
187
|
+
| Package | Version | Description |
|
|
188
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------ |
|
|
189
|
+
| `nestjs-temporal-core` | [](https://www.npmjs.com/package/nestjs-temporal-core) | Main integration package |
|
|
190
|
+
| `@temporalio/client` | [](https://www.npmjs.com/package/@temporalio/client) | Temporal client library |
|
|
191
|
+
| `@temporalio/worker` | [](https://www.npmjs.com/package/@temporalio/worker) | Temporal worker library |
|
|
192
|
+
| `@temporalio/workflow` | [](https://www.npmjs.com/package/@temporalio/workflow) | Workflow runtime library |
|
|
621
193
|
|
|
622
|
-
|
|
623
|
-
- Use signals for external events
|
|
624
|
-
- Use queries for retrieving workflow state
|
|
625
|
-
- Separate workflows by domain/function
|
|
194
|
+
## 🤝 Community
|
|
626
195
|
|
|
627
|
-
|
|
196
|
+
- **GitHub Discussions** - Ask questions and share ideas
|
|
197
|
+
- **Issues** - Report bugs and request features
|
|
198
|
+
- **Pull Requests** - Contribute to the project
|
|
628
199
|
|
|
629
|
-
|
|
630
|
-
- Configure appropriate timeouts for activities and workflows
|
|
631
|
-
- Implement proper error handling
|
|
200
|
+
## 📄 License
|
|
632
201
|
|
|
633
|
-
|
|
202
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
634
203
|
|
|
635
|
-
|
|
636
|
-
- Configure proper worker shutdown grace periods
|
|
637
|
-
- Consider using OnModuleInit to set up schedules
|
|
204
|
+
## 👨💻 Author
|
|
638
205
|
|
|
639
|
-
|
|
640
|
-
- Implement proper TLS security for production environments
|
|
641
|
-
- Use namespaces to isolate different environments
|
|
642
|
-
- Use API keys for Temporal Cloud authentication
|
|
206
|
+
**Harsh M** - [GitHub](https://github.com/harsh-simform)
|
|
643
207
|
|
|
644
|
-
##
|
|
208
|
+
## 🙏 Acknowledgments
|
|
645
209
|
|
|
646
|
-
|
|
210
|
+
- [Temporal.io](https://temporal.io/) - For the amazing workflow engine
|
|
211
|
+
- [NestJS](https://nestjs.com/) - For the incredible framework
|
|
212
|
+
- [TypeScript](https://www.typescriptlang.org/) - For making JavaScript enjoyable
|
|
647
213
|
|
|
648
|
-
|
|
214
|
+
---
|
|
649
215
|
|
|
650
|
-
|
|
216
|
+
**[📚 Continue to Getting Started →](./docs/getting-started.md)**
|