Module Queue
The nine endpoints that watch, retry and clear the work modules do in the background.
Overview
Provisioning, suspending or cancelling a service means the module has to talk to a provider. To keep the request from waiting, that conversation goes into a queue and runs in the background. These nine endpoints watch that queue and step into it.
A job gets a set number of tries; on reaching it the job fails and is never tried again on its own. Putting a failed job back in line, or running it without waiting, is what these endpoints are for.
Reference
Listing the Queue
Returns the jobs handed to modules to run in the background.
pending is queued, processing is running, completed finished, failed did not.curl -G 'https://panel.example.com/api/v1/admin/tools/module-queue' \
-H "Authorization: Bearer $API_KEY" \
-d status=failedconst url = new URL('https://panel.example.com/api/v1/admin/tools/module-queue');
url.searchParams.set('status', 'failed');
const res = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();$url = 'https://panel.example.com/api/v1/admin/tools/module-queue?' . http_build_query(['status' => 'failed']);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The list carries no logs: read an item's detail to see why a job failed.
$failed = Api::Tools()->GetModuleQueue([], ['status' => 'failed'])['data'];The Queue Counters
Returns how many jobs are in the queue, counted by status.
curl 'https://panel.example.com/api/v1/admin/tools/module-queue/stats' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/tools/module-queue/stats', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/module-queue/stats');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// This is the cheapest endpoint to watch: it gives the queue's health without pulling the list.
$stats = Api::Tools()->GetModuleQueueStats()['data'];
$stuck = $stats['failed'] > 0 || $stats['pending'] > 100;Item Detail
Returns one job together with the record of what was exchanged with the provider.
pending is queued, processing is running, completed finished, failed did not.curl 'https://panel.example.com/api/v1/admin/tools/module-queue/101' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/tools/module-queue/101', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/module-queue/101');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Read the logs BEFORE retrying: with the same condition in place the job fails at the same point.
$item = Api::Tools()->GetModuleQueueItem(['id' => 101])['data'];
$last = end($item['api_logs']);Retrying an Item
Puts a failed job back in the queue and resets its try counter.
curl -X POST 'https://panel.example.com/api/v1/admin/tools/module-queue/101/retry' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/tools/module-queue/101/retry', {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/module-queue/101/retry');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// A retry does not run the job NOW: it queues it and the background worker takes over.
// To see it without waiting, use the run endpoint.
Api::Tools()->RetryModuleQueueItem(['id' => 101]);Running an Item Now
Runs the job there and then, without waiting for the background worker, and returns the outcome.
curl -X POST 'https://panel.example.com/api/v1/admin/tools/module-queue/101/run' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/tools/module-queue/101/run', {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/module-queue/101/run');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The request answers 200 even when the job FAILED: success is in 'task_success'.
$result = Api::Tools()->RunModuleQueueItem(['id' => 101])['data'];
if (!$result['task_success']) {
$why = $result['task_message'];
}{
"data": {
"task_success": false,
"task_message": "Provider refused: quota exceeded.",
"item": {
"id": 101,
"status": "failed",
"attempts": 3,
"max_attempts": 3
}
}
}Deleting an Item
Takes a job out of the queue. The work itself stays undone.
gate:module.queue_intervene hook vetoed the operation.curl -X DELETE 'https://panel.example.com/api/v1/admin/tools/module-queue/101' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/tools/module-queue/101', {
method: 'DELETE',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/module-queue/101');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Deleting CANCELS the job: a service waiting to be provisioned keeps waiting.
Api::Tools()->DeleteModuleQueueItem(['id' => 101]);Deleting in Bulk
Takes several jobs out of the queue.
gate:module.queue_intervene hook vetoed the operation.curl -X POST 'https://panel.example.com/api/v1/admin/tools/module-queue/bulk-delete' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"ids":[101,102,103]}'const res = await fetch('https://panel.example.com/api/v1/admin/tools/module-queue/bulk-delete', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ ids: [101, 102, 103] }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/module-queue/bulk-delete');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['ids' => [101, 102, 103]]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The id list comes back as you sent it: ids that no longer exist are echoed too, never dropped.
$response = Api::Tools()->BulkDeleteModuleQueue(['ids' => [101, 102, 103]]);
$echoed = $response['data']['ids'];Retrying Everything That Failed
Puts every failed job in the queue back in line.
curl -X POST 'https://panel.example.com/api/v1/admin/tools/module-queue/retry-all-failed' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/tools/module-queue/retry-all-failed', {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/module-queue/retry-all-failed');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The endpoint does not say how many were queued; measure it with the counters either side.
$before = Api::Tools()->GetModuleQueueStats()['data']['failed'];
Api::Tools()->RetryAllFailedModuleQueue();
$after = Api::Tools()->GetModuleQueueStats()['data']['failed'];Clearing What Finished
Deletes the finished jobs from the queue.
curl -X POST 'https://panel.example.com/api/v1/admin/tools/module-queue/clear-completed' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/tools/module-queue/clear-completed', {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/module-queue/clear-completed');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The clear takes what FINISHED; failed jobs stay put and wait to be looked at.
Api::Tools()->ClearCompletedModuleQueue();Pitfalls
The run endpoint answers 200 even when the job failed; whether it worked is a field in the response. A client reading only the status code counts a failed provisioning as a success. The error message comes back in the same response.
A retry queues the job: the try counter resets and the background worker runs it when its turn comes. The run endpoint does the work there and then and returns the outcome. Use the second when you want to see what happened.
Deleting a queue item does not merely tidy a record: that job is never done. A service waiting to be provisioned keeps waiting and nothing reminds you. That is why the delete is guarded by a hook, and your installation may refuse the request through it.
The record of what was exchanged with the provider is heavy, so it is left out of the list and appears only on a single item. Read it before retrying a job, because with the same condition in place it fails at the same point again.
The retry-all and clear-completed endpoints say only that they ran; they do not report how many jobs they touched. To measure the effect, read the counters before and after.
Related Articles
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.