@mbc-cqrs-serverless/task 1.0.16 → 1.0.17

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.
Files changed (2) hide show
  1. package/README.md +281 -129
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -1,17 +1,20 @@
1
1
  ![MBC CQRS serverless framework](https://mbc-cqrs-serverless.mbc-net.com/img/mbc-cqrs-serverless.png)
2
2
 
3
- # MBC CQRS serverless framework Task package
3
+ # @mbc-cqrs-serverless/task
4
4
 
5
- ## Description
5
+ [![npm version](https://badge.fury.io/js/@mbc-cqrs-serverless%2Ftask.svg)](https://www.npmjs.com/package/@mbc-cqrs-serverless/task)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
7
 
7
- The Task package provides comprehensive task management functionality in the MBC CQRS Serverless framework. It enables:
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
- - Asynchronous task execution
10
- - Task status tracking
11
- - Progress monitoring
12
- - Error handling and retries
13
- - Task queue management
14
- - Task history and logging
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
- ## Usage
25
+ ## Quick Start
23
26
 
24
- ### Basic Setup
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.forRoot({
34
- queueUrl: process.env.TASK_QUEUE_URL,
35
- region: 'ap-northeast-1',
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
- ### Creating Tasks
58
+ ### 2. Create and Monitor Tasks
43
59
 
44
- 1. Define a task:
45
60
  ```typescript
46
- import { Task, TaskMetadata } from '@mbc-cqrs-serverless/task';
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
- @Task({
49
- name: 'ProcessOrder',
50
- maxRetries: 3,
51
- timeout: 300, // 5 minutes
52
- })
53
- export class ProcessOrderTask {
54
- async execute(
55
- data: any,
56
- metadata: TaskMetadata
57
- ): Promise<void> {
58
- // Task implementation
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
- 2. Schedule a task:
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
- import { TaskService } from '@mbc-cqrs-serverless/task';
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 OrderService {
69
- constructor(
70
- private readonly taskService: TaskService
71
- ) {}
72
-
73
- async processOrder(orderId: string): Promise<void> {
74
- await this.taskService.schedule('ProcessOrder', {
75
- orderId,
76
- items: [],
77
- // ... other data
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
- ### Task Status Tracking
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 TaskMonitor {
89
- constructor(
90
- private readonly taskService: TaskService
91
- ) {}
92
-
93
- async checkTaskStatus(taskId: string): Promise<TaskStatus> {
94
- const task = await this.taskService.getTask(taskId);
95
- return task.status;
96
- }
97
-
98
- async getTaskProgress(taskId: string): Promise<number> {
99
- const task = await this.taskService.getTask(taskId);
100
- return task.progress || 0;
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
- ### Progress Updates
215
+ ### Sub-task Processing
216
+
217
+ Split large tasks into parallel sub-tasks:
106
218
 
107
- 1. Update task progress:
108
219
  ```typescript
109
- @Task({
110
- name: 'BatchProcess',
111
- })
112
- export class BatchProcessTask {
113
- async execute(
114
- data: any,
115
- metadata: TaskMetadata
116
- ): Promise<void> {
117
- const total = data.items.length;
118
-
119
- for (let i = 0; i < total; i++) {
120
- await this.processItem(data.items[i]);
121
- await metadata.updateProgress((i + 1) / total * 100);
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
- ### Error Handling and Retries
240
+ ### Task Status Updates
241
+
242
+ Update task status with SNS notifications:
128
243
 
129
- 1. Configure retry behavior:
130
244
  ```typescript
131
- @Task({
132
- name: 'SendEmail',
133
- maxRetries: 3,
134
- retryDelay: 60, // 1 minute
135
- retryStrategy: 'exponential',
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
- await this.emailService.send(data);
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
- if (error.retryable) {
146
- throw new RetryableError(error.message);
147
- }
148
- throw error;
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
- ### Queue Management
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 WorkflowService {
160
- constructor(
161
- private readonly taskService: TaskService
162
- ) {}
163
-
164
- async scheduleWorkflow(): Promise<void> {
165
- // High priority queue
166
- await this.taskService.schedule('CriticalTask', data, {
167
- queueUrl: process.env.HIGH_PRIORITY_QUEUE_URL,
168
- });
169
-
170
- // Default queue
171
- await this.taskService.schedule('NormalTask', data);
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
- ### Task History and Logging
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
- @Injectable()
181
- export class AuditService {
182
- constructor(
183
- private readonly taskService: TaskService
184
- ) {}
185
-
186
- async getTaskHistory(taskId: string): Promise<TaskHistory[]> {
187
- const history = await this.taskService.getTaskHistory(taskId);
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
- async getTaskLogs(taskId: string): Promise<TaskLog[]> {
192
- const logs = await this.taskService.getTaskLogs(taskId);
193
- return logs;
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
- Visit https://mbc-cqrs-serverless.mbc-net.com/ to view the full documentation, including:
201
- - Task configuration
202
- - Queue management
203
- - Error handling strategies
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 &copy; 2024, Murakami Business Consulting, Inc. https://www.mbc-net.com/
210
- This project and sub projects are under the MIT License.
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.16",
3
+ "version": "1.0.17",
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.16"
44
+ "@mbc-cqrs-serverless/core": "1.0.17"
45
45
  },
46
- "gitHead": "4ab967474160873735b8cb816272a7012b8940d5"
46
+ "gitHead": "1870821803cfb045c9c4d6bc18d513fa2558de1c"
47
47
  }