This post is about asynchronous work in back end software. It is part one of a series of two posts.
This part looks at use cases and motivations for server-side background work – some of which most developers will have run into – and we prepare the stage for the implementation described in the second post: Getting Work Done with Quartz and Z2.
With background work or asynchronous work we denote activities that happen outside the scope of user interactions – but within the user’s business scope of course.
In essentially any not completely trivial business software, there is some work that is best offloaded to a later point in time or to different computing resources. Some typical use cases are
- Updating a search index or some analytical data (can be expensive and time consuming)
- Following up on some state change of a business entity, e.g. by sending emails
- Producing a state change of a business entity due to an expiration condition
These examples already give a good clue about the main motivation for background work:
- It has to be done once in while – but cannot be done on-demand as it is too expensive (either in time or space)
- It has to be done, but it is not necessary to have the user wait for it (and hence impact the user experience)
- It has to be done at some defined later point in time (e.g. order to be revisited two weeks after creation).
Another, great motivation to put work into the background is …
- … that the operation is not reliable and may need to be tried again at some later point in time (e.g. mail server problems, overload, etc.) and finally that
- … that resources may be used more efficiently, if work can be queued up and processed when resources are available rather when there is peaks of user load
- … to move the work elsewhere so that e.g. front end resource are not impacted and so that user experience is not harmed
All of these cases fall into one of the following two categories:
Asynchronous GET (AGET): The operation is idempotent. The operation generates some information, that – if nothing else is changed – stays unchanged. Computing analytical insight is an example for this case. This kind of work can be postponed, or repeated as convenient. The reason for an “Async GET” is an optimization.
Asynchronous POST (APOST): The operation implies a state change. It should be performed either as soon as possible or at some given point in time. An APOST corresponds to a user interaction. An APOST typically needs to some input data for processing. Once done, the operation may not be repeated. The reason for an APOST is an optimization of user experience or some intended deferment.
The analogy with the HTTP method GET and POST is intended and complete. In fact, all the sample use cases above, any use case I have encountered, can be modeled as scheduled GET or a deferred POST request. The analogy carries further: A scheduling system should indeed allow to trigger an AGET or retrigger an APOST at any time in a way that an administrator can completely infer the meaning and target of the “request”.
The analogy reduces the scheduling system to where it belongs: Managing activity triggers in time. This includes:
- Some concurrency control: In many cases it is more efficient that the scheduling system doesn’t even try is some other activity is still ongoing rather than blocking on the application layer.
- Ability to re-attempt some activity for some number of times and with some delay
- Some visual management of pending or failed activities
More on that in “Getting Work Done with Quartz and Z2.”. Stay tuned!