Jobs is a high-\/order API that adds inputs, runtime type checking, sequencing, and other functionality on top of Rx\+JS\textquotesingle{} {\ttfamily Observable}s.\hypertarget{md_sfcode_node_modules__angular_devkit_build_angular_node_modules__angular_devkit_core_src_experimental_jobs_architecture_autotoc_md790}{}\doxysection{Background}\label{md_sfcode_node_modules__angular_devkit_build_angular_node_modules__angular_devkit_core_src_experimental_jobs_architecture_autotoc_md790}
An {\ttfamily Observable} (at a higher level) is a function that receives a {\ttfamily Subscriber}, and outputs multiple values, and finishes once it calls the {\ttfamily Subscriber.\+prototype.\+complete()} method (in Java\+Script)\+:


\begin{DoxyCode}{0}
\DoxyCodeLine{const output1To10EverySecond = function (subscriber) \{}
\DoxyCodeLine{  let t = 0;}
\DoxyCodeLine{  const i = setInterval(() => \{}
\DoxyCodeLine{    t++;}
\DoxyCodeLine{    subscriber.next(t);}
\DoxyCodeLine{    if (t === 10) \{}
\DoxyCodeLine{      subscriber.complete(t);}
\DoxyCodeLine{    \}}
\DoxyCodeLine{  \}, 1000);}
\DoxyCodeLine{  return () => clearInterval(i);}
\DoxyCodeLine{\};}
\DoxyCodeLine{}
\DoxyCodeLine{const stream\$ = new Observable(output1To10EverySecond);}
\DoxyCodeLine{// Start the function, and output 1 to 100, once per line.}
\DoxyCodeLine{stream\$.subscribe(x => console.log(x)); }

\end{DoxyCode}


This, of course, can be typed in Type\+Script, but those types are not enforced at runtime.\hypertarget{md_sfcode_node_modules__angular_devkit_build_angular_node_modules__angular_devkit_core_src_experimental_jobs_architecture_autotoc_md791}{}\doxysection{Glossary}\label{md_sfcode_node_modules__angular_devkit_build_angular_node_modules__angular_devkit_core_src_experimental_jobs_architecture_autotoc_md791}

\begin{DoxyItemize}
\item {\ttfamily job handler}. The function that implements the job\textquotesingle{}s logic.
\item {\ttfamily raw input}. The input observable sending messages to the job. These messages are of type {\ttfamily Job\+Inbound\+Message}.
\item {\ttfamily raw output}. The output observer returned from the {\ttfamily job handler}. Messages on this observable are of type {\ttfamily Job\+Outbound\+Message}.
\end{DoxyItemize}\hypertarget{md_sfcode_node_modules__angular_devkit_build_angular_node_modules__angular_devkit_core_src_experimental_jobs_architecture_autotoc_md792}{}\doxysection{Description}\label{md_sfcode_node_modules__angular_devkit_build_angular_node_modules__angular_devkit_core_src_experimental_jobs_architecture_autotoc_md792}
A {\ttfamily Job\+Handler}, similar to observables, is a function that receives an argument and a context, and returns an {\ttfamily Observable} of messages, which can include outputs that are typed at runtime (using a Json Schema)\+:


\begin{DoxyCode}{0}
\DoxyCodeLine{const output1ToXEverySecond = function (x, context) \{}
\DoxyCodeLine{  return new Observable(subscriber => \{}
\DoxyCodeLine{    let t = 0;}
\DoxyCodeLine{}
\DoxyCodeLine{    // Notify our users that the actual work is started.}
\DoxyCodeLine{    subscriber.next(\{ kind: JobOutboundMessageKind.Start \});}
\DoxyCodeLine{    const i = setInterval(() => \{}
\DoxyCodeLine{      t++;}
\DoxyCodeLine{      subscriber.next(\{ kind: JobOutboundMessageKind.Output, value: t \});}
\DoxyCodeLine{      if (t === x) \{}
\DoxyCodeLine{        subscriber.next(\{ kind: JobOutboundMessageKind.End \});}
\DoxyCodeLine{        subscriber.complete();}
\DoxyCodeLine{      \}}
\DoxyCodeLine{    \}, 1000);}
\DoxyCodeLine{}
\DoxyCodeLine{    return () => \{}
\DoxyCodeLine{      clearInterval(i);}
\DoxyCodeLine{    \};}
\DoxyCodeLine{  \})}
\DoxyCodeLine{\};}
\DoxyCodeLine{}
\DoxyCodeLine{// For now, jobs can not be called without a registry and scheduler.}
\DoxyCodeLine{const registry = new SimpleJobRegistry();}
\DoxyCodeLine{registry.register('output-\/from-\/1-\/to-\/x', output1ToXEverySecond, \{}
\DoxyCodeLine{  argument: \{ type: 'number' \},}
\DoxyCodeLine{  output: \{ type: 'number' \},}
\DoxyCodeLine{\});}
\DoxyCodeLine{const scheduler = new SimpleScheduler(registry);}
\DoxyCodeLine{}
\DoxyCodeLine{// Need to keep the same name that the registry would understand.}
\DoxyCodeLine{// Count from 1 to 10.}
\DoxyCodeLine{const job = scheduler.schedule('output-\/from-\/1-\/to-\/x', 10);}
\DoxyCodeLine{}
\DoxyCodeLine{// A Job<> instance has more members, but we only want the output values here.}
\DoxyCodeLine{job.output.subscribe(x => console.log(x)); }

\end{DoxyCode}


This seems like a lot of boilerplate in comparison, but there are a few advantages;


\begin{DoxyEnumerate}
\item lifecycle. Jobs can tell when they start doing work and when work is done.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item everything is typed, even at runtime.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item the context also contains an input Observable that receives typed input messages, including input values, and stop requests.
\end{DoxyEnumerate}
\begin{DoxyEnumerate}
\item jobs can also schedule other jobs and wait for them, even if they don\textquotesingle{}t know if a job is implemented in the system.
\end{DoxyEnumerate}\hypertarget{md_sfcode_node_modules__angular_devkit_build_angular_node_modules__angular_devkit_core_src_experimental_jobs_architecture_autotoc_md793}{}\doxysubsection{Diagram}\label{md_sfcode_node_modules__angular_devkit_build_angular_node_modules__angular_devkit_core_src_experimental_jobs_architecture_autotoc_md793}
A simpler way to think about jobs in contrast to observables is that job are closer to a Unix process. It has an argument (command line flags), receive inputs (STDIN and interrupt signals), and output values (STDOUT) as well as diagnostic (STDERR). They can be plugged one into another (piping), and can be transformed, synchronized and scheduled (fork, exec, cron).


\begin{DoxyCode}{0}
\DoxyCodeLine{-\/ given A the type of the argument}
\DoxyCodeLine{-\/ given I the type of the input}
\DoxyCodeLine{-\/ given O the type of the output}
\DoxyCodeLine{}
\DoxyCodeLine{                              ,\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_   }
\DoxyCodeLine{    JobInboundMessage<I> -\/-\/> | handler(argument: A) |  -\/-\/> JobOutboundMessage<O>}
\DoxyCodeLine{                                                            -\/ JobOutboundMessageKind.Output}
\DoxyCodeLine{                                                            -\/ ... }

\end{DoxyCode}


{\ttfamily Job\+Inbound\+Message} includes\+:


\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}

{\ttfamily Job\+Outbound\+Message} includes\+:


\begin{DoxyEnumerate}
\item {\ttfamily Job\+Outbound\+Message\+Kind.\+Ready}. 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}

Utilities should have some filtering and dispatching to separate observables, as a convenience for the user. An example of this would be the {\ttfamily Job.\+prototype.\+output} observable which only contains the value contained by messages of type {\ttfamily Job\+Outbound\+Message\+Kind.\+Output}.\hypertarget{md_sfcode_node_modules__angular_devkit_build_angular_node_modules__angular_devkit_core_src_experimental_jobs_architecture_autotoc_md794}{}\doxysection{Higher Order Jobs}\label{md_sfcode_node_modules__angular_devkit_build_angular_node_modules__angular_devkit_core_src_experimental_jobs_architecture_autotoc_md794}
Because jobs are expected to be pure functions, they can be composed or transformed to create more complex behaviour, similar to how Rx\+JS operators can transform observables.


\begin{DoxyCode}{0}
\DoxyCodeLine{// Runs a job on the hour, every hour, regardless of how long the job takes.}
\DoxyCodeLine{// This creates a job function that can be registered by itself.}
\DoxyCodeLine{function scheduleJobOnTheHour(jobFunction) \{}
\DoxyCodeLine{  return function(argument, context) \{}
\DoxyCodeLine{    return new Observable(observer => \{}
\DoxyCodeLine{      let timeout = 0;}
\DoxyCodeLine{   }
\DoxyCodeLine{      function \_timeoutToNextHour() \{}
\DoxyCodeLine{        // Just wait until the next hour.}
\DoxyCodeLine{        const t = new Date();}
\DoxyCodeLine{        const secondsToNextHour = 3600 -\/ t.getSeconds() -\/ t.getMinutes() * 60;}
\DoxyCodeLine{        timeout = setTimeout(\_scheduleJobAndWaitAnHour, secondsToNextHour);}
\DoxyCodeLine{      \}}
\DoxyCodeLine{   }
\DoxyCodeLine{      function \_scheduleJobAndWaitAnHour() \{}
\DoxyCodeLine{        jobFunction(argument, context).subscribe(}
\DoxyCodeLine{          message => observer.next(message),}
\DoxyCodeLine{          error => observer.error(error),}
\DoxyCodeLine{          // Do not forward completion, but use it to schedule the next job run.}
\DoxyCodeLine{          () => \{}
\DoxyCodeLine{            \_timeoutToNextHour();}
\DoxyCodeLine{          \},}
\DoxyCodeLine{        );}
\DoxyCodeLine{      \}}
\DoxyCodeLine{   }
\DoxyCodeLine{      // Kick off by waiting for next hour.}
\DoxyCodeLine{      \_timeoutToNextHour();}
\DoxyCodeLine{   }
\DoxyCodeLine{      return () => clearTimeout(timeout);}
\DoxyCodeLine{    \});}
\DoxyCodeLine{  \};}
\DoxyCodeLine{\} }

\end{DoxyCode}


Another way to compose jobs is to schedule jobs based on their name, from other jobs.


\begin{DoxyCode}{0}
\DoxyCodeLine{// Runs a job on the hour, every hour, regardless of how long the job takes.}
\DoxyCodeLine{// This creates a high order job by getting a job name and an argument, and scheduling the job}
\DoxyCodeLine{// every hour.}
\DoxyCodeLine{function scheduleJobOnTheHour(job, context) \{}
\DoxyCodeLine{  const \{ name, argument \} = job;  // Destructure our input.}
\DoxyCodeLine{}
\DoxyCodeLine{  return new Observable(observer => \{}
\DoxyCodeLine{    let timeout = 0;}
\DoxyCodeLine{}
\DoxyCodeLine{    function \_timeoutToNextHour() \{}
\DoxyCodeLine{      // Just wait until the next hour.}
\DoxyCodeLine{      const t = new Date();}
\DoxyCodeLine{      const secondsToNextHour = 3600 -\/ t.getSeconds() -\/ t.getMinutes() * 60;}
\DoxyCodeLine{      timeout = setTimeout(\_scheduleJobAndWaitAnHour, secondsToNextHour);}
\DoxyCodeLine{    \}}
\DoxyCodeLine{}
\DoxyCodeLine{    function \_scheduleJobAndWaitAnHour() \{}
\DoxyCodeLine{      const subJob = context.scheduler.schedule(name, argument);}
\DoxyCodeLine{      // We do not forward the input to the sub-\/job but that would be a valid example as well.}
\DoxyCodeLine{      subJob.outboundBus.subscribe(}
\DoxyCodeLine{        message => observer.next(message),}
\DoxyCodeLine{        error => observer.error(error),}
\DoxyCodeLine{        // Do not forward completion, but use it to schedule the next job run.}
\DoxyCodeLine{        () => \{}
\DoxyCodeLine{          \_timeoutToNextHour();}
\DoxyCodeLine{        \},}
\DoxyCodeLine{      );}
\DoxyCodeLine{    \}}
\DoxyCodeLine{}
\DoxyCodeLine{    // Kick off by waiting for next hour.}
\DoxyCodeLine{    \_timeoutToNextHour();}
\DoxyCodeLine{}
\DoxyCodeLine{    return () => clearTimeout(timeout);}
\DoxyCodeLine{  \});}
\DoxyCodeLine{\}}
\DoxyCodeLine{}
\DoxyCodeLine{const registry = new SimpleJobRegistry();}
\DoxyCodeLine{registry.register('schedule-\/job-\/on-\/the-\/hour', scheduleJobOnTheHour, \{}
\DoxyCodeLine{  argument: \{}
\DoxyCodeLine{    properties: \{}
\DoxyCodeLine{      name: \{ type: 'string' \},}
\DoxyCodeLine{      argument: \{ type: true \},}
\DoxyCodeLine{    \},}
\DoxyCodeLine{  \},}
\DoxyCodeLine{\});}
\DoxyCodeLine{}
\DoxyCodeLine{// Implementation left to the reader.}
\DoxyCodeLine{registry.register('copy-\/files-\/from-\/a-\/to-\/b', require('some-\/package/copy-\/job'));}
\DoxyCodeLine{}
\DoxyCodeLine{const scheduler = new SimpleScheduler(registry);}
\DoxyCodeLine{}
\DoxyCodeLine{// A rudimentary backup system.}
\DoxyCodeLine{const job = scheduler.schedule('schedule-\/job-\/on-\/the-\/hour', \{}
\DoxyCodeLine{  name: 'copy-\/files-\/from-\/a-\/to-\/b',}
\DoxyCodeLine{  argument: \{}
\DoxyCodeLine{    from: '/some-\/directory/to/backup',}
\DoxyCodeLine{    to: '/volumes/usb-\/key',}
\DoxyCodeLine{  \},}
\DoxyCodeLine{\});}
\DoxyCodeLine{job.output.subscribe(x => console.log(x)); }

\end{DoxyCode}
\hypertarget{md_sfcode_node_modules__angular_devkit_build_angular_node_modules__angular_devkit_core_src_experimental_jobs_architecture_autotoc_md795}{}\doxysection{Limitations}\label{md_sfcode_node_modules__angular_devkit_build_angular_node_modules__angular_devkit_core_src_experimental_jobs_architecture_autotoc_md795}
Jobs input, output and argument must be serializable to JSONs. This is a big limitation in usage, but comes with the benefit that jobs can be serialized and called across memory boundaries. An example would be an operator that takes a module path and run the job from that path in a separate process. Or even a separate server, using HTTP calls.

Another limitation is that the boilerplate is complex. Manually managing start/end life cycle, and other messages such as ping/pong, etc. is tedious and requires a lot of code. A good way to keep this limitation under control is to provide helpers to create {\ttfamily Job\+Handler}s which manage those messages for the developer. A simple handler could be to get a {\ttfamily Promise} and return the output of that promise automatically. 