Skip to content
do- edited this page May 26, 2024 · 94 revisions

Job is a class of single-use objects created for each execution of a business method (from Application's ModuleMap).

(Its name means "jobs" as in Queueing theory, not Oracle Database's periodic tasks)

This class implements the basic workflow used in all doix based server applications. It's presumed to never be inherited from, only extended by setting event handlers.

Job instances are mostly passive objects: other pieces of code get and set their properties, subscribe to events and so on. Only two methods are exposed to be called from elsewhere.

Properties

Private

Name Description
Symbol('todo') An Array of Promises to be awaited for during toComplete ()
Symbol('tracker') a JobLifeCycleTracker or compatible object listening to job's events and registering it with logger
Symbol('timestamps') An object of event-to-timestamp pairs plus the 'created' key with the constructor call timestamp
Symbol('maxLatency') The maximum time between the constructor call and the end or error event, Infinity by default
Symbol('minLatency') The minimum time between the constructor call and the finished event, 0 by default

Public

Name Description
app the Application instance this job belongs to
parent absent by default, by convention this property should be set to this by a job creating another job. For instance, the clone () method sets it.
uuid the unique identifier of this job to use in logs etc. By default, is generated with crypto.randomUUID, but this can be overridden by setting uuid in generators object
rq request parameters, an an Object. Think PHP's $_REQUEST generalization. Setting rq is the way of passing parameters to the business method to be called in the context of this job
module business method containing module: the value fetched from Application's ModuleMap by MethodSelector's getModuleName () result
result the result returned by the business method and to be returned by toComplete ()
error the error thrown by the business method and to be thrown by toComplete ()
logger a winston compatible logger. ConsoleLogger by default (unless set in globals nor generators)
tracker lazy getter for Symbol('TRACKER')

Constructor

Only Application instances are supposed to call it directly.

Elsewhere, Job instances sould be produced by calling Application.createJob ()`.

Methods

assertTracking ()

This synchronous method checks for Symbol('TRACKER') and, unless set, initializes it properly.

callMethod (func)

This asynchronous method invokes func as a method of this job and, normally, returns its result or rethrows the error. If [Symbol('maxLatency')] is finite and the time is out, throws an expirationError () instead.

getTimeLeft (period)

This synchronous method returns period minus the number of milliseconds elapsed from the job creation.

expirationError ()

This synchronous method returns (not throws) an Error with the message "Timeout expired".

setMaxLatency (ms)

This synchronous method sets the Symbol('maxLatency') private property to the non-negative integer ms. If set to a finite number, the end event cannot occur later than ms milliseconds since the job creation. Incase of such a delay, the expirationError result is thrown.

setMinLatency (ms)

This synchronous method sets the Symbol('minLatency') private property to the non-negative integer ms. If set, the finished event will be emitted not earlier than ms milliseconds since the job creation, even if the result is obtained and all resources are freed.

toBroadcast (event, payload)

This asynchronous method implements a single step of the job's lifecycle:

  • writes the current timestamp into this [Symbol ('timestamps')] [event];
  • initializes the TODO list;
  • emits the event (which handlers should either be synchronous or call waitFor (promise));
  • awaits for all promises from the TODO list.

toComplete ()

This asynchronous method implements the job's lifecycle:

  • invokes assertTracking ();
  • setting module to the value fetched from Application's ModuleMap by MethodSelector's getModuleName () result;
  • invoking callMethod with the the business method (got by getMethodName ()) and then:
    • if it throws something, set it to error and rethrow;
    • set the value returned to result and return it otherwise.

At each step but the last one, toComplete () calls toBroadcast () with the corresponding event name to process asynchronous event handlers before proceeding to the next stage. The finished event is just emitted, so all its handlers must be synchronous and neither of them can throw an error.

Each event handler defined as a (not arrow) function sees the Job instance as this and can modify its content. The execution order is fixed, so for each event subsequent handlers see the job state modified by previous ones. In particular, if the business method throws something, the error property may be rewritten by error handlers and if finally it gets undefined, toComplete () returns undefined instead of throwing anything.

clone (rq = {})

This synchronous method duplicates the job by:

  • creating the new instance by calling the containing Application's createJob ();
  • setting its parent property;
  • copying the job's rq value into the new one;
  • overriding portions of it with the rq argument content by calling Object.assign().

The new Job instance is not launched automatically upon creation: it's up to the caller to use its toComplete () method whether immediately or, maybe, after some modifications like setting event listeners etc.

Note: the rq property is copied not by reference, but by value, using JSON.stringify() / JSON.parse(), so

  • modifying new job's rq nested objects can't affect the caller job;
  • rq value must be a plain object without circular references: otherwise, a data loss or a fatal error can occur.

waitFor (promise)

This synchronous method registers the given promise to be awaited for before toComplete () to proceeding to the next stage. It is to be called from event handlers.

fail (error)

This is a wrapper around waitFor that postpones a Promise immediately rejecting with the given error.

resources (clazz)

This generator method iterates over all job's resources provided by pools of a given clazz.

Events

Name When emitted Purpose
start Beginning of the lifecycle Logging, adjusting rq content (e. g. fetching it from a stream)
module The module is set, but the method is not yet chosen Security checks, resource injection
method The method name is known (passed as a parameter to the handler) Security checks, resource injection
end The result is obtained and set as a property Rewriting result, reporting it
error The error is caught and set as a property Rewriting error, reporting it
finish Guaranteed to be emitted after all end / error handlers are done working Cleaning up, logging
finished After asynchronous finish handlers, but not earlier than Symbol('minLatency') ms from job creation Scheduling chained jobs. Only synchronous functions allowed

Clone this wiki locally