Jobs is the Angular Dev\+Kit subsystem for scheduling and running generic functions with clearly typed inputs and outputs. A {\ttfamily Job} instance is a function associated with metadata. You can schedule a job, synchronize it with other jobs, and use it to schedule other jobs.

The whole API is serializable, allowing you to use a Node Stream or message channel to communicate between the job and the job scheduler.

Jobs are lazy, cold, and guaranteed to execute exactly once when scheduled. Subscribing to a job returns messages from the point where the job is at.\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1937}{}\doxysection{Argument, Input, Output and Channels}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1937}
A job receives a single argument when scheduled and can also listen to an input channel. It can emit multiple outputs, and can also provide multiple output channels that emit asynchronous JSON messages, which can be typed.

The I/O model is like that of an executable, where the argument corresponds to arguments on the command line, the input channel to STDIN, the output channel to STDOUT, and the channels would be additional output streams.\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1938}{}\doxysection{Life\+Cycle}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1938}
A {\ttfamily Job} goes through multiple Life\+Cycle messages before its completion;
\begin{DoxyEnumerate}
\item {\ttfamily Job\+State.\+Queued}. The job was queued and is waiting. This is the default state from the scheduler.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily Job\+State.\+Ready}. The job\textquotesingle{}s dependencies (see \href{\#Dependencies}{\texttt{ \char`\"{}\+Synchronizing and Dependencies\char`\"{}}}) are done running, the argument is validated, and the job is ready to execute.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily Job\+State.\+Started}. The argument has been validated, the job has been called and is running. This is handled by the job itself (or {\ttfamily create\+Job\+Handler()}).
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily Job\+State.\+Ended}. The job has ended and is done running. This is handled by the job itself (or {\ttfamily create\+Job\+Handler()}).
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily Job\+State.\+Errored}. A unrecoverable error happened.
\end{DoxyEnumerate}

Each state (except {\ttfamily Queued}) corresponds to a {\ttfamily Job\+Outbound\+Message} on the {\ttfamily outbound\+Bus} observable that triggers the state change. The {\ttfamily Scheduler} emits the {\ttfamily Ready} and {\ttfamily Errored} messages; the job implementation should not emit them, and if it does they are filtered out. You can listen for these messages or use the corresponding state member.

The job implementation should emit the {\ttfamily Start} and {\ttfamily End} messages when it is starting the job logic itself. Only the first {\ttfamily Start} and {\ttfamily End} messages will be forwarded. Any more will be filtered out.

The {\ttfamily Queued} state is set as the job is scheduled, so there is no need to listen for the message.\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1939}{}\doxysection{$<$tt$>$\+Job$<$\+Output\+Type$>$$<$/tt$>$ Object}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1939}
The {\ttfamily Job} object that is returned when you schedule a job provides access to the job\textquotesingle{}s status and utilities for tracking and modifying the job.


\begin{DoxyEnumerate}
\item {\ttfamily id}. A unique symbol that can be used as a Map key.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily description}. The description of the job from the scheduler. See {\ttfamily Job\+Description} object.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily argument}. The argument value that was used to start the job.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily input}. An {\ttfamily Observer} that can be used to send validated inputs to the job itself.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily output}. An {\ttfamily Observable$<$Output\+Type$>$} that filters out messages to get only the returned output of a job.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily promise}. A promise that waits for the last output of a job. Returns the last value outputted (or no value if there\textquotesingle{}s no last value).
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily state}. The current state of the job (see {\ttfamily Life\+Cycle}).
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily channels}. A map of side channels the user can listen to as {\ttfamily Observable}.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily ping()}. A function that can be used to ping the job, receiving a {\ttfamily Promise} for when the ping is answered.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily stop()}. Sends a {\ttfamily stop} input to the job, which suggests to stop the job. The job itself can choose to ignore this message.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily inbound\+Bus}. The raw input {\ttfamily Observer$<$Job\+Inbound\+Message$>$}. This can be used to send messages to the {\ttfamily context.\+inbound\+Bus} observable in the job. These are {\ttfamily Job\+Inbound\+Message} messages. See \href{\#Communicating}{\texttt{ \char`\"{}\+Communicating With Jobs\char`\"{}}}.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily outbound\+Bus}. The raw output {\ttfamily Observable$<$Job\+Output$>$}. This can be used to listen to messages from the job. See \href{\#Communicating}{\texttt{ \char`\"{}\+Communicating With Jobs\char`\"{}}}.
\end{DoxyEnumerate}\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1940}{}\doxysection{$<$tt$>$\+Job\+Handler\+Context$<$\+I, O$>$$<$/tt$>$ Object}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1940}
The {\ttfamily Job\+Handler\+Context$<$$>$} is passed to the job handler code in addition to its argument. The context contains the following members\+:


\begin{DoxyEnumerate}
\item {\ttfamily description}. The description of the job. Its name and schemas.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily scheduler}. A {\ttfamily Scheduler$<$$>$} instance that can be used to create additional jobs.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily dependencies}. A generic list of other job instances that were run as dependencies when scheduling this job. Their {\ttfamily id} is not guaranteed to match the {\ttfamily id} of the {\ttfamily Job$<$$>$} instance itself (those {\ttfamily Job$<$$>$}s might just be proxies). The state of those {\ttfamily Job$<$$>$} is guaranteed to be {\ttfamily Job\+State.\+Ended}, as {\ttfamily Job\+State.\+Errored} would have prevented this handler from running.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily inbound\+Bus}. The raw input observable, complement of the {\ttfamily inbound\+Bus} observer from the {\ttfamily Job$<$$>$}.
\end{DoxyEnumerate}\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1941}{}\doxysection{Examples}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1941}
An example of a job that adds all input together and return the output value. We use a simple synchronous job registry and a simple job scheduler.


\begin{DoxyCode}{0}
\DoxyCodeLine{import \{ jobs \} from '@angular-\/devkit/core';}
\DoxyCodeLine{}
\DoxyCodeLine{const add = jobs.createJobHandle<number[], number>(}
\DoxyCodeLine{  input => input.reduce((total, curr) => total + curr, 0),}
\DoxyCodeLine{);}
\DoxyCodeLine{}
\DoxyCodeLine{// Register the job in a SimpleJobRegistry. Different registries have different API.}
\DoxyCodeLine{const registry = new jobs.SimpleJobRegistry();}
\DoxyCodeLine{const scheduler = new jobs.SimpleScheduler(registry);}
\DoxyCodeLine{registry.register(add, \{}
\DoxyCodeLine{  name: 'add',}
\DoxyCodeLine{  input: \{ type: 'array', items: \{ type: 'number' \} \},}
\DoxyCodeLine{  output: \{ type: 'number' \},}
\DoxyCodeLine{\});}
\DoxyCodeLine{}
\DoxyCodeLine{scheduler.schedule('add', [1, 2, 3, 4]).promise}
\DoxyCodeLine{  .then(output => console.log('1 + 2 + 3 + 4 is ' + output)); }

\end{DoxyCode}
\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1942}{}\doxysection{Creating Jobs}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1942}
A job is at its core a function with a description object attached to it. The description object stores the JSON schemas used to validate the types of the argument passed in, the input and output values. By default, a job accepts and can output any JSON object.


\begin{DoxyCode}{0}
\DoxyCodeLine{import \{ Observable \} from 'rxjs';}
\DoxyCodeLine{import \{ jobs \} from '@angular-\/devkit/core';}
\DoxyCodeLine{}
\DoxyCodeLine{const argument = \{}
\DoxyCodeLine{  type: 'array', items: \{ type: 'number' \},}
\DoxyCodeLine{\};}
\DoxyCodeLine{const output = \{}
\DoxyCodeLine{  type: 'number',}
\DoxyCodeLine{\};}
\DoxyCodeLine{}
\DoxyCodeLine{export function add(argument: number[]): Observable<jobs.JobOutboundMessage<number>> \{}
\DoxyCodeLine{  return new Observable(o => \{}
\DoxyCodeLine{    o.next(\{ kind: jobs.JobOutboundMessageKind.Start \});}
\DoxyCodeLine{    o.next(\{}
\DoxyCodeLine{      kind: jobs.JobOutboundMessageKind.Output,}
\DoxyCodeLine{      output: argument.reduce((total, curr) => total + curr, 0),}
\DoxyCodeLine{    \});}
\DoxyCodeLine{    o.next(\{ kind: jobs.JobOutboundMessageKind.End \});}
\DoxyCodeLine{    o.complete();}
\DoxyCodeLine{  \});}
\DoxyCodeLine{\}}
\DoxyCodeLine{}
\DoxyCodeLine{// Add a property to `add` to make it officially a JobHandler. The Job system does not recognize}
\DoxyCodeLine{// any function as a JobHandler.}
\DoxyCodeLine{add.jobDescription = \{}
\DoxyCodeLine{  argument: argument,}
\DoxyCodeLine{  output: output,}
\DoxyCodeLine{\};}
\DoxyCodeLine{}
\DoxyCodeLine{// Call the job with an array as argument, and log its output.}
\DoxyCodeLine{declare const scheduler: jobs.Scheduler;}
\DoxyCodeLine{scheduler.schedule('add', [1, 2, 3, 4])}
\DoxyCodeLine{    .output.subscribe(x => console.log(x));  // Will output 10. }

\end{DoxyCode}


This is a lot of boilerplate, so we made some helpers to improve readability and manage argument, input and output automatically\+:


\begin{DoxyCode}{0}
\DoxyCodeLine{// Add is a JobHandler function, like the above.}
\DoxyCodeLine{export const add = jobs.createJobHandler<number[], number>(}
\DoxyCodeLine{  argument => argument.reduce((total, curr) => total + curr, 0),}
\DoxyCodeLine{);}
\DoxyCodeLine{}
\DoxyCodeLine{// Schedule like above. }

\end{DoxyCode}


You can also return a Promise or an Observable, as jobs are asynchronous. This helper will set start and end messages appropriately. It will also manage channels automatically (see below).

A more complex job can be declared like this\+:


\begin{DoxyCode}{0}
\DoxyCodeLine{import \{ Observable \} from 'rxjs';}
\DoxyCodeLine{import \{ jobs \} from '@angular-\/devkit/core';}
\DoxyCodeLine{}
\DoxyCodeLine{// Show progress with each count in a separate output channel. Output "{}more"{} in a channel.}
\DoxyCodeLine{export const count = jobs.createJobHandler<number, number>(}
\DoxyCodeLine{  // Receive a context that contains additional methods to create channels.}
\DoxyCodeLine{  (argument: number, \{ createChannel \}) => new Observable<number>(o => \{}
\DoxyCodeLine{    const side = createChannel('side', \{ type: 'string', const: 'more' \});}
\DoxyCodeLine{    const progress = createChannel('progress', \{ type: 'number' \});}
\DoxyCodeLine{    let i = 0;}
\DoxyCodeLine{    function doCount() \{}
\DoxyCodeLine{      o.next(i++);}
\DoxyCodeLine{      progress.next(i / argument);}
\DoxyCodeLine{      side.next('more');}
\DoxyCodeLine{  }
\DoxyCodeLine{      if (i < argument) \{}
\DoxyCodeLine{        setTimeout(doCount, 100);}
\DoxyCodeLine{      \} else \{}
\DoxyCodeLine{        o.complete();}
\DoxyCodeLine{      \}}
\DoxyCodeLine{    \}}
\DoxyCodeLine{    setTimeout(doCount, 100);}
\DoxyCodeLine{  \}),}
\DoxyCodeLine{  \{}
\DoxyCodeLine{    argument: \{ type: 'number' \},}
\DoxyCodeLine{    output: \{ type: 'number' \},}
\DoxyCodeLine{  \},}
\DoxyCodeLine{);}
\DoxyCodeLine{}
\DoxyCodeLine{// Get a hold of a scheduler that refers to the job above.}
\DoxyCodeLine{declare const scheduler: jobs.Scheduler;}
\DoxyCodeLine{}
\DoxyCodeLine{const job = scheduler.schedule('count', 0);}
\DoxyCodeLine{job.getChannel('side').subscribe(x => console.log(x));}
\DoxyCodeLine{// You can type a channel too. Messages will be filtered out.}
\DoxyCodeLine{job.getChannel<number>('progress', \{ type: 'number' \}).subscribe(x => console.log(x)); }

\end{DoxyCode}
\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1943}{}\doxysubsection{$<$a name=\char`\"{}\+Communicating\char`\"{}$>$$<$/a$>$\+Communicating With Jobs}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1943}
Jobs can be started and updated in a separate process or thread, and as such communication with a job should avoid using global objects (which might not be shared). The jobs API and schedulers provide 2 communication streams (one for input and the other for output), named {\ttfamily inbound\+Bus} and {\ttfamily outbound\+Bus}.\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1944}{}\doxysubsubsection{Raw Input Stream}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1944}
The {\ttfamily schedule()} function returns a {\ttfamily Job$<$$>$} interface that contains a {\ttfamily inbound\+Bus} member of type {\ttfamily Observer$<$Job\+Inbound\+Message$>$}. All messages sent {\itshape to} the job goes through this stream. The {\ttfamily kind} member of the {\ttfamily Job\+Inbound\+Message} interface dictates what kind of message it is sending\+:


\begin{DoxyEnumerate}
\item {\ttfamily Job\+Inbound\+Message\+Kind.\+Ping}. A simple message that should be answered with {\ttfamily Job\+Outbound\+Message\+Kind.\+Pong} when the job is responsive. The {\ttfamily id} field of the message should be used when returning {\ttfamily Pong}.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily Job\+Inbound\+Message\+Kind.\+Stop}. The job should be stopped. This is used when cancelling/unsubscribing from the {\ttfamily output} (or by calling {\ttfamily stop()}). Any inputs or outputs after this message will be ignored.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily Job\+Inbound\+Message\+Kind.\+Input} is used when sending inputs to a job. These correspond to the {\ttfamily next} methods of an {\ttfamily Observer} and are reported to the job through its {\ttfamily context.\+input} Observable. There is no way to communicate an error to the job.
\end{DoxyEnumerate}

Using the {\ttfamily create\+Job\+Handler()} helper, all those messages are automatically handled by the boilerplate code. If you need direct access to raw inputs, you should subscribe to the {\ttfamily context.\+inbound\+Bus} Observable.\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1945}{}\doxysubsubsection{Raw Output Stream}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1945}
The {\ttfamily Job$<$$>$} interface also contains a {\ttfamily outbound\+Bus} member (of type {\ttfamily Observable$<$Job\+Outbound\+Message$<$O$>$$>$} where {\ttfamily O} is the typed output of the job) which is the output complement of {\ttfamily inbound\+Bus}. All messages sent {\itshape from} the job goes through this stream. The {\ttfamily kind} member of the {\ttfamily Job\+Outbound\+Message$<$O$>$} interface dictates what kind of message it is sending\+:


\begin{DoxyEnumerate}
\item {\ttfamily Job\+Outbound\+Message\+Kind.\+Create}. The {\ttfamily Job$<$$>$} was created, its dependencies are done, and the library is validating Argument and calling the internal job code.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily Job\+Outbound\+Message\+Kind.\+Start}. The job code itself should send that message when started. {\ttfamily create\+Job\+Handler()} will do it automatically.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily Job\+Outbound\+Message\+Kind.\+End}. The job has ended. This is done by the job itself and should always be sent when completed. The scheduler will listen to this message to set the state and unblock dependent jobs. {\ttfamily create\+Job\+Handler()} automatically send this message.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily Job\+Outbound\+Message\+Kind.\+Pong}. The job should answer a {\ttfamily Job\+Inbound\+Message\+Kind.\+Ping} message with this. Automatically done by {\ttfamily create\+Job\+Handler()}.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily Job\+Outbound\+Message\+Kind.\+Output}. An {\ttfamily Output} has been generated by the job.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily Job\+Outbound\+Message\+Kind.\+Channel\+Message}, {\ttfamily Job\+Outbound\+Message\+Kind.\+Channel\+Error} and {\ttfamily Job\+Outbound\+Message\+Kind.\+Channel\+Complete} are used for output channels. These correspond to the {\ttfamily next}, {\ttfamily error} and {\ttfamily complete} methods of an {\ttfamily Observer} and are available to the callee through the {\ttfamily job.\+channels} map of Observable.
\end{DoxyEnumerate}

Those messages can be accessed directly through the {\ttfamily job.\+outbound\+Bus} member. The job itself should return an {\ttfamily Observable$<$Job\+Outbound\+Message$<$O$>$$>$}. The {\ttfamily create\+Job\+Handler()} helper handles most of use cases of this and makes it easier for jobs to handle this.\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1946}{}\doxysubsection{Job Dispatchers}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1946}
Dispatchers are a helper that redirect to different jobs given conditions. To create a job dispatcher, use the {\ttfamily create\+Dispatcher()} function\+:


\begin{DoxyCode}{0}
\DoxyCodeLine{import \{ jobs \} from '@angular-\/devkit/core';}
\DoxyCodeLine{}
\DoxyCodeLine{// A dispatcher that installs node modules given a user's preference.}
\DoxyCodeLine{const dispatcher = jobs.createDispatcher(\{}
\DoxyCodeLine{  name: 'node-\/install',}
\DoxyCodeLine{  argument: \{ properties: \{ moduleName: \{ type: 'string' \} \} \},}
\DoxyCodeLine{  output: \{ type: 'boolean' \},}
\DoxyCodeLine{\});}
\DoxyCodeLine{}
\DoxyCodeLine{const npmInstall = jobs.createJobHandler(/* ... */, \{ name: 'npm-\/install' \});}
\DoxyCodeLine{const yarnInstall = jobs.createJobHandler(/* ... */, \{ name: 'yarn-\/install' \});}
\DoxyCodeLine{const pnpmInstall = jobs.createJobHandler(/* ... */, \{ name: 'pnpm-\/install' \});}
\DoxyCodeLine{}
\DoxyCodeLine{declare const registry: jobs.SimpleJobRegistry;}
\DoxyCodeLine{registry.register(dispatcher);}
\DoxyCodeLine{registry.register(npmInstall);}
\DoxyCodeLine{registry.register(yarnInstall);}
\DoxyCodeLine{registry.register(pnpmInstall);}
\DoxyCodeLine{}
\DoxyCodeLine{// Default to npm.}
\DoxyCodeLine{dispatcher.setDefaultDelegate(npmInstall.name);}
\DoxyCodeLine{// If the user is asking for yarn over npm, uses it.}
\DoxyCodeLine{dispatcher.addConditionalDelegate(() => userWantsYarn, yarnInstall.name); }

\end{DoxyCode}
\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1947}{}\doxysubsection{Execution Strategy}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1947}
Jobs are always run in parallel and will always start, but many helper functions are provided when creating a job to help you control the execution strategy;


\begin{DoxyEnumerate}
\item {\ttfamily serialize()}. Multiple runs of this job will be queued with each others.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item {\ttfamily memoize(replay\+Messages = false)} will create a job, or reuse the same job when inputs are matching. If the inputs don\textquotesingle{}t match, a new job will be started and its outputs will be stored.
\end{DoxyEnumerate}

These strategies can be used when creating the job\+:


\begin{DoxyCode}{0}
\DoxyCodeLine{// Same input and output as above.}
\DoxyCodeLine{}
\DoxyCodeLine{export const add = jobs.strategy.memoize()(}
\DoxyCodeLine{  jobs.createJobHandler<number[], number>(}
\DoxyCodeLine{      argument => argument.reduce((total, curr) => total + curr, 0),}
\DoxyCodeLine{  ),}
\DoxyCodeLine{); }

\end{DoxyCode}


Strategies can be reused to synchronize between jobs. For example, given jobs {\ttfamily jobA} and {\ttfamily jobB}, you can reuse the strategy to serialize both jobs together;


\begin{DoxyCode}{0}
\DoxyCodeLine{const strategy = jobs.strategy.serialize();}
\DoxyCodeLine{const jobA = strategy(jobs.createJobHandler(...));}
\DoxyCodeLine{const jobB = strategy(jobs.createJobHandler(...)); }

\end{DoxyCode}


Even further, we can have package A and package B run in serialization, and B and C also be serialized. Running A and C will run in parallel, while running B will wait for both A and C to finish.


\begin{DoxyCode}{0}
\DoxyCodeLine{const strategy1 = jobs.strategy.serialize();}
\DoxyCodeLine{const strategy2 = jobs.strategy.serialize();}
\DoxyCodeLine{const jobA = strategy1(jobs.createJobHandler(...));}
\DoxyCodeLine{const jobB = strategy1(strategy2(jobs.createJobHandler(...)));}
\DoxyCodeLine{const jobC = strategy2(jobs.createJobHandler(...)); }

\end{DoxyCode}
\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1948}{}\doxysection{Scheduling Jobs}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1948}
Jobs can be scheduled using a {\ttfamily Scheduler} interface, which contains a {\ttfamily schedule()} method\+:


\begin{DoxyCode}{0}
\DoxyCodeLine{interface Scheduler \{}
\DoxyCodeLine{  /**}
\DoxyCodeLine{   * Schedule a job to be run, using its name.}
\DoxyCodeLine{   * @param name The name of job to be run.}
\DoxyCodeLine{   * @param argument The argument to send to the job when starting it.}
\DoxyCodeLine{   * @param options Scheduling options.}
\DoxyCodeLine{   * @returns The Job being run.}
\DoxyCodeLine{   */}
\DoxyCodeLine{  schedule<I extends MinimumInputValueT, O extends MinimumOutputValueT>(}
\DoxyCodeLine{    name: JobName,}
\DoxyCodeLine{    argument: I,}
\DoxyCodeLine{    options?: ScheduleJobOptions,}
\DoxyCodeLine{  ): Job<JsonValue, O>;}
\DoxyCodeLine{\} }

\end{DoxyCode}


The scheduler also has a {\ttfamily get\+Description()} method to get a {\ttfamily Job\+Description} object for a certain name; that description contains schemas for the argument, input, output, and other channels\+:


\begin{DoxyCode}{0}
\DoxyCodeLine{interface Scheduler \{}
\DoxyCodeLine{  /**}
\DoxyCodeLine{   * Get a job description for a named job.}
\DoxyCodeLine{   *}
\DoxyCodeLine{   * @param name The name of the job.}
\DoxyCodeLine{   * @returns A description, or null if the job cannot be scheduled.}
\DoxyCodeLine{   */}
\DoxyCodeLine{  getDescription(name: JobName): JobDescription | null;}
\DoxyCodeLine{    }
\DoxyCodeLine{  /**}
\DoxyCodeLine{   * Returns true if the job name has been registered.}
\DoxyCodeLine{   * @param name The name of the job.}
\DoxyCodeLine{   * @returns True if the job exists, false otherwise.}
\DoxyCodeLine{   */}
\DoxyCodeLine{  has(name: JobName): boolean;}
\DoxyCodeLine{\} }

\end{DoxyCode}


Finally, the scheduler interface has a {\ttfamily pause()} method to stop scheduling. This will queue all jobs and wait for the unpause function to be called before unblocking all the jobs scheduled. This does not affect already running jobs.


\begin{DoxyCode}{0}
\DoxyCodeLine{interface Scheduler \{}
\DoxyCodeLine{  /**}
\DoxyCodeLine{   * Pause the scheduler, temporary queueing \_new\_ jobs. Returns a resume function that should be}
\DoxyCodeLine{   * used to resume execution. If multiple `pause()` were called, all their resume functions must}
\DoxyCodeLine{   * be called before the Scheduler actually starts new jobs. Additional calls to the same resume}
\DoxyCodeLine{   * function will have no effect.}
\DoxyCodeLine{   *}
\DoxyCodeLine{   * Jobs already running are NOT paused. This is pausing the scheduler only.}
\DoxyCodeLine{   *}
\DoxyCodeLine{   * @returns A function that can be run to resume the scheduler. If multiple `pause()` calls}
\DoxyCodeLine{   *          were made, all their return function must be called (in any order) before the}
\DoxyCodeLine{   *          scheduler can resume.}
\DoxyCodeLine{   */}
\DoxyCodeLine{  pause(): () => void;}
\DoxyCodeLine{\} }

\end{DoxyCode}
\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1949}{}\doxysubsection{$<$a name=\char`\"{}\+Dependencies\char`\"{}$>$$<$/a$>$\+Synchronizing and Dependencies}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1949}
When scheduling jobs, it is often necessary to run jobs after certain other jobs are finished. This is done through the {\ttfamily dependencies} options in the {\ttfamily schedule()} method.

These jobs will also be passed to the job being scheduled, through its context. This can be useful if, for example, the output of those jobs are of a known type, or have known side channels.

An example of this would be a compiler that needs to know the output directory of other compilers before it, in a tool chain.\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1950}{}\doxysubsubsection{Dependencies}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1950}
When scheduling jobs, the user can add a {\ttfamily dependencies} field to the scheduling options. The scheduler will wait for those dependencies to finish before running the job, and pass those jobs in the context of the job.\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1951}{}\doxysubsubsection{Accessing Dependencies}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1951}
Jobs are called with a {\ttfamily Job\+Handler\+Context} as a second argument, which contains a {\ttfamily dependencies\+: Job$<$Json\+Value$>$\mbox{[}\mbox{]}} member which contains all dependencies that were used when scheduling the job. Those aren\textquotesingle{}t fully typed as they are determined by the user, and not the job itself. They also can contain jobs that are not finished, and the job should use the {\ttfamily state} member of the job itself before trying to access its content.\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1952}{}\doxysubsubsection{Scheduler Sub Jobs}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1952}
The {\ttfamily Job\+Handler\+Context} also contains a {\ttfamily scheduler} member which can be used to schedule jobs using the same scheduler that was used for the job. This allows jobs to call other jobs and wait for them to end.\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1953}{}\doxysubsection{Available Schedulers}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1953}
The Core Angular Dev\+Kit library provides 2 implementations for the {\ttfamily Scheduler} interface\+:\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1954}{}\doxysubsection{Simple\+Job\+Registry}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1954}
Available in the jobs namespace. A registry that accept job registration, and can also schedule jobs.


\begin{DoxyCode}{0}
\DoxyCodeLine{import \{ jobs \} from '@angular-\/devkit/core';}
\DoxyCodeLine{}
\DoxyCodeLine{const add = jobs.createJobHandler<number[], number>(}
\DoxyCodeLine{  argument => argument.reduce((total, curr) => total + curr, 0),}
\DoxyCodeLine{);}
\DoxyCodeLine{}
\DoxyCodeLine{// Register the job in a SimpleJobRegistry. Different registries have different API.}
\DoxyCodeLine{const registry = new jobs.SimpleJobRegistry();}
\DoxyCodeLine{const scheduler = new SimpleJobScheduler(registry);}
\DoxyCodeLine{}
\DoxyCodeLine{registry.register(add, \{}
\DoxyCodeLine{  name: 'add',}
\DoxyCodeLine{  argument: \{ type: 'array', items: \{ type: 'number' \} \},}
\DoxyCodeLine{  output: \{ type: 'number' \},}
\DoxyCodeLine{\});}
\DoxyCodeLine{}
\DoxyCodeLine{scheduler.schedule('add', [1, 2, 3, 4]); }

\end{DoxyCode}
\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1955}{}\doxysubsection{Node\+Module\+Job\+Registry}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1955}
Available through {\ttfamily @angular-\/devkit/core/node}.

A scheduler that loads jobs using their node package names. These jobs need to use the {\ttfamily create\+Job\+Handler()} helper and report their argument/input/output schemas that way.


\begin{DoxyCode}{0}
\DoxyCodeLine{declare const registry: NodeModuleJobRegistry;}
\DoxyCodeLine{const scheduler = new SimpleJobScheduler(registry);}
\DoxyCodeLine{}
\DoxyCodeLine{scheduler.schedule('some-\/node-\/package\#someExport', 'input'); }

\end{DoxyCode}
\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1956}{}\doxysection{Gotchas}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1956}

\begin{DoxyEnumerate}
\item Deadlocking Dependencies ~\newline
 It is impossible to add dependencies to an already running job, but it is entirely possible to get locked between jobs. Be aware of your own dependencies.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item Using {\ttfamily job.\+promise} ~\newline
 {\ttfamily job.\+promise} waits for the job to ends. Don\textquotesingle{}t rely on it unless you know the job is not watching and running for a long time. If you aren\textquotesingle{}t sure, use {\ttfamily job.\+output.\+pipe(first()).to\+Promise()} instead which will return the first next output, regardless of whether the job watches and rerun or not.
\end{DoxyEnumerate}\hypertarget{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1957}{}\doxysection{FAQ}\label{md_sfcode_node_modules__ngtools_webpack_node_modules__angular_devkit_core_src_experimental_jobs_README_autotoc_md1957}

\begin{DoxyEnumerate}
\item Laziness ~\newline
 A job is lazy until executed, but its messages will be replayed when resubscribed.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item Serialize Strategy vs Dependencies ~\newline
 Strategies are functions that transform the execution of a job, and can be used when declaring the job, or registering it. Dependencies, on the other hand, are listed when scheduling a job to order jobs during scheduling.

A job has no control over the way it\textquotesingle{}s scheduled, and its dependencies. It can, however, declare that it shouldn\textquotesingle{}t run at the same time as itself. Alternatively, a user could schedule a job twice and imply that the second run should wait for the first to finish. In practice, this would be equivalent to having the job be serialized, but the important detail is in {\itshape whom} is defining the rules; using the {\ttfamily serialize()} strategy, the job implementation is, while when using dependencies, the user is.

The user does not need to know how to job needs to synchronize with itself, and the job does not need to know how it synchronizes with other jobs that it doesn\textquotesingle{}t know about. That\textquotesingle{}s part of the strength of this system as every job can be developed in a vacuum, only caring about its contracts (argument, input and output) and its own synchronization. 
\end{DoxyEnumerate}