Although PHP had to be used for the reference implementation, the single biggest limitation it has (and probably the reason it is always available) was still an obstacle: no persistent server process.
Each script normally executes when requested and then terminates when done. Nothing is left running, between requests, and the server becomes idle. This is generally all that is required and is cheap to deploy so it is common across virtual all web hosting providers.
The problem is when you want something to happen "in the background" (or "at a later time") and not connected directly to pages being requested. To solve this problem, OpenAutonomy uses a set of classes which are referred to as the Asynchronous Execution Engine.
While it seems obvious to try to use PHP's fork support to accomplish this task, it has a few downsides:
Instead, the implementation invokes itself as a real web request. This way, the asynchronous task is not special and all of its code can run as though it were part of a normal request since it is one.
There are 2 levels of information storage and invocation decision-making at play in order to avoid some kinds of "barging" of a slowing down of the core dispatcher (since it is on the critical path of all of these operations):
1. A server-wide set of information recording how many tasks are currently in-flight, when each end-point on the server is next due to be called, and timeout information
2. A per-script queue of tasks to run, along with their string-type arguments and when they are due to run
Requesting async: Whenever a script requests an asynchronous invocation, this results in the request being stored per-scrpt and and an update to the server-wide mapping of next due request (assuming that the one requested is earlier than any pending).
Running async: When the server's async task requests the next event, it looks up the next due end-point (clearing it from the server-wide map), and calls it. When this call starts the script, the script checks its next due async event and runs it. Note that, if there are other events in queue, it will also re-update the server-side mapping with the new due time prior to running the task.
Server task management: The server's number of async tasks is set in a configuration option and the server will start, stop, and re-spawn tasks in response to changes in server work-load and detected timeouts, automatically.
Yes. There are relatively few external dependencies within the engine but the source is not currently laid out in such a way as to make this obvious. This kind of packaging option can be made available, if need be.
Main entry point is GlobalAsyncExecutor - it is easiest to start there to see how it works
Example of how to use this to implement a very simple multi-process application server: App Server Example
Note that relying on the async execution engine for critical operations could be dangerous since the events might be lost if there is a failure when the async task tries to call the end-point which registered the operation. This is unusual and should only happen in the case of a server problem like DNS failure or memory exhaustion, etc.
Also, the initial invocation of the engine is still subject to PHP's limitations: something needs to "start" it. An active server typically won't have this problem since various operations (in response to page requests) make sure that the engine hasn't stalled. It is also possible to create a "cron" entry-point which is called periodically to ensure the engine hasn't stalled (if you have shell access to the server, this should be added to the server's own cron).