...
- create "
ITaskHandler
" interface with "handleTaskRun(kDBItem $task_run)
" method - 0.5h - create "
TaskQueue
" database table (unit name "task-queue
") with following columns: - 1hId
TaskHandlerClass
- FQCN of PHP class, which is responsible for processing this task queue record (must implement "ITaskHandler
" interface)TaskData
- JSON-encoded data, that is needed for task execution (e.g. e-mail recipient, IDs of records to be processed)ScheduledOn
- when task needs to be processed (set at queuing time)QueuedOn
- when task was queuedQueuedById
- who queued the taskLastStatus
- status from last attempt of this queue record processing (same options as for "TaskRuns.Status
" field)MaxRetries
- if task fails specified number of times (5 by default), then don't retry itTaskRunsFailed
- number failed task runs (number is reset, when task execution was successful)
- create "
TaskRuns
" database table (unit name: "task-run
") with following columns: - 1hId
TaskQueueId
- ID of record from "TaskQueue
" table, that is responsible for creation this runStartedOn
- when task run was started; NULL set to moment, when status changes from "scheduled
" to "processing
"PercentsCompleted
- "0
" by default, but will be updated as task is being processedFinishedOn
- when task was finished executing (regardless of status)Results
- JSON-encoded results in any format, that be later displayed in human-readable formStatus
- same statuses as for "TaskQueue.LastStatus" column- "
scheduled
" - initially, when record is created; - "
running
" - when somebody is processing the record; - "
success
" - when execution finished without errors; - "
error
" - when known error happened during processing; - "
timeout
" - when associated task runner died unexpectedly
- "
StandardOutput
- what was written to "stdout" stream during this task runErrorOutput
- what was written to "stderr" stream during this task runErrorCode
- non-empty when known error happenedErrorMessage
- non-empty when known error happenedTaskRunnerId
- NULL by default; ID of task runner that processing/processed given task run
- create "
TaskRunners
" database table (unit name: "task-runner
") with following columns: - 1hId
ProcessId
- the PID of process, that started/created task runnerStartedOn
- when process was startedFinishedOn
- when process was finished; NULL initiallyStatus
- status of task runner:- "
running
" - default; means task runner is running - "
success
" - set, when task runner decides to kill itself - "
timeout
" - set by overseer when task runner in "running
" status and associated process isn't running
- "
- in "
task-run:OnAfterItemUpdate
" event will: - 0.5h- load "
task-queue
" object associated with updated task run - get all "
task-run
" records for that "task-queue
" (via sql); then sort them from recent to old (via php) - set following fields on "task-queue" object:
- "
LastStatus
" to "Status" of most recent "task-run" - "
TaskRunsFailed
" to count of "task-run" records in "error" and "timeout" statuses (if last run is failed) - "
TaskRunsFailed
" to "0" (if last run was successful)
- "
- load "
- in "
task-runner::OnBeforeItemCreate
" event set "ProcessId
" to PID of current process - 0.1h - in "
task-runner:OnAfterItemUpdate
" event, when "Status
" changes from "running
" to "timeout
" set all "task-run
" status, that are processed by this task runner from "running
" to "timeout
" as well - 0.3h - the "
task-run
" would be sub-item of "task-queue
" unit - 0.1h
...
- add "
declare(ticks = 1);
" on top of "/tools/run_event.php
" file - 0.1h - create new "
TaskRunnerLimit
" system setting set to "8
" by default - 0.2h - create "
TaskRunner
" class with: - 0.2h- add "
TaskRunner::taskRunnerId
" property - add "
TaskRunner::lastSignal
" property
- add "
- add protected "
TaskRunner::signalHandler
" method, that will store received signal in the "TaskRunner::lastSignal
" property - 0.5h - add "
TaskRunner::__construct($task_runner_id)
" method, that will: - 0.5h- store given "
$task_runner_id
" into "TaskRunner:taskRunnerId
" property - if executed from CLI (PHP_SAPI constant check), then use "
pcntl_signal
" function to register "TaskRunner::signalHandler
" method as signal listeners for following signals:SIGINT
SIGTERM
SIGKILL
SIGHUP
- store given "
- add public "
TaskQueue::getTaskRunner()
" method, that will: - 0.5h- call "
TaskQueue::getMissingTaskRunnerCount
" method - if method returned "0", then return "null"
- create new "
task-runner
" object - return instance of "
TaskRunner
" class initialized with ID of just created task runner
- call "
- add protected "
TaskRunner::getNextTaskRunId()
" method, that will: - 0.5h- acquire WRITE lock "
TaskRuns
" database table (solves racing condition in parallel environment) - pick 1st available "
task-run
" in "scheduled
" status (FIFO logic) - release above acquired lock
- return found task run id or "null" when nothing was found
- acquire WRITE lock "
- add protected "
TaskRunner
", that will: - 1h::processTaskRun($task_run_id)
- load "
task-run
" by given ID from the database or throw an exception if wasn't found - if given "
task-run
" isn't in "scheduled
" status, then throw an exception - set following fields and save changes to db immediately:
- "
TaskRunnerId
" to value of "TaskRunner::taskRunnerId
" property - "
Status
" to "processing
"
- "
- create task handler by calling "
TaskQueue::createTaskHandler
" method - enable redirection of "stdout" and "stderr" into temp files
- call the "
handle
TaskRun
" (wrapped within try/catch block) on that object providing task run object (was loaded above) as an argument - store contents of above temp files into "
StandardOutput
" and "ErrorOutput
" fields of "task-run
" object - the above method can update given object fields at will and save to db (e.g. "
PercentsCompleted
" and "Results
") - when exception was caught, then:
- set "
Status
" to "error
" - set "
ErrorCode
" to exception code - set "
ErrorMessage
" to exception message
- set "
- when no exception was caught, then:
- set "
Status
" to "success
" - set "
ErrorCode
" and "ErrorMessage
" to empty value
- set "
- set "
FinishedOn
" to time, when task was finished (with error or not)
- save changes to db
- load "
- add public "
TaskRunner::process()
" method, that will consist of while loop, where each iteration will: - 0.5h- call "
TaskRunner::
getNextTaskRunId
" method - call "
TaskRunner::
processTaskRun
" with ID found above (if ID was found) - in either of following cases set "
FinishedOn
" to NOW() on associated "task-runner
" record and exit- "
TaskRunner::lastSignal
" is set - overall memory consumption is more than 100MB
- it's not CLI mode
- "
- sleep for X of seconds
- call "
- add "
task-runner:OnProcess
" event, that will: - 0.5h- call the "
TaskQueue::getTaskRunner
" method - if an object is returned, then call "
->process()
" method on it
- call the "
...