@guanghechen/task 2.0.0 → 2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023-present guanghechen (https://github.com/guanghechen)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -49,7 +49,8 @@
49
49
  </header>
50
50
  <br/>
51
51
 
52
- Atomic and resumable tasks implementation with observable status tracking.
52
+ Atomic and resumable tasks implementation with observable status tracking. Provides two task types:
53
+ `AtomicTask` for one-shot operations and `ResumableTask` for pausable/resumable operations.
53
54
 
54
55
  ## Install
55
56
 
@@ -67,5 +68,124 @@ Atomic and resumable tasks implementation with observable status tracking.
67
68
 
68
69
  ## Usage
69
70
 
71
+ ### AtomicTask
72
+
73
+ For tasks that run to completion without pause/resume support:
74
+
75
+ ```typescript
76
+ import { AtomicTask, TaskStatusEnum, TaskStrategyEnum } from '@guanghechen/task'
77
+ import { Subscriber } from '@guanghechen/subscriber'
78
+
79
+ class DownloadTask extends AtomicTask {
80
+ private readonly url: string
81
+
82
+ constructor(url: string) {
83
+ super('download-task', TaskStrategyEnum.ABORT_ON_ERROR)
84
+ this.url = url
85
+ }
86
+
87
+ protected async run(): Promise<void> {
88
+ // Perform the download operation
89
+ console.log(`Downloading from ${this.url}`)
90
+ await fetch(this.url)
91
+ console.log('Download complete')
92
+ }
93
+ }
94
+
95
+ const task = new DownloadTask('https://example.com/file')
96
+
97
+ // Subscribe to status changes
98
+ const subscriber = new Subscriber({
99
+ onNext: (status) => {
100
+ console.log('Status:', TaskStatusEnum[status])
101
+ }
102
+ })
103
+ task.status.subscribe(subscriber)
104
+
105
+ // Start the task
106
+ await task.start()
107
+
108
+ // Or run to completion
109
+ await task.complete()
110
+
111
+ // Check for errors
112
+ if (task.errors.length > 0) {
113
+ console.error('Task failed:', task.errors)
114
+ }
115
+ ```
116
+
117
+ ### ResumableTask
118
+
119
+ For tasks that can be paused and resumed:
120
+
121
+ ```typescript
122
+ import { ResumableTask, TaskStatusEnum, TaskStrategyEnum } from '@guanghechen/task'
123
+
124
+ class BatchProcessTask extends ResumableTask {
125
+ private readonly items: string[]
126
+
127
+ constructor(items: string[]) {
128
+ super('batch-process', TaskStrategyEnum.CONTINUE_ON_ERROR, 100) // 100ms poll interval
129
+ this.items = items
130
+ }
131
+
132
+ protected *run(): IterableIterator<Promise<void>> {
133
+ for (const item of this.items) {
134
+ yield this.processItem(item)
135
+ }
136
+ }
137
+
138
+ private async processItem(item: string): Promise<void> {
139
+ console.log(`Processing: ${item}`)
140
+ await new Promise(resolve => setTimeout(resolve, 500))
141
+ }
142
+ }
143
+
144
+ const task = new BatchProcessTask(['item1', 'item2', 'item3'])
145
+
146
+ // Start the task
147
+ await task.start()
148
+
149
+ // Pause after some time
150
+ setTimeout(async () => {
151
+ await task.pause()
152
+ console.log('Task paused')
153
+
154
+ // Resume later
155
+ setTimeout(async () => {
156
+ await task.resume()
157
+ console.log('Task resumed')
158
+ }, 2000)
159
+ }, 1000)
160
+ ```
161
+
162
+ ### Task Status
163
+
164
+ Tasks have observable status with the following states:
165
+
166
+ | Status | Description |
167
+ | :------------------: | :----------------------------------: |
168
+ | `PENDING` | Task not started |
169
+ | `RUNNING` | Task is running |
170
+ | `SUSPENDED` | Task is paused (ResumableTask only) |
171
+ | `CANCELLED` | Task was cancelled |
172
+ | `FAILED` | Task failed with errors |
173
+ | `COMPLETED` | Task completed successfully |
174
+ | `ATTEMPT_SUSPENDING` | Attempting to pause |
175
+ | `ATTEMPT_RESUMING` | Attempting to resume |
176
+ | `ATTEMPT_CANCELING` | Attempting to cancel |
177
+ | `ATTEMPT_COMPLETING` | Attempting to complete |
178
+
179
+ ### Task Strategy
180
+
181
+ | Strategy | Description |
182
+ | :-----------------: | :--------------------------------------------: |
183
+ | `ABORT_ON_ERROR` | Stop task execution when an error occurs |
184
+ | `CONTINUE_ON_ERROR` | Continue execution despite errors |
185
+
186
+ ## Reference
187
+
188
+ - [homepage][homepage]
189
+
70
190
  [homepage]:
71
- https://github.com/guanghechen/sora/tree/@guanghechen/task@2.0.0/packages/task#readme
191
+ https://github.com/guanghechen/sora/tree/@guanghechen/task@2.0.0/packages/task#readme
package/lib/cjs/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var observable = require('@guanghechen/observable');
4
- var error_types = require('@guanghechen/error.types');
4
+ var types = require('@guanghechen/types');
5
5
 
6
6
  exports.TaskStrategyEnum = void 0;
7
7
  (function (TaskStrategyEnum) {
@@ -128,7 +128,7 @@ class AtomicTask {
128
128
  .catch(error => {
129
129
  const soraError = {
130
130
  from: this.name,
131
- level: error_types.ErrorLevelEnum.ERROR,
131
+ level: types.ErrorLevelEnum.ERROR,
132
132
  details: error,
133
133
  };
134
134
  this._errors.push(soraError);
@@ -235,7 +235,7 @@ class ResumableTask {
235
235
  catch (error) {
236
236
  const soraError = {
237
237
  from: this.name,
238
- level: error_types.ErrorLevelEnum.ERROR,
238
+ level: types.ErrorLevelEnum.ERROR,
239
239
  details: error,
240
240
  };
241
241
  this._errors.push(soraError);
@@ -253,7 +253,7 @@ class ResumableTask {
253
253
  if (status.alive) {
254
254
  const soraError = {
255
255
  from: this.name,
256
- level: error_types.ErrorLevelEnum.ERROR,
256
+ level: types.ErrorLevelEnum.ERROR,
257
257
  details: new RangeError('The task is not terminated.'),
258
258
  };
259
259
  this._errors.push(soraError);
@@ -284,7 +284,7 @@ class ResumableTask {
284
284
  this._step = undefined;
285
285
  const soraError = {
286
286
  from: this.name,
287
- level: error_types.ErrorLevelEnum.ERROR,
287
+ level: types.ErrorLevelEnum.ERROR,
288
288
  details: error,
289
289
  };
290
290
  this._errors.push(soraError);
@@ -299,8 +299,21 @@ class ResumableTask {
299
299
  }
300
300
  }
301
301
  async _queueStep() {
302
- await new Promise(resolve => setTimeout(resolve, this._pollInterval));
303
- await this._launchStep();
302
+ try {
303
+ await new Promise(resolve => setTimeout(resolve, this._pollInterval));
304
+ await this._launchStep();
305
+ }
306
+ catch (error) {
307
+ if (this.status.terminated)
308
+ return;
309
+ const soraError = {
310
+ from: this.name,
311
+ level: types.ErrorLevelEnum.ERROR,
312
+ details: error,
313
+ };
314
+ this._errors.push(soraError);
315
+ this.status.next(exports.TaskStatusEnum.FAILED, { strict: false });
316
+ }
304
317
  }
305
318
  }
306
319
 
package/lib/esm/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Observable } from '@guanghechen/observable';
2
- import { ErrorLevelEnum } from '@guanghechen/error.types';
2
+ import { ErrorLevelEnum } from '@guanghechen/types';
3
3
 
4
4
  var TaskStrategyEnum;
5
5
  (function (TaskStrategyEnum) {
@@ -297,8 +297,21 @@ class ResumableTask {
297
297
  }
298
298
  }
299
299
  async _queueStep() {
300
- await new Promise(resolve => setTimeout(resolve, this._pollInterval));
301
- await this._launchStep();
300
+ try {
301
+ await new Promise(resolve => setTimeout(resolve, this._pollInterval));
302
+ await this._launchStep();
303
+ }
304
+ catch (error) {
305
+ if (this.status.terminated)
306
+ return;
307
+ const soraError = {
308
+ from: this.name,
309
+ level: ErrorLevelEnum.ERROR,
310
+ details: error,
311
+ };
312
+ this._errors.push(soraError);
313
+ this.status.next(TaskStatusEnum.FAILED, { strict: false });
314
+ }
302
315
  }
303
316
  }
304
317
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guanghechen/task",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Atomic and resumable tasks",
5
5
  "author": {
6
6
  "name": "guanghechen",
@@ -8,17 +8,17 @@
8
8
  },
9
9
  "repository": {
10
10
  "type": "git",
11
- "url": "https://github.com/guanghechen/sora/tree/@guanghechen/task@1.0.6",
11
+ "url": "https://github.com/guanghechen/sora/tree/@guanghechen/task@2.0.0",
12
12
  "directory": "packages/task"
13
13
  },
14
- "homepage": "https://github.com/guanghechen/sora/tree/@guanghechen/task@1.0.6/packages/task#readme",
14
+ "homepage": "https://github.com/guanghechen/sora/tree/@guanghechen/task@2.0.0/packages/task#readme",
15
15
  "type": "module",
16
16
  "exports": {
17
17
  ".": {
18
+ "types": "./lib/types/index.d.ts",
18
19
  "source": "./src/index.ts",
19
20
  "import": "./lib/esm/index.mjs",
20
- "require": "./lib/cjs/index.cjs",
21
- "types": "./lib/types/index.d.ts"
21
+ "require": "./lib/cjs/index.cjs"
22
22
  }
23
23
  },
24
24
  "source": "./src/index.ts",
@@ -26,13 +26,6 @@
26
26
  "module": "./lib/esm/index.mjs",
27
27
  "types": "./lib/types/index.d.ts",
28
28
  "license": "MIT",
29
- "scripts": {
30
- "build": "rollup -c ../../rollup.config.mjs",
31
- "clean": "rimraf lib",
32
- "test": "vitest run --config ../../vitest.config.ts",
33
- "test:coverage": "vitest run --config ../../vitest.config.ts --coverage",
34
- "test:update": "vitest run --config ../../vitest.config.ts -u"
35
- },
36
29
  "files": [
37
30
  "lib/",
38
31
  "!lib/**/*.map",
@@ -42,8 +35,14 @@
42
35
  "README.md"
43
36
  ],
44
37
  "dependencies": {
45
- "@guanghechen/error.types": "^2.0.0",
46
- "@guanghechen/observable": "^7.0.0"
38
+ "@guanghechen/observable": "^7.0.1",
39
+ "@guanghechen/types": "^2.0.1"
47
40
  },
48
- "gitHead": "12990a720b31d50d217e2e17a6191256dc94eda6"
49
- }
41
+ "scripts": {
42
+ "build": "rollup -c ../../rollup.config.mjs",
43
+ "clean": "rimraf lib",
44
+ "test": "vitest run --config ../../vitest.config.ts",
45
+ "test:coverage": "vitest run --config ../../vitest.config.ts --coverage",
46
+ "test:update": "vitest run --config ../../vitest.config.ts -u"
47
+ }
48
+ }