@guanghechen/task 1.0.0-alpha.9 → 1.0.0-beta.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/CHANGELOG.md +119 -26
- package/lib/cjs/index.cjs +219 -206
- package/lib/esm/index.mjs +217 -197
- package/lib/types/index.d.ts +94 -33
- package/package.json +15 -29
package/lib/esm/index.mjs
CHANGED
|
@@ -1,138 +1,125 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { SoraErrorCollector } from '@guanghechen/error';
|
|
4
|
-
import { Monitor } from '@guanghechen/monitor';
|
|
1
|
+
import { Observable } from '@guanghechen/observable';
|
|
2
|
+
import { ErrorLevelEnum } from '@guanghechen/error.types';
|
|
5
3
|
|
|
6
|
-
|
|
4
|
+
var TaskStrategyEnum;
|
|
5
|
+
(function (TaskStrategyEnum) {
|
|
6
|
+
TaskStrategyEnum[TaskStrategyEnum["ABORT_ON_ERROR"] = 1] = "ABORT_ON_ERROR";
|
|
7
|
+
TaskStrategyEnum[TaskStrategyEnum["CONTINUE_ON_ERROR"] = 2] = "CONTINUE_ON_ERROR";
|
|
8
|
+
})(TaskStrategyEnum || (TaskStrategyEnum = {}));
|
|
9
|
+
var TaskStatusEnum;
|
|
10
|
+
(function (TaskStatusEnum) {
|
|
11
|
+
TaskStatusEnum[TaskStatusEnum["PENDING"] = 1] = "PENDING";
|
|
12
|
+
TaskStatusEnum[TaskStatusEnum["RUNNING"] = 2] = "RUNNING";
|
|
13
|
+
TaskStatusEnum[TaskStatusEnum["SUSPENDED"] = 4] = "SUSPENDED";
|
|
14
|
+
TaskStatusEnum[TaskStatusEnum["CANCELLED"] = 8] = "CANCELLED";
|
|
15
|
+
TaskStatusEnum[TaskStatusEnum["FAILED"] = 16] = "FAILED";
|
|
16
|
+
TaskStatusEnum[TaskStatusEnum["COMPLETED"] = 32] = "COMPLETED";
|
|
17
|
+
TaskStatusEnum[TaskStatusEnum["ATTEMPT_SUSPENDING"] = 64] = "ATTEMPT_SUSPENDING";
|
|
18
|
+
TaskStatusEnum[TaskStatusEnum["ATTEMPT_RESUMING"] = 128] = "ATTEMPT_RESUMING";
|
|
19
|
+
TaskStatusEnum[TaskStatusEnum["ATTEMPT_CANCELING"] = 256] = "ATTEMPT_CANCELING";
|
|
20
|
+
TaskStatusEnum[TaskStatusEnum["ATTEMPT_COMPLETING"] = 512] = "ATTEMPT_COMPLETING";
|
|
21
|
+
})(TaskStatusEnum || (TaskStatusEnum = {}));
|
|
7
22
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
TaskStatusEnum.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
TaskStatusEnum.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
23
|
+
const _terminated = TaskStatusEnum.CANCELLED | TaskStatusEnum.FAILED | TaskStatusEnum.COMPLETED;
|
|
24
|
+
const _transitionMap = {
|
|
25
|
+
[TaskStatusEnum.PENDING]: TaskStatusEnum.PENDING |
|
|
26
|
+
TaskStatusEnum.RUNNING |
|
|
27
|
+
TaskStatusEnum.CANCELLED |
|
|
28
|
+
TaskStatusEnum.ATTEMPT_CANCELING,
|
|
29
|
+
[TaskStatusEnum.RUNNING]: TaskStatusEnum.RUNNING |
|
|
30
|
+
TaskStatusEnum.SUSPENDED |
|
|
31
|
+
_terminated |
|
|
32
|
+
TaskStatusEnum.ATTEMPT_SUSPENDING |
|
|
33
|
+
TaskStatusEnum.ATTEMPT_CANCELING |
|
|
34
|
+
TaskStatusEnum.ATTEMPT_COMPLETING,
|
|
35
|
+
[TaskStatusEnum.SUSPENDED]: TaskStatusEnum.RUNNING |
|
|
36
|
+
TaskStatusEnum.SUSPENDED |
|
|
37
|
+
_terminated |
|
|
38
|
+
TaskStatusEnum.ATTEMPT_RESUMING |
|
|
39
|
+
TaskStatusEnum.ATTEMPT_CANCELING |
|
|
40
|
+
TaskStatusEnum.ATTEMPT_COMPLETING,
|
|
41
|
+
[TaskStatusEnum.CANCELLED]: TaskStatusEnum.CANCELLED,
|
|
42
|
+
[TaskStatusEnum.FAILED]: TaskStatusEnum.FAILED,
|
|
43
|
+
[TaskStatusEnum.COMPLETED]: TaskStatusEnum.COMPLETED,
|
|
44
|
+
[TaskStatusEnum.ATTEMPT_SUSPENDING]: TaskStatusEnum.SUSPENDED |
|
|
45
|
+
_terminated |
|
|
46
|
+
TaskStatusEnum.ATTEMPT_SUSPENDING |
|
|
47
|
+
TaskStatusEnum.ATTEMPT_CANCELING |
|
|
48
|
+
TaskStatusEnum.ATTEMPT_COMPLETING,
|
|
49
|
+
[TaskStatusEnum.ATTEMPT_RESUMING]: TaskStatusEnum.RUNNING |
|
|
50
|
+
_terminated |
|
|
51
|
+
TaskStatusEnum.ATTEMPT_RESUMING |
|
|
52
|
+
TaskStatusEnum.ATTEMPT_CANCELING |
|
|
53
|
+
TaskStatusEnum.ATTEMPT_COMPLETING,
|
|
54
|
+
[TaskStatusEnum.ATTEMPT_CANCELING]: _terminated | TaskStatusEnum.ATTEMPT_CANCELING,
|
|
55
|
+
[TaskStatusEnum.ATTEMPT_COMPLETING]: _terminated | TaskStatusEnum.ATTEMPT_COMPLETING,
|
|
56
|
+
};
|
|
57
|
+
class TaskStatus extends Observable {
|
|
58
|
+
constructor() {
|
|
59
|
+
super(TaskStatusEnum.PENDING);
|
|
37
60
|
}
|
|
38
61
|
get alive() {
|
|
39
|
-
|
|
62
|
+
const value = this.getSnapshot();
|
|
63
|
+
return (value & _terminated) === 0;
|
|
40
64
|
}
|
|
41
65
|
get terminated() {
|
|
42
|
-
|
|
66
|
+
const value = this.getSnapshot();
|
|
67
|
+
return (value & _terminated) > 0;
|
|
43
68
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
set status(status) {
|
|
53
|
-
const curStatus = this._status;
|
|
54
|
-
if (status !== curStatus) {
|
|
55
|
-
const accepted = this.check(status);
|
|
56
|
-
if (accepted) {
|
|
57
|
-
this._status = status;
|
|
58
|
-
this._monitorStatusChange.notify(status, curStatus);
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
throw new TypeError(`[transit] unexpected status: task(${this.name}) cur(${curStatus}) next(${status})`);
|
|
62
|
-
}
|
|
69
|
+
next(nextStatus, options) {
|
|
70
|
+
const curStatus = this.getSnapshot();
|
|
71
|
+
if (this._verifyTransition(curStatus, nextStatus)) {
|
|
72
|
+
super.next(nextStatus, options);
|
|
73
|
+
if ((nextStatus & _terminated) > 0)
|
|
74
|
+
this.dispose();
|
|
75
|
+
return;
|
|
63
76
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const unsubscribeOnAddError = this._monitorAddError.subscribe(onAddError);
|
|
70
|
-
const unsubscribeOnStatusChange = this._monitorStatusChange.subscribe(onStatusChange);
|
|
71
|
-
return () => {
|
|
72
|
-
unsubscribeOnAddError();
|
|
73
|
-
unsubscribeOnStatusChange();
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
check(nextStatus) {
|
|
77
|
-
const status = this._status;
|
|
78
|
-
switch (nextStatus) {
|
|
79
|
-
case TaskStatusEnum.PENDING:
|
|
80
|
-
return false;
|
|
81
|
-
case TaskStatusEnum.RUNNING:
|
|
82
|
-
return status === TaskStatusEnum.PENDING || status === TaskStatusEnum.ATTEMPT_RESUMING;
|
|
83
|
-
case TaskStatusEnum.SUSPENDED:
|
|
84
|
-
return status === TaskStatusEnum.ATTEMPT_SUSPENDING;
|
|
85
|
-
case TaskStatusEnum.CANCELLED:
|
|
86
|
-
return status === TaskStatusEnum.ATTEMPT_CANCELING;
|
|
87
|
-
case TaskStatusEnum.FAILED:
|
|
88
|
-
return (status !== TaskStatusEnum.PENDING &&
|
|
89
|
-
status !== TaskStatusEnum.SUSPENDED &&
|
|
90
|
-
(status & terminated) === 0);
|
|
91
|
-
case TaskStatusEnum.FINISHED:
|
|
92
|
-
return (status !== TaskStatusEnum.PENDING &&
|
|
93
|
-
status !== TaskStatusEnum.SUSPENDED &&
|
|
94
|
-
(status & terminated) === 0);
|
|
95
|
-
case TaskStatusEnum.ATTEMPT_SUSPENDING:
|
|
96
|
-
return status === TaskStatusEnum.RUNNING;
|
|
97
|
-
case TaskStatusEnum.ATTEMPT_RESUMING:
|
|
98
|
-
return status === TaskStatusEnum.SUSPENDED;
|
|
99
|
-
case TaskStatusEnum.ATTEMPT_CANCELING:
|
|
100
|
-
return (status & alive) > 0;
|
|
101
|
-
case TaskStatusEnum.ATTEMPT_FINISHING:
|
|
102
|
-
return status !== TaskStatusEnum.PENDING && (status & alive) > 0;
|
|
103
|
-
default:
|
|
104
|
-
return false;
|
|
77
|
+
const strict = options?.strict ?? true;
|
|
78
|
+
if (strict) {
|
|
79
|
+
const curStatusName = TaskStatusEnum[curStatus];
|
|
80
|
+
const nextStatusName = TaskStatusEnum[nextStatus];
|
|
81
|
+
throw new RangeError(`Invalid status transition: ${curStatusName} -> ${nextStatusName}.`);
|
|
105
82
|
}
|
|
106
83
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
this._monitorAddError.destroy();
|
|
113
|
-
}
|
|
114
|
-
_addError(type, error, level = ErrorLevelEnum.ERROR) {
|
|
115
|
-
this._errorCollector.add(type, error, level);
|
|
116
|
-
this._monitorAddError.notify(type, error, level);
|
|
84
|
+
_verifyTransition(curStatus, nextStatus) {
|
|
85
|
+
const validTransitions = _transitionMap[curStatus];
|
|
86
|
+
if (validTransitions === undefined)
|
|
87
|
+
return false;
|
|
88
|
+
return (nextStatus & validTransitions) > 0;
|
|
117
89
|
}
|
|
118
90
|
}
|
|
119
91
|
|
|
120
|
-
class AtomicTask
|
|
92
|
+
class AtomicTask {
|
|
93
|
+
name;
|
|
94
|
+
status;
|
|
95
|
+
strategy;
|
|
96
|
+
_errors;
|
|
121
97
|
_promise;
|
|
122
|
-
constructor(name) {
|
|
123
|
-
|
|
98
|
+
constructor(name, strategy) {
|
|
99
|
+
this.name = name;
|
|
100
|
+
this.strategy = strategy;
|
|
101
|
+
this.status = new TaskStatus();
|
|
102
|
+
this._errors = [];
|
|
124
103
|
this._promise = undefined;
|
|
125
104
|
}
|
|
105
|
+
get errors() {
|
|
106
|
+
return this._errors;
|
|
107
|
+
}
|
|
126
108
|
async start() {
|
|
127
|
-
if (this.status === TaskStatusEnum.PENDING) {
|
|
128
|
-
this.status
|
|
109
|
+
if (this.status.getSnapshot() === TaskStatusEnum.PENDING) {
|
|
110
|
+
this.status.next(TaskStatusEnum.RUNNING);
|
|
129
111
|
this._promise = this.run()
|
|
130
112
|
.then(() => {
|
|
131
|
-
this.status
|
|
113
|
+
this.status.next(TaskStatusEnum.COMPLETED);
|
|
132
114
|
})
|
|
133
115
|
.catch(error => {
|
|
134
|
-
|
|
135
|
-
|
|
116
|
+
const soraError = {
|
|
117
|
+
from: this.name,
|
|
118
|
+
level: ErrorLevelEnum.ERROR,
|
|
119
|
+
details: error,
|
|
120
|
+
};
|
|
121
|
+
this._errors.push(soraError);
|
|
122
|
+
this.status.next(TaskStatusEnum.FAILED);
|
|
136
123
|
});
|
|
137
124
|
}
|
|
138
125
|
return this._promise;
|
|
@@ -144,131 +131,164 @@ class AtomicTask extends TaskState {
|
|
|
144
131
|
await this._promise;
|
|
145
132
|
}
|
|
146
133
|
async cancel() {
|
|
147
|
-
if (this.status
|
|
148
|
-
this.status = TaskStatusEnum.ATTEMPT_CANCELING;
|
|
149
|
-
this.status = TaskStatusEnum.CANCELLED;
|
|
134
|
+
if (this.status.terminated)
|
|
150
135
|
return;
|
|
151
|
-
|
|
152
|
-
if (this.alive)
|
|
153
|
-
this.status = TaskStatusEnum.ATTEMPT_CANCELING;
|
|
136
|
+
this.status.next(TaskStatusEnum.ATTEMPT_CANCELING);
|
|
154
137
|
await this._promise;
|
|
138
|
+
this.status.next(TaskStatusEnum.CANCELLED, { strict: false });
|
|
155
139
|
}
|
|
156
|
-
async
|
|
157
|
-
|
|
140
|
+
async complete() {
|
|
141
|
+
const status = this.status;
|
|
142
|
+
if (status.getSnapshot() === TaskStatusEnum.PENDING)
|
|
158
143
|
await this.start();
|
|
159
|
-
if (
|
|
160
|
-
|
|
144
|
+
if (status.terminated)
|
|
145
|
+
return;
|
|
146
|
+
status.next(TaskStatusEnum.ATTEMPT_COMPLETING);
|
|
161
147
|
await this._promise;
|
|
148
|
+
status.next(TaskStatusEnum.COMPLETED, { strict: false });
|
|
162
149
|
}
|
|
163
150
|
}
|
|
164
151
|
|
|
165
|
-
class ResumableTask
|
|
152
|
+
class ResumableTask {
|
|
153
|
+
name;
|
|
154
|
+
status;
|
|
166
155
|
strategy;
|
|
156
|
+
_errors;
|
|
167
157
|
_pollInterval;
|
|
168
158
|
_execution;
|
|
169
159
|
_step;
|
|
170
|
-
constructor(
|
|
171
|
-
|
|
172
|
-
this.strategy =
|
|
173
|
-
this.
|
|
160
|
+
constructor(name, strategy, pollInterval) {
|
|
161
|
+
this.name = name;
|
|
162
|
+
this.strategy = strategy;
|
|
163
|
+
this.status = new TaskStatus();
|
|
164
|
+
this._errors = [];
|
|
165
|
+
this._pollInterval = Math.max(0, pollInterval);
|
|
174
166
|
this._execution = undefined;
|
|
175
167
|
this._step = undefined;
|
|
176
168
|
}
|
|
169
|
+
get errors() {
|
|
170
|
+
return this._errors;
|
|
171
|
+
}
|
|
177
172
|
async start() {
|
|
178
|
-
if (this.status === TaskStatusEnum.PENDING) {
|
|
179
|
-
this.status
|
|
173
|
+
if (this.status.getSnapshot() === TaskStatusEnum.PENDING) {
|
|
174
|
+
this.status.next(TaskStatusEnum.RUNNING);
|
|
180
175
|
this._execution = this.run();
|
|
181
|
-
this.
|
|
182
|
-
await this._step;
|
|
176
|
+
void this._launchStep();
|
|
183
177
|
}
|
|
184
178
|
}
|
|
185
179
|
async pause() {
|
|
186
|
-
if (this.status === TaskStatusEnum.RUNNING) {
|
|
187
|
-
this.status
|
|
180
|
+
if (this.status.getSnapshot() === TaskStatusEnum.RUNNING) {
|
|
181
|
+
this.status.next(TaskStatusEnum.ATTEMPT_SUSPENDING);
|
|
188
182
|
await this._step;
|
|
189
|
-
|
|
190
|
-
this.status = TaskStatusEnum.SUSPENDED;
|
|
191
|
-
}
|
|
183
|
+
this.status.next(TaskStatusEnum.SUSPENDED, { strict: false });
|
|
192
184
|
}
|
|
193
185
|
}
|
|
194
186
|
async resume() {
|
|
195
|
-
if (this.status === TaskStatusEnum.SUSPENDED) {
|
|
196
|
-
this.status
|
|
187
|
+
if (this.status.getSnapshot() === TaskStatusEnum.SUSPENDED) {
|
|
188
|
+
this.status.next(TaskStatusEnum.ATTEMPT_RESUMING);
|
|
197
189
|
await this._step;
|
|
198
|
-
if (this.status === TaskStatusEnum.ATTEMPT_RESUMING) {
|
|
199
|
-
this.status
|
|
200
|
-
this.
|
|
190
|
+
if (this.status.getSnapshot() === TaskStatusEnum.ATTEMPT_RESUMING) {
|
|
191
|
+
this.status.next(TaskStatusEnum.RUNNING);
|
|
192
|
+
void this._queueStep();
|
|
201
193
|
}
|
|
202
194
|
}
|
|
203
195
|
}
|
|
204
196
|
async cancel() {
|
|
205
|
-
if (this.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
}
|
|
197
|
+
if (this.status.terminated)
|
|
198
|
+
return;
|
|
199
|
+
this.status.next(TaskStatusEnum.ATTEMPT_CANCELING);
|
|
200
|
+
await this._step;
|
|
201
|
+
this.status.next(TaskStatusEnum.CANCELLED, { strict: false });
|
|
212
202
|
}
|
|
213
|
-
async
|
|
214
|
-
|
|
203
|
+
async complete() {
|
|
204
|
+
const status = this.status;
|
|
205
|
+
if (status.getSnapshot() === TaskStatusEnum.PENDING)
|
|
215
206
|
await this.start();
|
|
216
|
-
if (
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
if (step.done) {
|
|
224
|
-
this.status = this.hasError ? TaskStatusEnum.FAILED : TaskStatusEnum.FINISHED;
|
|
225
|
-
break;
|
|
226
|
-
}
|
|
227
|
-
await step.value.catch(error => {
|
|
228
|
-
this._addError('ResumableTaskError', error);
|
|
229
|
-
switch (this.strategy) {
|
|
230
|
-
case TaskStrategyEnum.ABORT_ON_ERROR:
|
|
231
|
-
if (!this.terminated)
|
|
232
|
-
this.status = TaskStatusEnum.FAILED;
|
|
233
|
-
break;
|
|
234
|
-
case TaskStrategyEnum.CONTINUE_ON_ERROR:
|
|
235
|
-
break;
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
launchStep() {
|
|
243
|
-
if (this.status === TaskStatusEnum.RUNNING && this._step === undefined && this._execution) {
|
|
244
|
-
const step = this._execution.next();
|
|
207
|
+
if (status.terminated)
|
|
208
|
+
return;
|
|
209
|
+
status.next(TaskStatusEnum.ATTEMPT_COMPLETING);
|
|
210
|
+
await this._step;
|
|
211
|
+
const execution = this._execution;
|
|
212
|
+
for (let alive = true; alive;) {
|
|
213
|
+
const step = execution.next();
|
|
245
214
|
if (step.done) {
|
|
246
|
-
|
|
247
|
-
|
|
215
|
+
const nextStatus = this._errors.length > 0 ? TaskStatusEnum.FAILED : TaskStatusEnum.COMPLETED;
|
|
216
|
+
status.next(nextStatus, { strict: false });
|
|
217
|
+
break;
|
|
248
218
|
}
|
|
249
|
-
|
|
250
|
-
.
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
219
|
+
try {
|
|
220
|
+
await step.value;
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
const soraError = {
|
|
224
|
+
from: this.name,
|
|
225
|
+
level: ErrorLevelEnum.ERROR,
|
|
226
|
+
details: error,
|
|
227
|
+
};
|
|
228
|
+
this._errors.push(soraError);
|
|
257
229
|
switch (this.strategy) {
|
|
258
230
|
case TaskStrategyEnum.ABORT_ON_ERROR:
|
|
259
|
-
|
|
260
|
-
|
|
231
|
+
status.next(TaskStatusEnum.FAILED, { strict: false });
|
|
232
|
+
alive = false;
|
|
261
233
|
break;
|
|
262
234
|
case TaskStrategyEnum.CONTINUE_ON_ERROR:
|
|
263
|
-
this.
|
|
235
|
+
await this._queueStep();
|
|
264
236
|
break;
|
|
265
237
|
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (status.alive) {
|
|
241
|
+
const soraError = {
|
|
242
|
+
from: this.name,
|
|
243
|
+
level: ErrorLevelEnum.ERROR,
|
|
244
|
+
details: new RangeError('The task is not terminated.'),
|
|
245
|
+
};
|
|
246
|
+
this._errors.push(soraError);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
async _launchStep() {
|
|
250
|
+
if (this._execution === undefined)
|
|
251
|
+
return;
|
|
252
|
+
if (this._step !== undefined)
|
|
253
|
+
return;
|
|
254
|
+
if (this.status.getSnapshot() !== TaskStatusEnum.RUNNING)
|
|
255
|
+
return;
|
|
256
|
+
const execution = this._execution;
|
|
257
|
+
const step = execution.next();
|
|
258
|
+
if (step.done) {
|
|
259
|
+
this.status.next(this._errors.length > 0 ? TaskStatusEnum.FAILED : TaskStatusEnum.COMPLETED, {
|
|
260
|
+
strict: false,
|
|
266
261
|
});
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
this._step = step.value;
|
|
265
|
+
try {
|
|
266
|
+
await step.value;
|
|
267
|
+
this._step = undefined;
|
|
268
|
+
void this._queueStep();
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
this._step = undefined;
|
|
272
|
+
const soraError = {
|
|
273
|
+
from: this.name,
|
|
274
|
+
level: ErrorLevelEnum.ERROR,
|
|
275
|
+
details: error,
|
|
276
|
+
};
|
|
277
|
+
this._errors.push(soraError);
|
|
278
|
+
switch (this.strategy) {
|
|
279
|
+
case TaskStrategyEnum.ABORT_ON_ERROR:
|
|
280
|
+
this.status.next(TaskStatusEnum.FAILED, { strict: false });
|
|
281
|
+
break;
|
|
282
|
+
case TaskStrategyEnum.CONTINUE_ON_ERROR:
|
|
283
|
+
void this._queueStep();
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
267
286
|
}
|
|
268
287
|
}
|
|
269
|
-
|
|
270
|
-
|
|
288
|
+
async _queueStep() {
|
|
289
|
+
await new Promise(resolve => setTimeout(resolve, this._pollInterval));
|
|
290
|
+
await this._launchStep();
|
|
271
291
|
}
|
|
272
292
|
}
|
|
273
293
|
|
|
274
|
-
export { AtomicTask, ResumableTask,
|
|
294
|
+
export { AtomicTask, ResumableTask, TaskStatus, TaskStatusEnum, TaskStrategyEnum };
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,58 +1,119 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { TaskStatusEnum, TaskStrategyEnum } from '@guanghechen/constant';
|
|
3
|
-
import { ITaskState, ISoraErrorCollector, ITaskError, ITaskMonitor, IUnMonitorTask, ITask } from '@guanghechen/types';
|
|
4
|
-
export { ITask, ITaskError, ITaskMonitor, ITaskState } from '@guanghechen/types';
|
|
1
|
+
import { IObservable, IObservableNextOptions, Observable } from '@guanghechen/observable';
|
|
5
2
|
|
|
6
|
-
declare
|
|
3
|
+
declare enum TaskStrategyEnum {
|
|
4
|
+
ABORT_ON_ERROR = 1,// Abort the task if any error occurred.
|
|
5
|
+
CONTINUE_ON_ERROR = 2
|
|
6
|
+
}
|
|
7
|
+
declare enum TaskStatusEnum {
|
|
8
|
+
PENDING = 1,// Task not start.
|
|
9
|
+
RUNNING = 2,// Task is running.
|
|
10
|
+
SUSPENDED = 4,// Task is paused.
|
|
11
|
+
CANCELLED = 8,// Task is cancelled.
|
|
12
|
+
FAILED = 16,// Task is failed.
|
|
13
|
+
COMPLETED = 32,// Task is completed.
|
|
14
|
+
ATTEMPT_SUSPENDING = 64,// Attempting to suspend the task.
|
|
15
|
+
ATTEMPT_RESUMING = 128,// Attempting to resume the task.
|
|
16
|
+
ATTEMPT_CANCELING = 256,// Attempting to cancel the task.
|
|
17
|
+
ATTEMPT_COMPLETING = 512
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface ITaskStatus extends IObservable<TaskStatusEnum> {
|
|
21
|
+
/**
|
|
22
|
+
* Whether the task was alive.
|
|
23
|
+
*/
|
|
24
|
+
readonly alive: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Whether the task was terminated.
|
|
27
|
+
*/
|
|
28
|
+
readonly terminated: boolean;
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
* @param nextStatus
|
|
32
|
+
* @param options
|
|
33
|
+
*/
|
|
34
|
+
next(nextStatus: TaskStatusEnum, options?: IObservableNextOptions): void;
|
|
35
|
+
}
|
|
36
|
+
interface ITask {
|
|
37
|
+
/**
|
|
38
|
+
* Task name.
|
|
39
|
+
*/
|
|
7
40
|
readonly name: string;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Task status.
|
|
43
|
+
*/
|
|
44
|
+
readonly status: ITaskStatus;
|
|
45
|
+
/**
|
|
46
|
+
* Task strategy.
|
|
47
|
+
*/
|
|
48
|
+
readonly strategy: TaskStrategyEnum;
|
|
49
|
+
/**
|
|
50
|
+
* Errors while run the task.
|
|
51
|
+
*/
|
|
52
|
+
readonly errors: ReadonlyArray<unknown>;
|
|
53
|
+
/**
|
|
54
|
+
* Start the task.
|
|
55
|
+
*/
|
|
56
|
+
start(): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Pause the task.
|
|
59
|
+
*/
|
|
60
|
+
pause(): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Resume the task.
|
|
63
|
+
*/
|
|
64
|
+
resume(): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Cancel the task.
|
|
67
|
+
*/
|
|
68
|
+
cancel(): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* finish the task: run to completed no matter if the task started or not.
|
|
71
|
+
*/
|
|
72
|
+
complete(): Promise<void>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
declare class TaskStatus extends Observable<TaskStatusEnum> implements ITaskStatus {
|
|
76
|
+
constructor();
|
|
15
77
|
get alive(): boolean;
|
|
16
78
|
get terminated(): boolean;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
set status(status: TaskStatusEnum);
|
|
20
|
-
monitor(monitor: Partial<ITaskMonitor>): IUnMonitorTask;
|
|
21
|
-
check(nextStatus: TaskStatusEnum): boolean;
|
|
22
|
-
cleanup(): void;
|
|
23
|
-
protected _addError(type: string, error: unknown, level?: ErrorLevelEnum): void;
|
|
79
|
+
next(nextStatus: TaskStatusEnum, options?: IObservableNextOptions): void;
|
|
80
|
+
protected _verifyTransition(curStatus: TaskStatusEnum, nextStatus: TaskStatusEnum): boolean;
|
|
24
81
|
}
|
|
25
82
|
|
|
26
|
-
declare abstract class AtomicTask
|
|
83
|
+
declare abstract class AtomicTask implements ITask {
|
|
84
|
+
readonly name: string;
|
|
85
|
+
readonly status: ITaskStatus;
|
|
86
|
+
readonly strategy: TaskStrategyEnum;
|
|
87
|
+
protected readonly _errors: unknown[];
|
|
27
88
|
private _promise;
|
|
28
|
-
constructor(name: string);
|
|
89
|
+
constructor(name: string, strategy: TaskStrategyEnum);
|
|
90
|
+
get errors(): ReadonlyArray<unknown>;
|
|
29
91
|
start(): Promise<void>;
|
|
30
92
|
pause(): Promise<void>;
|
|
31
93
|
resume(): Promise<void>;
|
|
32
94
|
cancel(): Promise<void>;
|
|
33
|
-
|
|
95
|
+
complete(): Promise<void>;
|
|
34
96
|
protected abstract run(): Promise<void>;
|
|
35
97
|
}
|
|
36
98
|
|
|
37
|
-
|
|
38
|
-
name: string;
|
|
39
|
-
|
|
40
|
-
pollInterval: number;
|
|
41
|
-
}
|
|
42
|
-
declare abstract class ResumableTask extends TaskState implements ITask {
|
|
99
|
+
declare abstract class ResumableTask implements ITask {
|
|
100
|
+
readonly name: string;
|
|
101
|
+
readonly status: ITaskStatus;
|
|
43
102
|
readonly strategy: TaskStrategyEnum;
|
|
103
|
+
protected readonly _errors: unknown[];
|
|
44
104
|
private readonly _pollInterval;
|
|
45
105
|
private _execution;
|
|
46
106
|
private _step;
|
|
47
|
-
constructor(
|
|
107
|
+
constructor(name: string, strategy: TaskStrategyEnum, pollInterval: number);
|
|
108
|
+
get errors(): ReadonlyArray<unknown>;
|
|
48
109
|
start(): Promise<void>;
|
|
49
110
|
pause(): Promise<void>;
|
|
50
111
|
resume(): Promise<void>;
|
|
51
112
|
cancel(): Promise<void>;
|
|
52
|
-
|
|
113
|
+
complete(): Promise<void>;
|
|
53
114
|
protected abstract run(): IterableIterator<Promise<void>>;
|
|
54
|
-
private
|
|
55
|
-
private
|
|
115
|
+
private _launchStep;
|
|
116
|
+
private _queueStep;
|
|
56
117
|
}
|
|
57
118
|
|
|
58
|
-
export { AtomicTask, ResumableTask,
|
|
119
|
+
export { AtomicTask, type ITask, type ITaskStatus, ResumableTask, TaskStatus, TaskStatusEnum, TaskStrategyEnum };
|