@angular-devkit/core 12.0.0-rc.0 → 12.0.0
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 +36 -34
- package/node/_golden-api.d.ts +1 -1
- package/node/_golden-api.js +1 -1
- package/node/cli-logger.d.ts +7 -0
- package/node/cli-logger.js +4 -6
- package/node/experimental/index.d.ts +2 -2
- package/node/experimental/index.js +3 -3
- package/node/experimental/jobs/index.d.ts +1 -1
- package/node/experimental/jobs/index.js +7 -7
- package/node/experimental/jobs/job-registry.d.ts +1 -1
- package/node/experimental/jobs/job-registry.js +4 -4
- package/node/fs.d.ts +7 -0
- package/node/fs.js +3 -3
- package/node/host.d.ts +2 -2
- package/node/host.js +31 -33
- package/node/index.d.ts +2 -2
- package/node/index.js +1 -1
- package/node/testing/index.d.ts +2 -2
- package/node/testing/index.js +8 -5
- package/package.json +3 -3
- package/src/_golden-api.d.ts +1 -1
- package/src/_golden-api.js +1 -1
- package/src/analytics/api.d.ts +1 -1
- package/src/analytics/api.js +7 -0
- package/src/analytics/forwarder.d.ts +1 -1
- package/src/analytics/forwarder.js +7 -0
- package/src/analytics/index.d.ts +1 -1
- package/src/analytics/index.js +7 -7
- package/src/analytics/logging.d.ts +1 -1
- package/src/analytics/logging.js +7 -0
- package/src/analytics/multi.d.ts +1 -1
- package/src/analytics/multi.js +6 -6
- package/src/analytics/noop.d.ts +1 -1
- package/src/analytics/noop.js +10 -1
- package/src/exception/exception.d.ts +1 -1
- package/src/exception/exception.js +25 -9
- package/src/exception/index.d.ts +1 -1
- package/src/exception/index.js +1 -1
- package/src/experimental/jobs/README.md +133 -112
- package/src/experimental/jobs/api.d.ts +1 -1
- package/src/experimental/jobs/api.js +8 -3
- package/src/experimental/jobs/architecture.md +43 -38
- package/src/experimental/jobs/create-job-handler.d.ts +1 -2
- package/src/experimental/jobs/create-job-handler.js +17 -14
- package/src/experimental/jobs/dispatcher.d.ts +1 -2
- package/src/experimental/jobs/dispatcher.js +7 -0
- package/src/experimental/jobs/exception.d.ts +1 -1
- package/src/experimental/jobs/exception.js +3 -3
- package/src/experimental/jobs/fallback-registry.d.ts +1 -1
- package/src/experimental/jobs/fallback-registry.js +4 -4
- package/src/experimental/jobs/index.d.ts +1 -1
- package/src/experimental/jobs/index.js +7 -7
- package/src/experimental/jobs/simple-registry.d.ts +1 -1
- package/src/experimental/jobs/simple-registry.js +6 -4
- package/src/experimental/jobs/simple-scheduler.d.ts +1 -1
- package/src/experimental/jobs/simple-scheduler.js +38 -29
- package/src/experimental/jobs/strategy.d.ts +7 -0
- package/src/experimental/jobs/strategy.js +10 -9
- package/src/experimental.d.ts +2 -2
- package/src/experimental.js +3 -3
- package/src/index.d.ts +2 -2
- package/src/index.js +7 -7
- package/src/json/index.d.ts +2 -2
- package/src/json/index.js +9 -9
- package/src/json/interface.d.ts +1 -1
- package/src/json/interface.js +7 -0
- package/src/json/parser.d.ts +1 -1
- package/src/json/parser.js +39 -22
- package/src/json/schema/index.d.ts +2 -2
- package/src/json/schema/index.js +9 -9
- package/src/json/schema/interface.d.ts +1 -1
- package/src/json/schema/interface.js +7 -0
- package/src/json/schema/pointer.d.ts +1 -1
- package/src/json/schema/pointer.js +17 -5
- package/src/json/schema/registry.d.ts +1 -1
- package/src/json/schema/registry.js +28 -47
- package/src/json/schema/schema.d.ts +1 -1
- package/src/json/schema/schema.js +3 -3
- package/src/json/schema/transforms.d.ts +1 -1
- package/src/json/schema/transforms.js +14 -13
- package/src/json/schema/utility.d.ts +7 -0
- package/src/json/schema/utility.js +7 -7
- package/src/json/schema/visitor.d.ts +1 -1
- package/src/json/schema/visitor.js +8 -7
- package/src/logger/indent.d.ts +7 -0
- package/src/logger/indent.js +5 -5
- package/src/logger/index.d.ts +1 -1
- package/src/logger/index.js +7 -7
- package/src/logger/level.d.ts +1 -1
- package/src/logger/level.js +7 -0
- package/src/logger/logger.d.ts +1 -1
- package/src/logger/logger.js +13 -6
- package/src/logger/null-logger.d.ts +7 -0
- package/src/logger/null-logger.js +3 -3
- package/src/logger/transform-logger.d.ts +1 -1
- package/src/logger/transform-logger.js +7 -0
- package/src/utils/array.d.ts +1 -1
- package/src/utils/array.js +2 -2
- package/src/utils/index.d.ts +1 -1
- package/src/utils/index.js +7 -7
- package/src/utils/lang.d.ts +1 -1
- package/src/utils/lang.js +3 -3
- package/src/utils/literals.d.ts +1 -1
- package/src/utils/literals.js +15 -8
- package/src/utils/object.d.ts +1 -1
- package/src/utils/object.js +3 -3
- package/src/utils/partially-ordered-set.d.ts +2 -2
- package/src/utils/partially-ordered-set.js +12 -8
- package/src/utils/priority-queue.d.ts +1 -1
- package/src/utils/priority-queue.js +2 -2
- package/src/utils/strings.d.ts +7 -0
- package/src/utils/strings.js +12 -9
- package/src/utils/template.d.ts +1 -1
- package/src/utils/template.js +24 -30
- package/src/virtual-fs/host/alias.d.ts +1 -1
- package/src/virtual-fs/host/alias.js +7 -5
- package/src/virtual-fs/host/buffer.d.ts +1 -1
- package/src/virtual-fs/host/buffer.js +7 -0
- package/src/virtual-fs/host/create.d.ts +7 -0
- package/src/virtual-fs/host/create.js +3 -3
- package/src/virtual-fs/host/empty.d.ts +1 -1
- package/src/virtual-fs/host/empty.js +3 -3
- package/src/virtual-fs/host/index.d.ts +1 -1
- package/src/virtual-fs/host/index.js +1 -1
- package/src/virtual-fs/host/interface.d.ts +1 -1
- package/src/virtual-fs/host/interface.js +7 -0
- package/src/virtual-fs/host/memory.d.ts +1 -1
- package/src/virtual-fs/host/memory.js +32 -20
- package/src/virtual-fs/host/pattern.d.ts +1 -1
- package/src/virtual-fs/host/pattern.js +17 -8
- package/src/virtual-fs/host/record.d.ts +1 -1
- package/src/virtual-fs/host/record.js +45 -28
- package/src/virtual-fs/host/resolver.d.ts +1 -1
- package/src/virtual-fs/host/resolver.js +10 -1
- package/src/virtual-fs/host/safe.d.ts +1 -1
- package/src/virtual-fs/host/safe.js +3 -3
- package/src/virtual-fs/host/scoped.d.ts +1 -1
- package/src/virtual-fs/host/scoped.js +3 -3
- package/src/virtual-fs/host/sync.d.ts +1 -1
- package/src/virtual-fs/host/sync.js +12 -3
- package/src/virtual-fs/host/test.d.ts +1 -1
- package/src/virtual-fs/host/test.js +11 -2
- package/src/virtual-fs/index.d.ts +2 -2
- package/src/virtual-fs/index.js +8 -8
- package/src/virtual-fs/path.d.ts +1 -1
- package/src/virtual-fs/path.js +17 -8
- package/src/workspace/core.d.ts +7 -0
- package/src/workspace/core.js +3 -3
- package/src/workspace/definitions.d.ts +1 -1
- package/src/workspace/definitions.js +7 -0
- package/src/workspace/host.d.ts +1 -1
- package/src/workspace/host.js +3 -3
- package/src/workspace/index.d.ts +1 -1
- package/src/workspace/index.js +7 -7
- package/src/workspace/json/metadata.d.ts +1 -1
- package/src/workspace/json/metadata.js +8 -1
- package/src/workspace/json/reader.d.ts +7 -0
- package/src/workspace/json/reader.js +4 -4
- package/src/workspace/json/utilities.d.ts +1 -1
- package/src/workspace/json/utilities.js +12 -5
- package/src/workspace/json/writer.d.ts +7 -0
- package/src/workspace/json/writer.js +4 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Description
|
|
2
2
|
|
|
3
|
-
Jobs is the Angular DevKit subsystem for scheduling and running generic functions with clearly
|
|
3
|
+
Jobs is the Angular DevKit subsystem for scheduling and running generic functions with clearly
|
|
4
4
|
typed inputs and outputs. A `Job` instance is a function associated with metadata. You can
|
|
5
5
|
schedule a job, synchronize it with other jobs, and use it to schedule other jobs.
|
|
6
6
|
|
|
@@ -11,30 +11,33 @@ Jobs are lazy, cold, and guaranteed to execute exactly once when scheduled. Subs
|
|
|
11
11
|
returns messages from the point where the job is at.
|
|
12
12
|
|
|
13
13
|
## Argument, Input, Output and Channels
|
|
14
|
+
|
|
14
15
|
A job receives a single argument when scheduled and can also listen to an input channel. It can
|
|
15
|
-
emit multiple outputs, and can also provide multiple output channels that emit asynchronous JSON
|
|
16
|
-
messages, which can be typed.
|
|
16
|
+
emit multiple outputs, and can also provide multiple output channels that emit asynchronous JSON
|
|
17
|
+
messages, which can be typed.
|
|
17
18
|
|
|
18
|
-
The I/O model is like that of an executable, where the argument corresponds to arguments on the
|
|
19
|
+
The I/O model is like that of an executable, where the argument corresponds to arguments on the
|
|
19
20
|
command line, the input channel to STDIN, the output channel to STDOUT, and the channels
|
|
20
21
|
would be additional output streams.
|
|
21
22
|
|
|
22
23
|
## LifeCycle
|
|
24
|
+
|
|
23
25
|
A `Job` goes through multiple LifeCycle messages before its completion;
|
|
26
|
+
|
|
24
27
|
1. `JobState.Queued`. The job was queued and is waiting. This is the default state from the
|
|
25
|
-
|
|
28
|
+
scheduler.
|
|
26
29
|
1. `JobState.Ready`. The job's dependencies (see
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
1. `JobState.Started`. The argument has been validated, the job has been called and is running.
|
|
30
|
-
|
|
31
|
-
1. `JobState.Ended`. The job has ended and is done running. This is handled by the job itself (or
|
|
32
|
-
|
|
30
|
+
["Synchronizing and Dependencies"](#Dependencies)) are done running, the argument is
|
|
31
|
+
validated, and the job is ready to execute.
|
|
32
|
+
1. `JobState.Started`. The argument has been validated, the job has been called and is running.
|
|
33
|
+
This is handled by the job itself (or `createJobHandler()`).
|
|
34
|
+
1. `JobState.Ended`. The job has ended and is done running. This is handled by the job itself (or
|
|
35
|
+
`createJobHandler()`).
|
|
33
36
|
1. `JobState.Errored`. A unrecoverable error happened.
|
|
34
37
|
|
|
35
38
|
Each state (except `Queued`) corresponds to a `JobOutboundMessage` on the `outboundBus` observable
|
|
36
|
-
that triggers the state change. The `Scheduler` emits the `Ready` and `Errored` messages; the job
|
|
37
|
-
implementation should not emit them, and if it does they are filtered out. You can listen for
|
|
39
|
+
that triggers the state change. The `Scheduler` emits the `Ready` and `Errored` messages; the job
|
|
40
|
+
implementation should not emit them, and if it does they are filtered out. You can listen for
|
|
38
41
|
these messages or use the corresponding state member.
|
|
39
42
|
|
|
40
43
|
The job implementation should emit the `Start` and `End` messages when it is starting the job logic
|
|
@@ -43,51 +46,53 @@ itself. Only the first `Start` and `End` messages will be forwarded. Any more wi
|
|
|
43
46
|
The `Queued` state is set as the job is scheduled, so there is no need to listen for the message.
|
|
44
47
|
|
|
45
48
|
## `Job<OutputType>` Object
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
|
|
50
|
+
The `Job` object that is returned when you schedule a job provides access to the job's status and
|
|
51
|
+
utilities for tracking and modifying the job.
|
|
48
52
|
|
|
49
53
|
1. `id`. A unique symbol that can be used as a Map key.
|
|
50
54
|
1. `description`. The description of the job from the scheduler. See `JobDescription` object.
|
|
51
55
|
1. `argument`. The argument value that was used to start the job.
|
|
52
56
|
1. `input`. An `Observer` that can be used to send validated inputs to the job itself.
|
|
53
57
|
1. `output`. An `Observable<OutputType>` that filters out messages to get only the returned output
|
|
54
|
-
|
|
58
|
+
of a job.
|
|
55
59
|
1. `promise`. A promise that waits for the last output of a job. Returns the last value outputted
|
|
56
|
-
|
|
60
|
+
(or no value if there's no last value).
|
|
57
61
|
1. `state`. The current state of the job (see `LifeCycle`).
|
|
58
62
|
1. `channels`. A map of side channels the user can listen to as `Observable`.
|
|
59
63
|
1. `ping()`. A function that can be used to ping the job, receiving a `Promise` for when the ping
|
|
60
|
-
|
|
64
|
+
is answered.
|
|
61
65
|
1. `stop()`. Sends a `stop` input to the job, which suggests to stop the job. The job itself can
|
|
62
|
-
|
|
66
|
+
choose to ignore this message.
|
|
63
67
|
1. `inboundBus`. The raw input `Observer<JobInboundMessage>`. This can be used to send messages to
|
|
64
|
-
|
|
65
|
-
|
|
68
|
+
the `context.inboundBus` observable in the job. These are `JobInboundMessage` messages. See
|
|
69
|
+
["Communicating With Jobs"](#Communicating).
|
|
66
70
|
1. `outboundBus`. The raw output `Observable<JobOutput>`. This can be used to listen to messages
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
from the job. See ["Communicating With Jobs"](#Communicating).
|
|
72
|
+
|
|
69
73
|
## `JobHandlerContext<I, O>` Object
|
|
74
|
+
|
|
70
75
|
The `JobHandlerContext<>` is passed to the job handler code in addition to its argument. The
|
|
71
76
|
context contains the following members:
|
|
72
77
|
|
|
73
78
|
1. `description`. The description of the job. Its name and schemas.
|
|
74
79
|
1. `scheduler`. A `Scheduler<>` instance that can be used to create additional jobs.
|
|
75
80
|
1. `dependencies`. A generic list of other job instances that were run as dependencies when
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
scheduling this job. Their `id` is not guaranteed to match the `id` of the `Job<>` instance
|
|
82
|
+
itself (those `Job<>`s might just be proxies). The state of those `Job<>` is guaranteed to be
|
|
83
|
+
`JobState.Ended`, as `JobState.Errored` would have prevented this handler from running.
|
|
79
84
|
1. `inboundBus`. The raw input observable, complement of the `inboundBus` observer from the `Job<>`.
|
|
80
85
|
|
|
81
86
|
# Examples
|
|
82
87
|
|
|
83
|
-
An example of a job that adds all input together and return the output value. We use a
|
|
88
|
+
An example of a job that adds all input together and return the output value. We use a
|
|
84
89
|
simple synchronous job registry and a simple job scheduler.
|
|
85
90
|
|
|
86
91
|
```typescript
|
|
87
92
|
import { jobs } from '@angular-devkit/core';
|
|
88
93
|
|
|
89
|
-
const add = jobs.createJobHandle<number[], number>(
|
|
90
|
-
input
|
|
94
|
+
const add = jobs.createJobHandle<number[], number>((input) =>
|
|
95
|
+
input.reduce((total, curr) => total + curr, 0),
|
|
91
96
|
);
|
|
92
97
|
|
|
93
98
|
// Register the job in a SimpleJobRegistry. Different registries have different API.
|
|
@@ -99,8 +104,9 @@ registry.register(add, {
|
|
|
99
104
|
output: { type: 'number' },
|
|
100
105
|
});
|
|
101
106
|
|
|
102
|
-
scheduler
|
|
103
|
-
.
|
|
107
|
+
scheduler
|
|
108
|
+
.schedule('add', [1, 2, 3, 4])
|
|
109
|
+
.promise.then((output) => console.log('1 + 2 + 3 + 4 is ' + output));
|
|
104
110
|
```
|
|
105
111
|
|
|
106
112
|
# Creating Jobs
|
|
@@ -114,14 +120,15 @@ import { Observable } from 'rxjs';
|
|
|
114
120
|
import { jobs } from '@angular-devkit/core';
|
|
115
121
|
|
|
116
122
|
const argument = {
|
|
117
|
-
type: 'array',
|
|
123
|
+
type: 'array',
|
|
124
|
+
items: { type: 'number' },
|
|
118
125
|
};
|
|
119
126
|
const output = {
|
|
120
127
|
type: 'number',
|
|
121
128
|
};
|
|
122
129
|
|
|
123
130
|
export function add(argument: number[]): Observable<jobs.JobOutboundMessage<number>> {
|
|
124
|
-
return new Observable(o => {
|
|
131
|
+
return new Observable((o) => {
|
|
125
132
|
o.next({ kind: jobs.JobOutboundMessageKind.Start });
|
|
126
133
|
o.next({
|
|
127
134
|
kind: jobs.JobOutboundMessageKind.Output,
|
|
@@ -141,17 +148,16 @@ add.jobDescription = {
|
|
|
141
148
|
|
|
142
149
|
// Call the job with an array as argument, and log its output.
|
|
143
150
|
declare const scheduler: jobs.Scheduler;
|
|
144
|
-
scheduler.schedule('add', [1, 2, 3, 4])
|
|
145
|
-
.output.subscribe(x => console.log(x)); // Will output 10.
|
|
151
|
+
scheduler.schedule('add', [1, 2, 3, 4]).output.subscribe((x) => console.log(x)); // Will output 10.
|
|
146
152
|
```
|
|
147
153
|
|
|
148
|
-
This is a lot of boilerplate, so we made some helpers to improve readability and manage argument,
|
|
154
|
+
This is a lot of boilerplate, so we made some helpers to improve readability and manage argument,
|
|
149
155
|
input and output automatically:
|
|
150
156
|
|
|
151
157
|
```typescript
|
|
152
158
|
// Add is a JobHandler function, like the above.
|
|
153
|
-
export const add = jobs.createJobHandler<number[], number>(
|
|
154
|
-
argument
|
|
159
|
+
export const add = jobs.createJobHandler<number[], number>((argument) =>
|
|
160
|
+
argument.reduce((total, curr) => total + curr, 0),
|
|
155
161
|
);
|
|
156
162
|
|
|
157
163
|
// Schedule like above.
|
|
@@ -169,23 +175,24 @@ import { jobs } from '@angular-devkit/core';
|
|
|
169
175
|
// Show progress with each count in a separate output channel. Output "more" in a channel.
|
|
170
176
|
export const count = jobs.createJobHandler<number, number>(
|
|
171
177
|
// Receive a context that contains additional methods to create channels.
|
|
172
|
-
(argument: number, { createChannel }) =>
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
178
|
+
(argument: number, { createChannel }) =>
|
|
179
|
+
new Observable<number>((o) => {
|
|
180
|
+
const side = createChannel('side', { type: 'string', const: 'more' });
|
|
181
|
+
const progress = createChannel('progress', { type: 'number' });
|
|
182
|
+
let i = 0;
|
|
183
|
+
function doCount() {
|
|
184
|
+
o.next(i++);
|
|
185
|
+
progress.next(i / argument);
|
|
186
|
+
side.next('more');
|
|
187
|
+
|
|
188
|
+
if (i < argument) {
|
|
189
|
+
setTimeout(doCount, 100);
|
|
190
|
+
} else {
|
|
191
|
+
o.complete();
|
|
192
|
+
}
|
|
185
193
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}),
|
|
194
|
+
setTimeout(doCount, 100);
|
|
195
|
+
}),
|
|
189
196
|
{
|
|
190
197
|
argument: { type: 'number' },
|
|
191
198
|
output: { type: 'number' },
|
|
@@ -196,63 +203,69 @@ export const count = jobs.createJobHandler<number, number>(
|
|
|
196
203
|
declare const scheduler: jobs.Scheduler;
|
|
197
204
|
|
|
198
205
|
const job = scheduler.schedule('count', 0);
|
|
199
|
-
job.getChannel('side').subscribe(x => console.log(x));
|
|
206
|
+
job.getChannel('side').subscribe((x) => console.log(x));
|
|
200
207
|
// You can type a channel too. Messages will be filtered out.
|
|
201
|
-
job
|
|
208
|
+
job
|
|
209
|
+
.getChannel<number>('progress', { type: 'number' })
|
|
210
|
+
.subscribe((x) => console.log(x));
|
|
202
211
|
```
|
|
203
212
|
|
|
204
213
|
## <a name="Communicating"></a>Communicating With Jobs
|
|
205
|
-
|
|
214
|
+
|
|
215
|
+
Jobs can be started and updated in a separate process or thread, and as such communication with a
|
|
206
216
|
job should avoid using global objects (which might not be shared). The jobs API and schedulers
|
|
207
|
-
provide 2 communication streams (one for input and the other for output), named `inboundBus` and
|
|
217
|
+
provide 2 communication streams (one for input and the other for output), named `inboundBus` and
|
|
208
218
|
`outboundBus`.
|
|
209
219
|
|
|
210
220
|
### Raw Input Stream
|
|
221
|
+
|
|
211
222
|
The `schedule()` function returns a `Job<>` interface that contains a `inboundBus` member of type
|
|
212
223
|
`Observer<JobInboundMessage>`. All messages sent _to_ the job goes through this stream. The `kind`
|
|
213
224
|
member of the `JobInboundMessage` interface dictates what kind of message it is sending:
|
|
214
225
|
|
|
215
226
|
1. `JobInboundMessageKind.Ping`. A simple message that should be answered with
|
|
216
|
-
|
|
217
|
-
|
|
227
|
+
`JobOutboundMessageKind.Pong` when the job is responsive. The `id` field of the message should
|
|
228
|
+
be used when returning `Pong`.
|
|
218
229
|
1. `JobInboundMessageKind.Stop`. The job should be stopped. This is used when
|
|
219
|
-
|
|
220
|
-
|
|
230
|
+
cancelling/unsubscribing from the `output` (or by calling `stop()`). Any inputs or outputs
|
|
231
|
+
after this message will be ignored.
|
|
221
232
|
1. `JobInboundMessageKind.Input` is used when sending inputs to a job. These correspond to the
|
|
222
|
-
|
|
223
|
-
|
|
233
|
+
`next` methods of an `Observer` and are reported to the job through its `context.input`
|
|
234
|
+
Observable. There is no way to communicate an error to the job.
|
|
224
235
|
|
|
225
236
|
Using the `createJobHandler()` helper, all those messages are automatically handled by the
|
|
226
237
|
boilerplate code. If you need direct access to raw inputs, you should subscribe to the
|
|
227
238
|
`context.inboundBus` Observable.
|
|
228
239
|
|
|
229
240
|
### Raw Output Stream
|
|
241
|
+
|
|
230
242
|
The `Job<>` interface also contains a `outboundBus` member (of type
|
|
231
243
|
`Observable<JobOutboundMessage<O>>` where `O` is the typed output of the job) which is the output
|
|
232
244
|
complement of `inboundBus`. All messages sent _from_ the job goes through this stream. The `kind`
|
|
233
245
|
member of the `JobOutboundMessage<O>` interface dictates what kind of message it is sending:
|
|
234
246
|
|
|
235
247
|
1. `JobOutboundMessageKind.Create`. The `Job<>` was created, its dependencies are done, and the
|
|
236
|
-
|
|
248
|
+
library is validating Argument and calling the internal job code.
|
|
237
249
|
1. `JobOutboundMessageKind.Start`. The job code itself should send that message when started.
|
|
238
|
-
|
|
250
|
+
`createJobHandler()` will do it automatically.
|
|
239
251
|
1. `JobOutboundMessageKind.End`. The job has ended. This is done by the job itself and should always
|
|
240
|
-
|
|
241
|
-
|
|
252
|
+
be sent when completed. The scheduler will listen to this message to set the state and unblock
|
|
253
|
+
dependent jobs. `createJobHandler()` automatically send this message.
|
|
242
254
|
1. `JobOutboundMessageKind.Pong`. The job should answer a `JobInboundMessageKind.Ping` message with
|
|
243
|
-
|
|
255
|
+
this. Automatically done by `createJobHandler()`.
|
|
244
256
|
1. `JobOutboundMessageKind.Output`. An `Output` has been generated by the job.
|
|
245
257
|
1. `JobOutboundMessageKind.ChannelMessage`, `JobOutboundMessageKind.ChannelError` and
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
258
|
+
`JobOutboundMessageKind.ChannelComplete` are used for output channels. These correspond to the
|
|
259
|
+
`next`, `error` and `complete` methods of an `Observer` and are available to the callee through
|
|
260
|
+
the `job.channels` map of Observable.
|
|
249
261
|
|
|
250
262
|
Those messages can be accessed directly through the `job.outboundBus` member. The job itself should
|
|
251
263
|
return an `Observable<JobOutboundMessage<O>>`. The `createJobHandler()` helper handles most of use
|
|
252
264
|
cases of this and makes it easier for jobs to handle this.
|
|
253
265
|
|
|
254
266
|
## Job Dispatchers
|
|
255
|
-
|
|
267
|
+
|
|
268
|
+
Dispatchers are a helper that redirect to different jobs given conditions. To create a job
|
|
256
269
|
dispatcher, use the `createDispatcher()` function:
|
|
257
270
|
|
|
258
271
|
```typescript
|
|
@@ -282,12 +295,13 @@ dispatcher.addConditionalDelegate(() => userWantsYarn, yarnInstall.name);
|
|
|
282
295
|
```
|
|
283
296
|
|
|
284
297
|
## Execution Strategy
|
|
285
|
-
|
|
298
|
+
|
|
299
|
+
Jobs are always run in parallel and will always start, but many helper functions are provided
|
|
286
300
|
when creating a job to help you control the execution strategy;
|
|
287
301
|
|
|
288
302
|
1. `serialize()`. Multiple runs of this job will be queued with each others.
|
|
289
|
-
1. `memoize(replayMessages = false)` will create a job, or reuse the same job
|
|
290
|
-
matching. If the inputs don't match, a new job will be started and its outputs will be stored.
|
|
303
|
+
1. `memoize(replayMessages = false)` will create a job, or reuse the same job when inputs are
|
|
304
|
+
matching. If the inputs don't match, a new job will be started and its outputs will be stored.
|
|
291
305
|
|
|
292
306
|
These strategies can be used when creating the job:
|
|
293
307
|
|
|
@@ -295,13 +309,13 @@ These strategies can be used when creating the job:
|
|
|
295
309
|
// Same input and output as above.
|
|
296
310
|
|
|
297
311
|
export const add = jobs.strategy.memoize()(
|
|
298
|
-
jobs.createJobHandler<number[], number>(
|
|
299
|
-
|
|
312
|
+
jobs.createJobHandler<number[], number>((argument) =>
|
|
313
|
+
argument.reduce((total, curr) => total + curr, 0),
|
|
300
314
|
),
|
|
301
315
|
);
|
|
302
316
|
```
|
|
303
317
|
|
|
304
|
-
Strategies can be reused to synchronize between jobs. For example, given jobs `jobA` and `jobB`,
|
|
318
|
+
Strategies can be reused to synchronize between jobs. For example, given jobs `jobA` and `jobB`,
|
|
305
319
|
you can reuse the strategy to serialize both jobs together;
|
|
306
320
|
|
|
307
321
|
```typescript
|
|
@@ -310,8 +324,8 @@ const jobA = strategy(jobs.createJobHandler(...));
|
|
|
310
324
|
const jobB = strategy(jobs.createJobHandler(...));
|
|
311
325
|
```
|
|
312
326
|
|
|
313
|
-
Even further, we can have package A and package B run in serialization, and B and C also be
|
|
314
|
-
serialized. Running A and C will run in parallel, while running B will wait for both A and C
|
|
327
|
+
Even further, we can have package A and package B run in serialization, and B and C also be
|
|
328
|
+
serialized. Running A and C will run in parallel, while running B will wait for both A and C
|
|
315
329
|
to finish.
|
|
316
330
|
|
|
317
331
|
```typescript
|
|
@@ -323,6 +337,7 @@ const jobC = strategy2(jobs.createJobHandler(...));
|
|
|
323
337
|
```
|
|
324
338
|
|
|
325
339
|
# Scheduling Jobs
|
|
340
|
+
|
|
326
341
|
Jobs can be scheduled using a `Scheduler` interface, which contains a `schedule()` method:
|
|
327
342
|
|
|
328
343
|
```typescript
|
|
@@ -342,7 +357,7 @@ interface Scheduler {
|
|
|
342
357
|
}
|
|
343
358
|
```
|
|
344
359
|
|
|
345
|
-
The scheduler also has a `getDescription()` method to get a `JobDescription` object for a certain
|
|
360
|
+
The scheduler also has a `getDescription()` method to get a `JobDescription` object for a certain
|
|
346
361
|
name; that description contains schemas for the argument, input, output, and other channels:
|
|
347
362
|
|
|
348
363
|
```typescript
|
|
@@ -354,7 +369,7 @@ interface Scheduler {
|
|
|
354
369
|
* @returns A description, or null if the job cannot be scheduled.
|
|
355
370
|
*/
|
|
356
371
|
getDescription(name: JobName): JobDescription | null;
|
|
357
|
-
|
|
372
|
+
|
|
358
373
|
/**
|
|
359
374
|
* Returns true if the job name has been registered.
|
|
360
375
|
* @param name The name of the job.
|
|
@@ -364,8 +379,8 @@ interface Scheduler {
|
|
|
364
379
|
}
|
|
365
380
|
```
|
|
366
381
|
|
|
367
|
-
Finally, the scheduler interface has a `pause()` method to stop scheduling. This will queue all
|
|
368
|
-
jobs and wait for the unpause function to be called before unblocking all the jobs scheduled.
|
|
382
|
+
Finally, the scheduler interface has a `pause()` method to stop scheduling. This will queue all
|
|
383
|
+
jobs and wait for the unpause function to be called before unblocking all the jobs scheduled.
|
|
369
384
|
This does not affect already running jobs.
|
|
370
385
|
|
|
371
386
|
```typescript
|
|
@@ -387,7 +402,8 @@ interface Scheduler {
|
|
|
387
402
|
```
|
|
388
403
|
|
|
389
404
|
## <a name="Dependencies"></a>Synchronizing and Dependencies
|
|
390
|
-
|
|
405
|
+
|
|
406
|
+
When scheduling jobs, it is often necessary to run jobs after certain other jobs are finished.
|
|
391
407
|
This is done through the `dependencies` options in the `schedule()` method.
|
|
392
408
|
|
|
393
409
|
These jobs will also be passed to the job being scheduled, through its context. This can be
|
|
@@ -397,34 +413,39 @@ An example of this would be a compiler that needs to know the output directory o
|
|
|
397
413
|
before it, in a tool chain.
|
|
398
414
|
|
|
399
415
|
### Dependencies
|
|
416
|
+
|
|
400
417
|
When scheduling jobs, the user can add a `dependencies` field to the scheduling options. The
|
|
401
|
-
scheduler will wait for those dependencies to finish before running the job, and pass those jobs
|
|
418
|
+
scheduler will wait for those dependencies to finish before running the job, and pass those jobs
|
|
402
419
|
in the context of the job.
|
|
403
420
|
|
|
404
421
|
### Accessing Dependencies
|
|
422
|
+
|
|
405
423
|
Jobs are called with a `JobHandlerContext` as a second argument, which contains a
|
|
406
|
-
`dependencies: Job<JsonValue>[]` member which contains all dependencies that were used when
|
|
424
|
+
`dependencies: Job<JsonValue>[]` member which contains all dependencies that were used when
|
|
407
425
|
scheduling the job. Those aren't fully typed as they are determined by the user, and not the job
|
|
408
426
|
itself. They also can contain jobs that are not finished, and the job should use the `state`
|
|
409
427
|
member of the job itself before trying to access its content.
|
|
410
428
|
|
|
411
429
|
### Scheduler Sub Jobs
|
|
430
|
+
|
|
412
431
|
The `JobHandlerContext` also contains a `scheduler` member which can be used to schedule jobs
|
|
413
432
|
using the same scheduler that was used for the job. This allows jobs to call other jobs
|
|
414
433
|
and wait for them to end.
|
|
415
434
|
|
|
416
435
|
## Available Schedulers
|
|
436
|
+
|
|
417
437
|
The Core Angular DevKit library provides 2 implementations for the `Scheduler` interface:
|
|
418
438
|
|
|
419
439
|
## SimpleJobRegistry
|
|
440
|
+
|
|
420
441
|
Available in the jobs namespace. A registry that accept job registration, and can also schedule
|
|
421
442
|
jobs.
|
|
422
443
|
|
|
423
444
|
```typescript
|
|
424
445
|
import { jobs } from '@angular-devkit/core';
|
|
425
446
|
|
|
426
|
-
const add = jobs.createJobHandler<number[], number>(
|
|
427
|
-
argument
|
|
447
|
+
const add = jobs.createJobHandler<number[], number>((argument) =>
|
|
448
|
+
argument.reduce((total, curr) => total + curr, 0),
|
|
428
449
|
);
|
|
429
450
|
|
|
430
451
|
// Register the job in a SimpleJobRegistry. Different registries have different API.
|
|
@@ -441,6 +462,7 @@ scheduler.schedule('add', [1, 2, 3, 4]);
|
|
|
441
462
|
```
|
|
442
463
|
|
|
443
464
|
## NodeModuleJobRegistry
|
|
465
|
+
|
|
444
466
|
Available through `@angular-devkit/core/node`.
|
|
445
467
|
|
|
446
468
|
A scheduler that loads jobs using their node package names. These jobs need to use the
|
|
@@ -456,34 +478,33 @@ scheduler.schedule('some-node-package#someExport', 'input');
|
|
|
456
478
|
# Gotchas
|
|
457
479
|
|
|
458
480
|
1. Deadlocking Dependencies
|
|
459
|
-
It is impossible to add dependencies to an already running job, but it is entirely possible to
|
|
481
|
+
It is impossible to add dependencies to an already running job, but it is entirely possible to
|
|
460
482
|
get locked between jobs. Be aware of your own dependencies.
|
|
461
483
|
|
|
462
484
|
1. Using `job.promise`
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
485
|
+
`job.promise` waits for the job to ends. Don't rely on it unless you know the job is not
|
|
486
|
+
watching and running for a long time. If you aren't sure, use
|
|
487
|
+
`job.output.pipe(first()).toPromise()` instead which will return the first next output,
|
|
488
|
+
regardless of whether the job watches and rerun or not.
|
|
468
489
|
|
|
469
490
|
# FAQ
|
|
470
491
|
|
|
471
492
|
1. Laziness
|
|
472
|
-
|
|
493
|
+
A job is lazy until executed, but its messages will be replayed when resubscribed.
|
|
473
494
|
|
|
474
495
|
1. Serialize Strategy vs Dependencies
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
496
|
+
Strategies are functions that transform the execution of a job, and can be used when
|
|
497
|
+
declaring the job, or registering it. Dependencies, on the other hand, are listed when
|
|
498
|
+
scheduling a job to order jobs during scheduling.
|
|
499
|
+
|
|
500
|
+
A job has no control over the way it's scheduled, and its dependencies. It can, however,
|
|
501
|
+
declare that it shouldn't run at the same time as itself. Alternatively, a user could
|
|
502
|
+
schedule a job twice and imply that the second run should wait for the first to finish. In
|
|
503
|
+
practice, this would be equivalent to having the job be serialized, but the important detail
|
|
504
|
+
is in _whom_ is defining the rules; using the `serialize()` strategy, the job implementation
|
|
505
|
+
is, while when using dependencies, the user is.
|
|
506
|
+
|
|
507
|
+
The user does not need to know how to job needs to synchronize with itself, and the job does
|
|
508
|
+
not need to know how it synchronizes with other jobs that it doesn't know about. That's part
|
|
509
|
+
of the strength of this system as every job can be developed in a vacuum, only caring about
|
|
510
|
+
its contracts (argument, input and output) and its own synchronization.
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright Google LLC All Rights Reserved.
|
|
5
|
+
*
|
|
6
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
7
|
+
* found in the LICENSE file at https://angular.io/license
|
|
8
|
+
*/
|
|
2
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
10
|
exports.isJobHandler = exports.JobState = exports.JobOutboundMessageKind = exports.JobInboundMessageKind = void 0;
|
|
4
11
|
/**
|
|
@@ -61,8 +68,6 @@ var JobState;
|
|
|
61
68
|
})(JobState = exports.JobState || (exports.JobState = {}));
|
|
62
69
|
function isJobHandler(value) {
|
|
63
70
|
const job = value;
|
|
64
|
-
return typeof job == 'function'
|
|
65
|
-
&& typeof job.jobDescription == 'object'
|
|
66
|
-
&& job.jobDescription !== null;
|
|
71
|
+
return (typeof job == 'function' && typeof job.jobDescription == 'object' && job.jobDescription !== null);
|
|
67
72
|
}
|
|
68
73
|
exports.isJobHandler = isJobHandler;
|