PHPackages                             profi-tech/tsqm-php - 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. profi-tech/tsqm-php

ActiveLibrary

profi-tech/tsqm-php
===================

Simple and reliable task runner

v1.1.0(1mo ago)7496↓33.3%1MITPHPPHP &gt;=8.2CI passing

Since May 27Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/profi-tech/tsqm-php)[ Packagist](https://packagist.org/packages/profi-tech/tsqm-php)[ RSS](/packages/profi-tech-tsqm-php/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (18)Versions (27)Used By (0)

[![CI](https://github.com/profi-tech/tsqm-php/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/profi-tech/tsqm-php/actions/workflows/ci.yml)

What is TSQM?
=============

[](#what-is-tsqm)

TSQM is a low-level PHP library for transactional and reliable execution of code involving external calls, service requests, database queries, etc. In case of an error, the code can be retried, or if retries are not feasible, it could be “compensated”.

How low is "low-level"?
-----------------------

[](#how-low-is-low-level)

One of the main requirements for the library was its ability to integrate into any PHP codebase starting from version 7.4. TSQM provides basic classes and methods that can be embedded into almost any project or framework. The main classes are:

- **Task**: A class-wrapper for PHP code, allowing to specify retry policies, arguments and other execution options.
- **TSQM Engine**: Schedules, executes, retries, and handles errors for tasks.

⚠️ **Attention!** TSQM does not work out of the box; it requires integration and configuration.

Basic usage
===========

[](#basic-usage)

1. Install
----------

[](#1-install)

```
composer require profi-tech/tsqm-php

```

2. Database Initialization
--------------------------

[](#2-database-initialization)

TSQM requires a table in a MySQL or SQLite database. You can get the SQL to create this table using:

```
vendor/bin/tsqm-db
```

Or by specifying the vendor and table name:

```
vendor/bin/tsqm-db mysql my_tsqm_table
vendor/bin/tsqm-db sqlite my_tsqm_table
```

Run the generated SQL on the database you want TSQM to work with.

3. Configuring TSQM engine
--------------------------

[](#3-configuring-tsqm-engine)

```
$dsn = "";
$username = "";
$password = "";
$pdo = new PDO($dsn, $username, $password);

$tsqm = new Tsqm\Tsqm($pdo);
...
```

You could tune TSQM engine by passing an instance of `Tsqm\Options` to the constructor:

```
$tsqm = new Tsqm\Tsqm(
  $pdo,
  (new Tsqm\Options())
    ->setTable("my_tsqm_table") // Name of the table where tasks are stored
    ->setLogger(new MyLogger()) // PSR-3 compatible logger
    ->setContainer($container) // DI container e.g. PHP-DI
    ->setQueue(new MyQueue()) // Queue implementation
    ->setForceSyncRuns(true) // Force synchronous runs for debugging and unit testing
    ->setMaxNestingLevel(10) // Maximum number of nested transactions
    ->setMaxGeneratorTasks(10) // Maximum number of tasks in a generator
);
```

4. Creating a task
------------------

[](#4-creating-a-task)

To create tasks, you need to create a new `Task` object and set the necessary fields:

```
$task = (new Tsqm\Task())
  ->setCallable("greet")
  ->setArgs("John Doe");
```

The argument for `setCallable` could be:

- A callable object of a class with the `__invoke` method (recommended).
- Name of static method along with its class name e.g. `MyClass::myMethod`
- Name of global functions e.g. `MyGlobalFunction` (strongly not recommended).

⚠️ If you use callable objects, you need to set a DI container for the TSQM engine that implements `Psr\Container\ContainerInterface`. The callable object must be accessible in the container by its class name.

Task supports the following options:

- `setScheduledFor` — DateTime object with the scheduled execution time.
- `setWaitInterval` — Time interval to wait before starting a task.
- `setIsSecret` — if true, task args and results will be logged as secrets.
- `setTrace` — trace object to trace task execution via logs.

Also you could specify retry policy via `setRetryPolicy` and `RetryPolicy` object:

- `setMaxRetries` — Maximum number of retries.
- `setMinInterval` — Minimum interval between retries in milliseconds or a string that can be parsed by DateTime::modify().
- `setBackoffFactor` — factor to multiply the interval between retries.
- `setUseJitter` — if true, a random value will be added to the interval between retries.

Example:

```
class Greeter {
  public function __invoke(string $name): string {
    return "Hello, $name!";
  }
}

class MyContainer implements Psr\Container\ContainerInterface {
  ...
}

$tsqm = new Tsqm\Tsqm(
  $pdo,
  (new Tsqm\Options())
    ->setContainer(new MyContainer())
);

$task = (new Tsqm\Task())
  ->setCallable(new Greeter())
  ->setArgs("John Doe")
  ->setRetryPolicy(
    (new Tsqm\RetryPolicy())
      ->setMaxRetries(3)
      ->setMinInterval(5000)
  );

...
```

5. Running a task
-----------------

[](#5-running-a-task)

To execute a task, you need to call the `run` method:

```
$task = $tsqm->run($task);
```

The execution result will be available in the `$task` object:

```
echo "Task id: ".$task->getId();
if ($task->isFinished()) {
    if (!$task->hasError()) {
      $result = $task->getResult();
    } else {
      $error = $task->getError();
    }
}
```

6. Retries and scheduled tasks
------------------------------

[](#6-retries-and-scheduled-tasks)

A task does not complete if:

- An error occurred and the task has a retry policy set.
- The task has a future execution time set via the `setScheduledFor` option.

Tasks that need to be retried can be run through the `poll` method:

```
$tsqm->poll(
  100, // Number of tasks to poll
  30, // Time in seconds to "step back" from the current time (useful for the fallback mode)
  10 // Idle time in seconds if no tasks found
);
```

Although the `poll` method can perform scheduled runs, for production it should be used only as a fallback to the main queue-based approach.

7. Queues
---------

[](#7-queues)

To integrate queues in TSQM, you need to implement the `Tsqm\Queue\QueueInterface` and add the implementing class during the TSQM engine initialization:

```
class MyQueue implements Tsqm\Queue\QueueInterface {

  public function enqueue(string $taskName, string $taskId, DateTime $scheduledFor): void {
    ... put $taskId into your favorite message broker like RabbitMQ, Apache Kafka etc.
  }

  /**
   * @param callable(string $taskId): ?Task $callback
   */
  public function listen(string $taskName, callable $callback): void {
    ... listen to your favorite message broker like RabbitMQ, Apache Kafka etc
    ... receive $taskId and call $callback with it
  }
}

$tsqm = new Tsqm\Tsqm(
  $pdo,
  (new Tsqm\Options())
    ->setQueue(new MyQueue())
);
```

The TSQM engine will automatically call the `enqueue` method of your class if the task needs to be executed later.

To receive and handle the tasks, call the `listen` method in a separate script:

```
$tsqm->listen($taskName);
```

8. Transactions
---------------

[](#8-transactions)

In addition to simple tasks, TSQM supports transactions; you can implement a task where the callable returns a generator of tasks. All standard logics will apply, such as error handling, retries, etc. An example of implementing a transaction:

```
class Greet
{
  ...
  public function __invoke(string $name): Generator
  {
    $valid = yield (new Task())
      ->setCallable($this->validateName)
      ->setArgs($name);
    if (!$valid) {
      return false;
    }

    $greeting = yield (new Task())
      ->setCallable($this->createGreeting)
      ->setArgs($name);

    try {
      $greeting = yield (new Task())
        ->setCallable($this->purchase)
        ->setArgs($greeting)
        ->setIsSecret(true)
        ->setRetryPolicy(
          (new RetryPolicy())
            ->setMaxRetries(3)
            ->setMinInterval(5000)
      );
    } catch (Exception $e) {
      yield (new Task())
        ->setCallable($this->revertGreeting)
        ->setArgs($greeting);
      return false;
    }

    return $greeting;
  }
}
...
$task = (new Task())
  ->setCallable(new Greet(...))
  ->setArgs("John Doe");

$task = $tsqm->run($task);
```

If the `purchase` task fails, the transaction execution will stop and retry according to the policy "3 attempts every 5 seconds". If all attempts fail, the `rollback` task will be executed.

⚠️ **Attention!** TSQM caches the results of completed tasks and checks the determinism of the transaction during execution, meaning it is safe to retry the call as many times as needed.

9. Logging
----------

[](#9-logging)

TSQM logs every step of task and transaction execution. To access these logs, you need to provide a class that implements `Psr\Log\LoggerInterface` e.g. [Monolog](https://github.com/Seldaek/monolog)

```
$tsqm = new Tsqm\Tsqm(
 $pdo,
 (new Tsqm\Options())
   ->setLogger(
     // instance of logger
   )
);
```

Limitations and warnings
========================

[](#limitations-and-warnings)

- TSQM is generally not a Workflow Engine but a library for reliably executing PHP code with external calls. However, you can try to use the library as a workflow engine, provided that all task code is stored and executed within the same codebase.
- Task data is deleted from the database after execution, as the persistent storage is used only to ensure transactional consistency.
- For errors, only the class, message, and code are stored.
- TSQM is lightweight and fast but has not been tested under heavy loads.

###  Health Score

49

—

FairBetter than 95% of packages

Maintenance87

Actively maintained with recent releases

Popularity24

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity63

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~30 days

Recently: every ~140 days

Total

23

Last Release

53d ago

Major Versions

v0.7.1 → v1.0.02026-02-10

PHP version history (2 changes)v0.0.1-alphaPHP &gt;=7.4

v1.0.0PHP &gt;=8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/65c0ec3ac0e6370e95c6ad6af3a5a9a364d376255846a570489763d99a888381?d=identicon)[chernovev@team.profi.ru](/maintainers/chernovev@team.profi.ru)

---

Top Contributors

[![em1nx](https://avatars.githubusercontent.com/u/2318127?v=4)](https://github.com/em1nx "em1nx (77 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/profi-tech-tsqm-php/health.svg)

```
[![Health](https://phpackages.com/badges/profi-tech-tsqm-php/health.svg)](https://phpackages.com/packages/profi-tech-tsqm-php)
```

###  Alternatives

[laravel/framework

The Laravel Framework.

34.7k509.9M17.0k](/packages/laravel-framework)[cakephp/cakephp

The CakePHP framework

8.8k18.5M1.6k](/packages/cakephp-cakephp)[nelmio/api-doc-bundle

Generates documentation for your REST API from attributes

2.3k63.6M233](/packages/nelmio-api-doc-bundle)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.3M152](/packages/sulu-sulu)[ecotone/ecotone

Supporting you in building DDD, CQRS, Event Sourcing applications with ease.

558549.8k17](/packages/ecotone-ecotone)[civicrm/civicrm-core

Open source constituent relationship management for non-profits, NGOs and advocacy organizations.

728272.9k20](/packages/civicrm-civicrm-core)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
