@mbc-cqrs-serverless/task 1.0.16 → 1.0.18
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 +281 -129
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|

|
|
2
2
|
|
|
3
|
-
#
|
|
3
|
+
# @mbc-cqrs-serverless/task
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@mbc-cqrs-serverless/task)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
Asynchronous task processing for the MBC CQRS Serverless framework. Execute long-running operations, batch processes, and background jobs with status tracking and SNS notifications.
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Async Task Execution**: Process long-running operations in background
|
|
13
|
+
- **Step Functions Integration**: Orchestrate complex workflows with AWS Step Functions
|
|
14
|
+
- **Sub-task Support**: Break large tasks into smaller parallel sub-tasks
|
|
15
|
+
- **Status Tracking**: Real-time task status updates via SNS notifications
|
|
16
|
+
- **Multi-tenant**: Isolated task queues per tenant
|
|
17
|
+
- **Error Handling**: Built-in alarm notifications for failed tasks
|
|
15
18
|
|
|
16
19
|
## Installation
|
|
17
20
|
|
|
@@ -19,192 +22,341 @@ The Task package provides comprehensive task management functionality in the MBC
|
|
|
19
22
|
npm install @mbc-cqrs-serverless/task
|
|
20
23
|
```
|
|
21
24
|
|
|
22
|
-
##
|
|
25
|
+
## Quick Start
|
|
23
26
|
|
|
24
|
-
###
|
|
27
|
+
### 1. Register the Module
|
|
25
28
|
|
|
26
|
-
1. Import and configure the task module:
|
|
27
29
|
```typescript
|
|
28
|
-
import { TaskModule } from '@mbc-cqrs-serverless/task';
|
|
29
30
|
import { Module } from '@nestjs/common';
|
|
31
|
+
import { TaskModule, ITaskQueueEventFactory, TaskQueueEvent, StepFunctionTaskEvent } from '@mbc-cqrs-serverless/task';
|
|
32
|
+
import { IEvent } from '@mbc-cqrs-serverless/core';
|
|
33
|
+
|
|
34
|
+
// Implement factory to transform task events into your custom events
|
|
35
|
+
class MyTaskQueueEventFactory implements ITaskQueueEventFactory {
|
|
36
|
+
async transformTask(event: TaskQueueEvent): Promise<IEvent[]> {
|
|
37
|
+
// Transform task queue event into your custom events
|
|
38
|
+
return [event];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async transformStepFunctionTask(event: StepFunctionTaskEvent): Promise<IEvent[]> {
|
|
42
|
+
// Transform step function task event into your custom events
|
|
43
|
+
return [event];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
30
46
|
|
|
31
47
|
@Module({
|
|
32
48
|
imports: [
|
|
33
|
-
TaskModule.
|
|
34
|
-
|
|
35
|
-
|
|
49
|
+
TaskModule.register({
|
|
50
|
+
taskQueueEventFactory: MyTaskQueueEventFactory,
|
|
51
|
+
enableController: true, // Optional: enable REST endpoints
|
|
36
52
|
}),
|
|
37
53
|
],
|
|
38
54
|
})
|
|
39
55
|
export class AppModule {}
|
|
40
56
|
```
|
|
41
57
|
|
|
42
|
-
###
|
|
58
|
+
### 2. Create and Monitor Tasks
|
|
43
59
|
|
|
44
|
-
1. Define a task:
|
|
45
60
|
```typescript
|
|
46
|
-
import {
|
|
61
|
+
import { Injectable } from '@nestjs/common';
|
|
62
|
+
import { TaskService, TaskStatusEnum } from '@mbc-cqrs-serverless/task';
|
|
63
|
+
import { getUserContext, IInvoke } from '@mbc-cqrs-serverless/core';
|
|
47
64
|
|
|
48
|
-
@
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
65
|
+
@Injectable()
|
|
66
|
+
export class BatchService {
|
|
67
|
+
constructor(private readonly taskService: TaskService) {}
|
|
68
|
+
|
|
69
|
+
async startBatchProcess(data: any[], opts: { invokeContext: IInvoke }) {
|
|
70
|
+
const { tenantCode } = getUserContext(opts.invokeContext);
|
|
71
|
+
|
|
72
|
+
// Create a new task
|
|
73
|
+
const task = await this.taskService.createTask(
|
|
74
|
+
{
|
|
75
|
+
tenantCode,
|
|
76
|
+
taskType: 'BATCH_IMPORT',
|
|
77
|
+
name: 'Import Customer Data',
|
|
78
|
+
input: data,
|
|
79
|
+
},
|
|
80
|
+
opts,
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
console.log(task.id); // Task identifier
|
|
84
|
+
console.log(task.status); // "CREATED"
|
|
85
|
+
console.log(task.code); // ULID code
|
|
86
|
+
|
|
87
|
+
return task;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async checkStatus(pk: string, sk: string) {
|
|
91
|
+
const task = await this.taskService.getTask({ pk, sk });
|
|
92
|
+
return task.status;
|
|
59
93
|
}
|
|
60
94
|
}
|
|
61
95
|
```
|
|
62
96
|
|
|
63
|
-
|
|
97
|
+
## API Reference
|
|
98
|
+
|
|
99
|
+
### TaskService
|
|
100
|
+
|
|
101
|
+
| Method | Description |
|
|
102
|
+
|--------|-------------|
|
|
103
|
+
| `createTask(dto, options)` | Create a new async task |
|
|
104
|
+
| `createStepFunctionTask(dto, options)` | Create a task for Step Functions workflow |
|
|
105
|
+
| `createSubTask(event)` | Create sub-tasks from parent task input |
|
|
106
|
+
| `getTask(key)` | Get task by pk/sk |
|
|
107
|
+
| `updateStatus(key, status, attributes?, notifyId?)` | Update task status with SNS notification |
|
|
108
|
+
| `updateSubTaskStatus(key, status, attributes?, notifyId?)` | Update sub-task status |
|
|
109
|
+
| `listItemsByPk(tenantCode, type?, options?)` | List tasks by tenant |
|
|
110
|
+
| `getAllSubTask(subTaskKey)` | Get all sub-tasks of a parent task |
|
|
111
|
+
| `publishAlarm(event, errorDetails)` | Send alarm notification for failed tasks |
|
|
112
|
+
|
|
113
|
+
### CreateTaskDto
|
|
114
|
+
|
|
115
|
+
| Property | Type | Required | Description |
|
|
116
|
+
|----------|------|----------|-------------|
|
|
117
|
+
| `tenantCode` | string | Yes | Tenant identifier |
|
|
118
|
+
| `taskType` | string | Yes | Task type identifier |
|
|
119
|
+
| `name` | string | No | Human-readable task name |
|
|
120
|
+
| `input` | object | Yes | Task input data |
|
|
121
|
+
|
|
122
|
+
### TaskStatusEnum
|
|
123
|
+
|
|
124
|
+
| Status | Description |
|
|
125
|
+
|--------|-------------|
|
|
126
|
+
| `CREATED` | Task created, not yet queued |
|
|
127
|
+
| `QUEUED` | Task queued for processing |
|
|
128
|
+
| `STARTED` | Task execution started |
|
|
129
|
+
| `PROCESSING` | Task is being processed |
|
|
130
|
+
| `FINISHED` | Task execution finished |
|
|
131
|
+
| `COMPLETED` | Task completed successfully |
|
|
132
|
+
| `ERRORED` | Task encountered an error |
|
|
133
|
+
| `FAILED` | Task failed permanently |
|
|
134
|
+
|
|
135
|
+
### TaskEntity
|
|
136
|
+
|
|
64
137
|
```typescript
|
|
65
|
-
|
|
138
|
+
{
|
|
139
|
+
id: string; // Full identifier (pk#sk)
|
|
140
|
+
pk: string; // Partition key (TASK#tenantCode)
|
|
141
|
+
sk: string; // Sort key (taskType#taskCode)
|
|
142
|
+
code: string; // ULID task code
|
|
143
|
+
type: string; // Task type
|
|
144
|
+
name: string; // Task name
|
|
145
|
+
tenantCode: string; // Tenant identifier
|
|
146
|
+
status: string; // Current status
|
|
147
|
+
input: any; // Task input data
|
|
148
|
+
attributes?: any; // Result/error data
|
|
149
|
+
createdAt: Date;
|
|
150
|
+
updatedAt: Date;
|
|
151
|
+
createdBy: string;
|
|
152
|
+
updatedBy: string;
|
|
153
|
+
}
|
|
154
|
+
```
|
|
66
155
|
|
|
156
|
+
## Usage Examples
|
|
157
|
+
|
|
158
|
+
### Standard Task Processing
|
|
159
|
+
|
|
160
|
+
Create and process tasks with SQS queue:
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
67
163
|
@Injectable()
|
|
68
|
-
export class
|
|
69
|
-
constructor(
|
|
70
|
-
|
|
71
|
-
) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
164
|
+
export class ReportService {
|
|
165
|
+
constructor(private readonly taskService: TaskService) {}
|
|
166
|
+
|
|
167
|
+
async generateReport(reportType: string, opts: { invokeContext: IInvoke }) {
|
|
168
|
+
const { tenantCode } = getUserContext(opts.invokeContext);
|
|
169
|
+
|
|
170
|
+
// Create task - triggers SNS/SQS workflow
|
|
171
|
+
const task = await this.taskService.createTask(
|
|
172
|
+
{
|
|
173
|
+
tenantCode,
|
|
174
|
+
taskType: 'REPORT_GENERATION',
|
|
175
|
+
name: `Generate ${reportType} Report`,
|
|
176
|
+
input: { reportType, filters: {} },
|
|
177
|
+
},
|
|
178
|
+
opts,
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
return { taskId: task.id, status: task.status };
|
|
79
182
|
}
|
|
80
183
|
}
|
|
81
184
|
```
|
|
82
185
|
|
|
83
|
-
###
|
|
186
|
+
### Step Functions Task
|
|
187
|
+
|
|
188
|
+
Create tasks that integrate with AWS Step Functions:
|
|
84
189
|
|
|
85
|
-
1. Monitor task status:
|
|
86
190
|
```typescript
|
|
87
191
|
@Injectable()
|
|
88
|
-
export class
|
|
89
|
-
constructor(
|
|
90
|
-
|
|
91
|
-
) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
192
|
+
export class WorkflowService {
|
|
193
|
+
constructor(private readonly taskService: TaskService) {}
|
|
194
|
+
|
|
195
|
+
async startWorkflow(data: any, opts: { invokeContext: IInvoke }) {
|
|
196
|
+
const { tenantCode } = getUserContext(opts.invokeContext);
|
|
197
|
+
|
|
198
|
+
// Create Step Functions task
|
|
199
|
+
const task = await this.taskService.createStepFunctionTask(
|
|
200
|
+
{
|
|
201
|
+
tenantCode,
|
|
202
|
+
taskType: 'ORDER_PROCESSING',
|
|
203
|
+
name: 'Process Order Workflow',
|
|
204
|
+
input: data,
|
|
205
|
+
},
|
|
206
|
+
opts,
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
// Task key for Step Functions: SFN_TASK#tenantCode
|
|
210
|
+
return task;
|
|
101
211
|
}
|
|
102
212
|
}
|
|
103
213
|
```
|
|
104
214
|
|
|
105
|
-
###
|
|
215
|
+
### Sub-task Processing
|
|
216
|
+
|
|
217
|
+
Split large tasks into parallel sub-tasks:
|
|
106
218
|
|
|
107
|
-
1. Update task progress:
|
|
108
219
|
```typescript
|
|
109
|
-
@
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
async
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
220
|
+
@Injectable()
|
|
221
|
+
export class BulkImportHandler implements IEventHandler<TaskQueueEvent> {
|
|
222
|
+
constructor(private readonly taskService: TaskService) {}
|
|
223
|
+
|
|
224
|
+
async handle(event: TaskQueueEvent) {
|
|
225
|
+
// Create sub-tasks from parent task input array
|
|
226
|
+
const subTasks = await this.taskService.createSubTask(event);
|
|
227
|
+
|
|
228
|
+
// Each sub-task processes one item from the input array
|
|
229
|
+
console.log(`Created ${subTasks.length} sub-tasks`);
|
|
230
|
+
|
|
231
|
+
// Update parent task status
|
|
232
|
+
await this.taskService.updateStatus(
|
|
233
|
+
event.taskEvent.taskKey,
|
|
234
|
+
TaskStatusEnum.PROCESSING,
|
|
235
|
+
);
|
|
123
236
|
}
|
|
124
237
|
}
|
|
125
238
|
```
|
|
126
239
|
|
|
127
|
-
###
|
|
240
|
+
### Task Status Updates
|
|
241
|
+
|
|
242
|
+
Update task status with SNS notifications:
|
|
128
243
|
|
|
129
|
-
1. Configure retry behavior:
|
|
130
244
|
```typescript
|
|
131
|
-
@
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
})
|
|
137
|
-
export class SendEmailTask {
|
|
138
|
-
async execute(
|
|
139
|
-
data: any,
|
|
140
|
-
metadata: TaskMetadata
|
|
141
|
-
): Promise<void> {
|
|
245
|
+
@Injectable()
|
|
246
|
+
export class TaskProcessor {
|
|
247
|
+
constructor(private readonly taskService: TaskService) {}
|
|
248
|
+
|
|
249
|
+
async processTask(pk: string, sk: string) {
|
|
142
250
|
try {
|
|
143
|
-
|
|
251
|
+
// Mark as processing
|
|
252
|
+
await this.taskService.updateStatus(
|
|
253
|
+
{ pk, sk },
|
|
254
|
+
TaskStatusEnum.PROCESSING,
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
// ... do work ...
|
|
258
|
+
|
|
259
|
+
// Mark as completed with result
|
|
260
|
+
await this.taskService.updateStatus(
|
|
261
|
+
{ pk, sk },
|
|
262
|
+
TaskStatusEnum.COMPLETED,
|
|
263
|
+
{ result: { processedCount: 100 } },
|
|
264
|
+
);
|
|
144
265
|
} catch (error) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
266
|
+
// Mark as failed with error
|
|
267
|
+
await this.taskService.updateStatus(
|
|
268
|
+
{ pk, sk },
|
|
269
|
+
TaskStatusEnum.FAILED,
|
|
270
|
+
{ error: error.message },
|
|
271
|
+
);
|
|
149
272
|
}
|
|
150
273
|
}
|
|
151
274
|
}
|
|
152
275
|
```
|
|
153
276
|
|
|
154
|
-
###
|
|
277
|
+
### List Tasks
|
|
278
|
+
|
|
279
|
+
Query tasks by tenant and type:
|
|
155
280
|
|
|
156
|
-
1. Work with multiple queues:
|
|
157
281
|
```typescript
|
|
158
282
|
@Injectable()
|
|
159
|
-
export class
|
|
160
|
-
constructor(
|
|
161
|
-
|
|
162
|
-
) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
//
|
|
171
|
-
await this.taskService.
|
|
283
|
+
export class TaskDashboard {
|
|
284
|
+
constructor(private readonly taskService: TaskService) {}
|
|
285
|
+
|
|
286
|
+
async getTaskList(tenantCode: string) {
|
|
287
|
+
// List standard tasks
|
|
288
|
+
const tasks = await this.taskService.listItemsByPk(
|
|
289
|
+
tenantCode,
|
|
290
|
+
'TASK',
|
|
291
|
+
{ limit: 20, order: 'desc' },
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
// List Step Function tasks
|
|
295
|
+
const sfnTasks = await this.taskService.listItemsByPk(
|
|
296
|
+
tenantCode,
|
|
297
|
+
'SFN_TASK',
|
|
298
|
+
{ limit: 20, order: 'desc' },
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
return { tasks: tasks.items, sfnTasks: sfnTasks.items };
|
|
172
302
|
}
|
|
173
303
|
}
|
|
174
304
|
```
|
|
175
305
|
|
|
176
|
-
|
|
306
|
+
## Event Handlers
|
|
307
|
+
|
|
308
|
+
The package provides built-in event handlers for task processing:
|
|
309
|
+
|
|
310
|
+
### TaskQueueEventHandler
|
|
311
|
+
|
|
312
|
+
Handles task queue events from SQS:
|
|
177
313
|
|
|
178
|
-
1. Access task history:
|
|
179
314
|
```typescript
|
|
180
|
-
@
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return history;
|
|
315
|
+
import { EventsHandler, IEventHandler } from '@mbc-cqrs-serverless/core';
|
|
316
|
+
import { TaskQueueEvent } from '@mbc-cqrs-serverless/task';
|
|
317
|
+
|
|
318
|
+
@EventsHandler(TaskQueueEvent)
|
|
319
|
+
export class MyTaskHandler implements IEventHandler<TaskQueueEvent> {
|
|
320
|
+
async handle(event: TaskQueueEvent) {
|
|
321
|
+
const { taskKey, taskEntity } = event.taskEvent;
|
|
322
|
+
// Process the task...
|
|
189
323
|
}
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### StepFunctionTaskEventHandler
|
|
190
328
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
329
|
+
Handles Step Functions task events:
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
import { EventsHandler, IEventHandler } from '@mbc-cqrs-serverless/core';
|
|
333
|
+
import { StepFunctionTaskEvent } from '@mbc-cqrs-serverless/task';
|
|
334
|
+
|
|
335
|
+
@EventsHandler(StepFunctionTaskEvent)
|
|
336
|
+
export class MySfnHandler implements IEventHandler<StepFunctionTaskEvent> {
|
|
337
|
+
async handle(event: StepFunctionTaskEvent) {
|
|
338
|
+
const { taskKey } = event;
|
|
339
|
+
// Process the Step Function task...
|
|
194
340
|
}
|
|
195
341
|
}
|
|
196
342
|
```
|
|
197
343
|
|
|
344
|
+
## Related Packages
|
|
345
|
+
|
|
346
|
+
| Package | Description |
|
|
347
|
+
|---------|-------------|
|
|
348
|
+
| [@mbc-cqrs-serverless/core](https://www.npmjs.com/package/@mbc-cqrs-serverless/core) | Core CQRS framework |
|
|
349
|
+
| [@mbc-cqrs-serverless/import](https://www.npmjs.com/package/@mbc-cqrs-serverless/import) | Data import with task processing |
|
|
350
|
+
|
|
198
351
|
## Documentation
|
|
199
352
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
-
|
|
203
|
-
-
|
|
204
|
-
- Monitoring and logging
|
|
205
|
-
- API reference
|
|
353
|
+
Full documentation available at [https://mbc-cqrs-serverless.mbc-net.com/](https://mbc-cqrs-serverless.mbc-net.com/)
|
|
354
|
+
|
|
355
|
+
- [Task Service Guide](https://mbc-cqrs-serverless.mbc-net.com/docs/task-service)
|
|
356
|
+
- [Step Functions Integration](https://mbc-cqrs-serverless.mbc-net.com/docs/step-functions)
|
|
206
357
|
|
|
207
358
|
## License
|
|
208
359
|
|
|
209
|
-
Copyright
|
|
210
|
-
|
|
360
|
+
Copyright © 2024-2025, Murakami Business Consulting, Inc. [https://www.mbc-net.com/](https://www.mbc-net.com/)
|
|
361
|
+
|
|
362
|
+
This project is under the [MIT License](../../LICENSE.txt).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mbc-cqrs-serverless/task",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.18",
|
|
4
4
|
"description": "long-running task",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mbc",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@mbc-cqrs-serverless/core": "1.0.
|
|
44
|
+
"@mbc-cqrs-serverless/core": "1.0.18"
|
|
45
45
|
},
|
|
46
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "f94a747c55ac4b09a643a5201dc89e4edda19c76"
|
|
47
47
|
}
|