Task Error Handling
Task Error Handling
Warlock tasks (delayed jobs, scheduled jobs, and event handlers run by the Warlock Agent) execute in their own child process. By default, if a task raises an unhandled exception, the Agent simply logs it. If the task runs infrequently — a monthly report, an occasional notification — that log entry can easily go unnoticed.
To make failures visible without requiring someone to watch the log file, the Agent can be configured with a task error handler: a callable that is automatically scheduled and executed whenever a task fails, and which receives the error and information about the task that failed. Because it runs as its own task, it is managed by the same task queue, runs in a new process so it doesn't block the Agent, and executes within the full application context (DBI, models, and all other app configuration are available).
Configuring an Error Handler
Register a task.error_handler in your Agent configuration file (agent.json, or your application's config.json).
<?php
return [
'task' => [
'error_handler' => 'App\Models\MyErrorHandler::handleTaskError',
'error_delay' => 35,
],
];{
"task": {
"error_handler": "App\\Models\\MyErrorHandler::handleTaskError",
"error_delay": 35
}
}error_handler: The callable to invoke when a task fails. Accepts the same formats as other Warlock endpoints (Class::methodstring,[Class, method]array). If unset (the default), errors are only logged, matching the previous behaviour.error_delay: Number of seconds to wait before running the error handler task, defaulting to35. This gives the system a brief window to recover on its own before the handler runs.
Writing the Error Handler
An error handler is a normal Warlock endpoint. It is recommended to extend Hazaar\Warlock\Agent\Container so you have access to helper methods like log() and trigger().
namespace App\Models;
use Hazaar\Warlock\Agent\Container;
use Hazaar\Warlock\Enum\LogLevel;
class MyErrorHandler extends Container
{
public function handleTaskError(\stdClass $error, \stdClass $taskInfo): void
{
$this->log("Task {$taskInfo->endpoint} failed: {$error->message}", LogLevel::ERROR);
// Do whatever you need to here - store it in a database, send an
// email, post to a chat channel, etc.
}
}Error Object
The $error argument is a stdClass object describing the exception that was thrown, with the following properties:
message: The exception message.code: The exception code.file: The file the exception was thrown from.line: The line number the exception was thrown from.trace: The exception's stack trace.
Task Info Object
The $taskInfo argument is a stdClass object describing the task that failed:
id: The internal ID of the failed task.endpoint: TheClass::methodname of the endpoint that was executing.retries: The number of retry attempts already consumed by the task before it was considered failed.
Tips
Because the failed task's own process, connections, and application state are gone by the time the handler runs, only this lightweight summary is passed along rather than the task itself.
Recursion and Duplicate Protection
If the error handler task itself throws, it is not rescheduled again — the Agent detects that the failing task is already an error handler and just logs the failure, preventing an endless loop.
Error handler tasks are also tagged per failing task (errorHandler-{taskID}). If the same task fails again before its previously scheduled handler has finished running, the existing handler task is left alone rather than being duplicated.