nestjs-temporal-core 3.0.8 → 3.0.10
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 -39
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,6 +14,20 @@ NestJS Temporal Core brings Temporal's durable execution to NestJS with familiar
|
|
|
14
14
|
|
|
15
15
|
🔗 **[Complete Example Project](https://github.com/harsh-simform/nestjs-temporal-core-example)** - Check out our full working example repository to see NestJS Temporal Core in action with real-world use cases, configuration examples, and best practices.
|
|
16
16
|
|
|
17
|
+
## 🏁 Getting Started: Recommendations
|
|
18
|
+
|
|
19
|
+
Welcome to NestJS Temporal Core! Here are some quick recommendations to help you get started smoothly:
|
|
20
|
+
|
|
21
|
+
- **Choose Your Workflow Style:** You can implement workflows as plain exported functions (recommended for most use cases) or as injectable classes with decorators for advanced scenarios. See the comparison below.
|
|
22
|
+
- **Parameter Injection:** Use `@WorkflowParam`, `@WorkflowId`, etc., only if you need advanced injection or metadata. For most workflows, plain parameters are simpler and preferred.
|
|
23
|
+
- **Scheduling:** Schedules trigger workflows, not service methods. Make sure your scheduled workflow is exported and available to the worker.
|
|
24
|
+
- **Signals & Queries:** Use signals to update workflow state and queries to fetch workflow status. See the expanded examples below for best practices.
|
|
25
|
+
- **Keep Activities Idempotent:** Activities should be safe to retry and handle errors gracefully.
|
|
26
|
+
- **Separate Concerns:** Keep workflows, activities, and schedules in separate files for clarity and maintainability.
|
|
27
|
+
- **Check the Example Repo:** For real-world patterns, see [nestjs-temporal-core-example](https://github.com/harsh-simform/nestjs-temporal-core-example).
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
17
31
|
## 🚀 Key Features
|
|
18
32
|
|
|
19
33
|
- **🎯 NestJS-Native** - Familiar patterns: `@Activity`, `@Cron`, `@Interval`, `@Scheduled`
|
|
@@ -141,90 +155,101 @@ export async function processEmailWorkflow(
|
|
|
141
155
|
|
|
142
156
|
### 4. Schedule Workflows
|
|
143
157
|
|
|
158
|
+
> **Note:** Schedules in NestJS Temporal Core trigger workflows, not service methods. The decorated method is used to define the schedule metadata, but the actual execution runs the workflow you specify.
|
|
159
|
+
|
|
144
160
|
```typescript
|
|
145
161
|
// services/scheduled.service.ts
|
|
146
162
|
import { Injectable } from '@nestjs/common';
|
|
147
163
|
import {
|
|
148
164
|
Scheduled,
|
|
149
|
-
Cron,
|
|
150
|
-
Interval,
|
|
151
165
|
CRON_EXPRESSIONS,
|
|
152
|
-
INTERVAL_EXPRESSIONS
|
|
153
166
|
} from 'nestjs-temporal-core';
|
|
154
167
|
|
|
155
168
|
@Injectable()
|
|
156
169
|
export class ScheduledService {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
170
|
+
@Scheduled({
|
|
171
|
+
scheduleId: 'daily-report',
|
|
172
|
+
cron: CRON_EXPRESSIONS.DAILY_8AM,
|
|
173
|
+
description: 'Generate daily sales report',
|
|
174
|
+
taskQueue: 'reports',
|
|
175
|
+
workflowType: 'generateReportWorkflow', // Name of the workflow function to run
|
|
176
|
+
workflowArgs: [{ reportType: 'sales' }], // Arguments passed to the workflow
|
|
177
|
+
})
|
|
164
178
|
async generateDailyReport(): Promise<void> {
|
|
165
|
-
|
|
166
|
-
// Your report generation logic
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
@Cron(CRON_EXPRESSIONS.WEEKLY_MONDAY_9AM, {
|
|
170
|
-
scheduleId: 'weekly-cleanup',
|
|
171
|
-
description: 'Weekly system cleanup'
|
|
172
|
-
})
|
|
173
|
-
async performWeeklyCleanup(): Promise<void> {
|
|
174
|
-
console.log('Performing weekly cleanup...');
|
|
175
|
-
// Your cleanup logic
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
@Interval(INTERVAL_EXPRESSIONS.EVERY_5_MINUTES, {
|
|
179
|
-
scheduleId: 'health-check',
|
|
180
|
-
description: 'System health monitoring'
|
|
181
|
-
})
|
|
182
|
-
async performHealthCheck(): Promise<void> {
|
|
183
|
-
console.log('Performing health check...');
|
|
184
|
-
// Your health check logic
|
|
179
|
+
// This method is NOT executed directly. Instead, the schedule triggers the workflow specified above.
|
|
185
180
|
}
|
|
186
181
|
}
|
|
187
182
|
```
|
|
188
183
|
|
|
184
|
+
- The `@Scheduled` decorator registers a schedule with Temporal.
|
|
185
|
+
- The `workflowType` property specifies the workflow function to run (must be exported and available to the worker).
|
|
186
|
+
- The `workflowArgs` property allows you to pass arguments to the workflow when the schedule triggers.
|
|
187
|
+
|
|
188
|
+
> **Best Practice:** Keep your scheduled workflow logic in a dedicated workflow file, and use the schedule only to trigger it with the desired arguments.
|
|
189
|
+
|
|
189
190
|
### 5. Parameter Injection in Workflows
|
|
190
191
|
|
|
192
|
+
You can use parameter decorators to inject workflow metadata and context. This is most useful for advanced scenarios, such as handling signals and queries in a class-based workflow.
|
|
193
|
+
|
|
194
|
+
#### Comprehensive Example: Handling Signals and Workflow State
|
|
195
|
+
|
|
191
196
|
```typescript
|
|
192
197
|
// workflows/order.workflow.ts
|
|
193
198
|
import { Injectable } from '@nestjs/common';
|
|
194
|
-
import {
|
|
195
|
-
WorkflowParam,
|
|
196
|
-
WorkflowContext,
|
|
197
|
-
WorkflowId,
|
|
199
|
+
import {
|
|
200
|
+
WorkflowParam,
|
|
201
|
+
WorkflowContext,
|
|
202
|
+
WorkflowId,
|
|
198
203
|
RunId,
|
|
199
|
-
TaskQueue
|
|
204
|
+
TaskQueue,
|
|
205
|
+
Signal,
|
|
206
|
+
Query
|
|
200
207
|
} from 'nestjs-temporal-core';
|
|
201
208
|
|
|
202
209
|
@Injectable()
|
|
203
210
|
export class OrderWorkflowController {
|
|
204
|
-
|
|
211
|
+
private updateData: any = null; // Store signal data in workflow state
|
|
212
|
+
private status: string = 'processing';
|
|
213
|
+
|
|
205
214
|
async processOrder(
|
|
206
215
|
@WorkflowParam(0) orderId: string,
|
|
207
216
|
@WorkflowParam(1) customerData: any,
|
|
208
217
|
@WorkflowId() workflowId: string,
|
|
209
218
|
@WorkflowContext() context: any
|
|
210
219
|
): Promise<void> {
|
|
211
|
-
|
|
212
|
-
//
|
|
220
|
+
// Main workflow logic
|
|
221
|
+
// Wait for an update signal (example: polling or event-driven)
|
|
222
|
+
while (!this.updateData) {
|
|
223
|
+
// ...wait or yield...
|
|
224
|
+
// In real Temporal workflows, use condition() or similar for waiting
|
|
225
|
+
}
|
|
226
|
+
// Use updateData in your logic
|
|
227
|
+
// ...
|
|
228
|
+
this.status = 'completed';
|
|
213
229
|
}
|
|
214
230
|
|
|
215
231
|
@Signal('updateOrder')
|
|
216
232
|
async updateOrder(@WorkflowParam() updateData: any): Promise<void> {
|
|
217
233
|
// Handle order update signal
|
|
234
|
+
this.updateData = updateData; // Store for use in processOrder
|
|
235
|
+
this.status = 'updated';
|
|
218
236
|
}
|
|
219
237
|
|
|
220
238
|
@Query('getOrderStatus')
|
|
221
239
|
getOrderStatus(@RunId() runId: string): string {
|
|
222
240
|
// Return current order status
|
|
223
|
-
return
|
|
241
|
+
return this.status;
|
|
224
242
|
}
|
|
225
243
|
}
|
|
226
244
|
```
|
|
227
245
|
|
|
246
|
+
- **Signal Handling:** Use a class property to persist signal data (`updateData`) so it can be accessed by the main workflow logic.
|
|
247
|
+
- **Best Practice:** Always store signal data in workflow state (class property or closure variable) to ensure it is available after workflow replay.
|
|
248
|
+
- **Forwarding Data:** The main workflow function (`processOrder`) can access and use the updated data as needed.
|
|
249
|
+
- **Status Tracking:** Use a property like `status` to track and query workflow progress.
|
|
250
|
+
|
|
251
|
+
> **Tip:** In Temporal workflows, use `condition()` or similar mechanisms to wait for signals in a non-blocking, replay-safe way.
|
|
252
|
+
|
|
228
253
|
### 6. Use in Services
|
|
229
254
|
|
|
230
255
|
```typescript
|
|
@@ -898,3 +923,53 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
|
898
923
|
---
|
|
899
924
|
|
|
900
925
|
Built with ❤️ for the NestJS and Temporal communities
|
|
926
|
+
|
|
927
|
+
## Workflow Implementation Approaches
|
|
928
|
+
|
|
929
|
+
NestJS Temporal Core supports two main ways to define workflows:
|
|
930
|
+
|
|
931
|
+
### 1. Function-Based Workflows (Recommended for Most Use Cases)
|
|
932
|
+
- **How:** Export a plain async function from your workflow file.
|
|
933
|
+
- **Benefits:**
|
|
934
|
+
- Simpler, more idiomatic Temporal style
|
|
935
|
+
- Fully compatible with Temporal's TypeScript SDK
|
|
936
|
+
- Easier to test and bundle
|
|
937
|
+
- **When to Use:**
|
|
938
|
+
- Most workflows, especially if you don't need dependency injection or advanced metadata
|
|
939
|
+
|
|
940
|
+
```typescript
|
|
941
|
+
// workflows/email.workflow.ts
|
|
942
|
+
export async function processEmailWorkflow(userId: string, emailData: { to: string; subject: string; body: string }) {
|
|
943
|
+
// ...
|
|
944
|
+
}
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
### 2. Class-Based Workflows with Decorators (Advanced)
|
|
948
|
+
- **How:** Use an injectable class and parameter decorators like `@WorkflowParam`, `@WorkflowId`, etc.
|
|
949
|
+
- **Benefits:**
|
|
950
|
+
- Enables parameter injection (workflowId, context, etc.)
|
|
951
|
+
- Useful for advanced scenarios (e.g., dynamic metadata, dependency injection)
|
|
952
|
+
- Can organize signals/queries as class methods
|
|
953
|
+
- **When to Use:**
|
|
954
|
+
- When you need to access workflow context, IDs, or inject dependencies
|
|
955
|
+
- When you want to group signals/queries with workflow logic
|
|
956
|
+
|
|
957
|
+
```typescript
|
|
958
|
+
@Injectable()
|
|
959
|
+
export class OrderWorkflowController {
|
|
960
|
+
async processOrder(
|
|
961
|
+
@WorkflowParam(0) orderId: string,
|
|
962
|
+
@WorkflowId() workflowId: string,
|
|
963
|
+
@WorkflowContext() context: any
|
|
964
|
+
) {
|
|
965
|
+
// ...
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
```
|
|
969
|
+
|
|
970
|
+
#### Which Should I Use?
|
|
971
|
+
- **Start with function-based workflows** for simplicity and compatibility.
|
|
972
|
+
- **Use class-based workflows** only if you need advanced features like parameter injection or grouping signals/queries.
|
|
973
|
+
- `@WorkflowParam` and related decorators are only needed for class-based workflows and provide access to workflow metadata or injected parameters.
|
|
974
|
+
|
|
975
|
+
---
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nestjs-temporal-core",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.10",
|
|
4
4
|
"description": "Complete NestJS integration for Temporal.io with auto-discovery, declarative scheduling, enhanced monitoring, and enterprise-ready features",
|
|
5
5
|
"author": "Harsh M",
|
|
6
6
|
"license": "MIT",
|