Skip to content

Async Jobs via Quartz

David An edited this page Oct 13, 2023 · 6 revisions

So, you want to create a new async API, or at least a new async job.

Quickstart

look at ImportService, which creates ImportJobInput and TdrManifestSchedulable and eventually executes TdrManifestQuartzJob.

Checklist

The high-level development tasks for a new async job are:

  1. Define the API signature, including request and response payloads, in OpenAPI YAML. New "v1" APIs should go in apis-v1.yaml.
  2. Define a model for the user-supplied input arguments, i.e. the request payload, by subclassing JobInput
  3. Define a model for the user-facing output, i.e. the response payload, by subclassing JobResponse
  4. Define the internal job metadata, such as its description and implementation class, by subclassing Schedulable or using Schedulable as-is
  5. Writing the internal implementation code for the functionality you want to execute asynchronously, in a subclass of QuartzJob.
    1. This must be a Spring Bean - for instance, annotated with @Component - and therefore can/must include injected resources such as JobDao.
  6. Stitch all these together, following the execution flow defined below

Execution Flow

At a high level, the flow of an asynchronous API is:

  1. End user makes a request to your async API
  2. Controller class processes the request, deserializing the payload into an auto-generated model class, and hands off to a Service class
  3. Service class:
    1. Translates the auto-generated model class into your JobInput subclass
    2. Uses the JobInput class to create a Job instance
    3. Persists the Job to the Postgres sys_wds.job table via JobDao.createJob()
    4. Generates the inputs for the async process and creates a Schedulable defining what should be run asynchronously
    5. Persists the Schedulable to Quartz via SchedulerDao.schedule(). This begins the async execution.
    6. Marks the Job as QUEUED via JobDao.updateStatus()
    7. Returns some value to the controller class
  4. Controller class responds with a 202 Accepted to the end user
  5. Quartz notices the async process that was scheduled in step 3.v. - it may have already started.
    1. Quartz finds the Spring Bean matching the class defined in your Schedulable
    2. Quartz calls execute() on that bean. Note that if your code subclasses QuartzJob, you are likely to have implemented executeInternal() instead; QuartzJob provides a best-practice implementation of execute().
  6. Your implementation code, inside your subclass of QuartzJob, must:
    1. Retrieve any necessary inputs from JobExecutionContext.getMergedJobDataMap(), potentially using the helper methods inside QuartzJob
    2. Perform your custom business logic
    3. Throw an exception on any failures, potentially using JobExecutionException
    4. Persist any user-facing output to the Job using a JobResult subclass

WDS Async API flow (1)