PHPackages                             salesrender/plugin-component-queue - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. salesrender/plugin-component-queue

ActiveLibrary

salesrender/plugin-component-queue
==================================

SalesRender plugin queue abstract component

0.3.5(2y ago)01.0k↓100%3proprietaryPHPPHP &gt;=7.4.0

Since Oct 13Pushed 2mo ago2 watchersCompare

[ Source](https://github.com/SalesRender/plugin-component-queue)[ Packagist](https://packagist.org/packages/salesrender/plugin-component-queue)[ RSS](/packages/salesrender-plugin-component-queue/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (5)Versions (10)Used By (3)

salesrender/plugin-component-queue
==================================

[](#salesrenderplugin-component-queue)

Abstract queue component for the SalesRender plugin ecosystem. Provides a task queue with retry logic, built on top of Symfony Console and Symfony Process. Tasks are persisted in the database via [`plugin-component-db`](https://github.com/SalesRender/plugin-component-db) and executed as background child processes through CLI commands.

Installation
------------

[](#installation)

```
composer require salesrender/plugin-component-queue
```

Requirements
------------

[](#requirements)

RequirementVersionPHP&gt;= 7.4.0ext-json\*symfony/console^5.3symfony/process^5.3salesrender/plugin-component-db^0.3.8xakepehok/path^0.2.1khill/php-duration^1.1Architecture overview
---------------------

[](#architecture-overview)

The queue operates as a two-command pattern:

1. **QueueCommand** -- a long-running daemon that polls the database for pending tasks and spawns background child processes (one per task) via `symfony/process`.
2. **QueueHandleCommand** -- invoked by the child process to load a single task by ID and execute the actual business logic.

Tasks are persisted as database models (extending `Task`) with built-in retry tracking (`TaskAttempt`). The queue command runs in a loop until memory usage exceeds the configured limit.

Key classes
-----------

[](#key-classes)

### `TaskAttempt`

[](#taskattempt)

Tracks retry state for a task.

**Namespace:** `SalesRender\Plugin\Components\Queue\Models\Task`

MethodSignatureDescription`__construct``__construct(int $limit, int $interval)`Create attempt tracker with max retries and interval (seconds) between attempts`getLastTime``getLastTime(): ?int`Unix timestamp of last attempt, or `null` if never attempted`getNumber``getNumber(): int`Current attempt number (starts at 0)`getLimit``getLimit(): int`Maximum number of attempts allowed`setLimit``setLimit(int $limit): void`Override the attempt limit`getInterval``getInterval(): int`Interval in seconds between retries`setInterval``setInterval(int $interval): void`Override the retry interval`getLog``getLog(): string`Log message from the last attempt`attempt``attempt(string $log): void`Record an attempt: increments number, sets lastTime to `time()`, saves log`isSpent``isSpent(): bool`Returns `true` when all attempts have been exhausted (`number >= limit`)### `Task` (abstract)

[](#task-abstract)

Abstract database model representing a queued task. Extends `Model` from [`plugin-component-db`](https://github.com/SalesRender/plugin-component-db).

**Namespace:** `SalesRender\Plugin\Components\Queue\Models\Task`

MethodSignatureDescription`__construct``__construct(TaskAttempt $attempt)`Generates UUID, captures current `PluginReference` from `Connector`, sets `createdAt``getPluginReference``getPluginReference(): ?PluginReference`Returns the plugin reference (companyId, alias, pluginId) or `null``schema``static schema(): array`Database schema with fields: `companyId`, `pluginAlias`, `pluginId`, `createdAt`, `attemptLastTime`, `attemptNumber`, `attemptLimit`, `attemptInterval`, `attemptLog`Inherited from `Model`: `save()`, `delete()`, `findById()`, `findByCondition()`, `freeUpMemory()`, `tableName()`.

### `QueueCommand` (abstract)

[](#queuecommand-abstract)

Long-running daemon command that polls for tasks and spawns child processes.

**Namespace:** `SalesRender\Plugin\Components\Queue\Commands`

MethodSignatureDescription`__construct``__construct(string $name, int $limit, int $maxMemoryInMb = 25)`Sets command name to `{name}:queue`, concurrency limit, and max memory`findModels``abstract findModels(): ModelInterface[]`**Must be implemented.** Return array of task models ready to be processed`handleQueue``handleQueue(ModelInterface $model): bool`Spawns a child process: `php console.php {name}:handle {id}``startedLog``startedLog(ModelInterface $model, OutputInterface $output): void`Logs "Process started" message; override for custom logging`execute``execute(InputInterface $input, OutputInterface $output): int`Main loop: mutex lock, poll for models, spawn processes, until memory limit**CLI option:** `--disable-mutex` (`-dm`) -- disables file-based mutex that prevents duplicate instances.

**Environment variable:** `LV_PLUGIN_PHP_BINARY` -- path to the PHP binary used to spawn child processes.

### `QueueHandleCommand` (abstract)

[](#queuehandlecommand-abstract)

Command invoked by child processes to handle a single task.

**Namespace:** `SalesRender\Plugin\Components\Queue\Commands`

MethodSignatureDescription`__construct``__construct(string $name)`Sets command name to `{name}:handle`The `execute` method must be implemented in subclasses. Receives `id` as a required argument (`$input->getArgument('id')`).

Usage
-----

[](#usage)

### 1. Define a Task model

[](#1-define-a-task-model)

Create a concrete task class that extends `Task`. Pass a `TaskAttempt` with the desired retry limit and interval.

From `plugin-logistic-eushipments` -- a simple task with 100 retries and 600-second interval:

```
use SalesRender\Plugin\Components\Queue\Models\Task\Task;
use SalesRender\Plugin\Components\Queue\Models\Task\TaskAttempt;

final class BindingSyncTask extends Task
{
    public function __construct()
    {
        parent::__construct(new TaskAttempt(100, 600));
    }

    public function getAttempt(): TaskAttempt
    {
        return $this->attempt;
    }
}
```

From [`plugin-core-chat`](https://github.com/SalesRender/plugin-core-chat) -- a task carrying additional data (Chat object), with custom serialization:

```
use SalesRender\Plugin\Components\Queue\Models\Task\Task;
use SalesRender\Plugin\Components\Queue\Models\Task\TaskAttempt;

class ChatSendTask extends Task
{
    protected Chat $chat;

    public function __construct(Chat $chat)
    {
        parent::__construct(new TaskAttempt(100, 10));
        $this->chat = $chat;
    }

    public function getChat(): Chat
    {
        return $this->chat;
    }

    public function getAttempt(): TaskAttempt
    {
        return $this->attempt;
    }

    protected static function beforeWrite(array $data): array
    {
        $data = parent::beforeWrite($data);
        $data['chat'] = json_encode($data['chat']);
        return $data;
    }

    protected static function afterRead(array $data): array
    {
        $data = parent::afterRead($data);
        $data['chat'] = Chat::parseFromArray(json_decode($data['chat'], true));
        return $data;
    }

    public static function schema(): array
    {
        return array_merge(parent::schema(), [
            'chat' => ['TEXT', 'NOT NULL'],
        ]);
    }
}
```

### 2. Implement QueueCommand

[](#2-implement-queuecommand)

Override `findModels()` to query pending tasks from the database. Use Medoo conditions to filter by `attemptLastTime` and `attemptInterval` so that tasks are retried only after the interval has elapsed.

From [`plugin-core-chat`](https://github.com/SalesRender/plugin-core-chat):

```
use SalesRender\Plugin\Components\Queue\Commands\QueueCommand;
use Medoo\Medoo;

class ChatSendQueueCommand extends QueueCommand
{
    public function __construct()
    {
        parent::__construct(
            'chatSendQueue',
            $_ENV['LV_PLUGIN_CHAT_SEND_QUEUE_LIMIT'] ?? 100,
            25
        );
    }

    protected function findModels(): array
    {
        ChatSendTask::freeUpMemory();
        $condition = [
            'OR' => [
                'attemptLastTime' => null,
                'attemptLastTime[
