PHPackages                             mangoweb/pg-deadlock-playground - 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. [Debugging &amp; Profiling](/categories/debugging)
4. /
5. mangoweb/pg-deadlock-playground

ActiveLibrary[Debugging &amp; Profiling](/categories/debugging)

mangoweb/pg-deadlock-playground
===============================

v0.1.1(9y ago)1715[1 issues](https://github.com/mangoweb-backend/pg-deadlock-playground/issues)MITPHPPHP ~7.1

Since Feb 23Pushed 9y ago3 watchersCompare

[ Source](https://github.com/mangoweb-backend/pg-deadlock-playground)[ Packagist](https://packagist.org/packages/mangoweb/pg-deadlock-playground)[ RSS](/packages/mangoweb-pg-deadlock-playground/feed)WikiDiscussions master Synced today

READMEChangelogDependencies (2)Versions (3)Used By (0)

PostgreSQL Deadlock Playground
==============================

[](#postgresql-deadlock-playground)

A simple tool for playing with multiple concurrent PostgreSQL transactions and testing whether and under what circumstances they may result in deadlock. The verifier class can automatically test given scenario with all possible orderings.

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

[](#installation)

```
composer require mangoweb/pg-deadlock-playground
```

Documentation
-------------

[](#documentation)

### Creating Scenario

[](#creating-scenario)

A scenario is an ordered sequence of steps. Every step is defined as a tuple of connection ID and query.

```
$scenario = new Mangoweb\PgDeadlockPlayground\Scenario();
$scenario->addStep(0, 'SELECT 123');     // first execute SELECT 123 on connection #0
$scenario->addStep(1, 'SELECT 456');     // then execute SELECT 456 on connection #1
$scenario->addStep(1, 'SELECT 789');     // then execute SELECT 789 on connection #1
$scenario->addStep(2, 'SELECT \'abc\''); // then execute SELECT 'abc' on connection #2
$scenario->addStep(0, 'SELECT NOW()');   // then execute SELECT NOW on connection #0
```

At any point you can dump the scenario with `$scenario->dump()` call. In this case it will print

```
SELECT 123
               SELECT 456
               SELECT 789
                            SELECT 'abc'
SELECT NOW()

```

Alternatively you can create the same scenario with `Scenario::fromArray`

```
$scenario = Mangoweb\PgDeadlockPlayground\Scenario::fromArray([
    ['SELECT 123',   NULL,        NULL            ],
    [NULL,          'SELECT 456', NULL            ],
    [NULL,          'SELECT 789', NULL            ],
    [NULL,           NULL,        'SELECT \'abc\''],
    ['SELECT NOW()', NULL,        NULL            ],
]);
```

### Generating All Scenario Step Orderings

[](#generating-all-scenario-step-orderings)

To get all possible step orderings for given scenario call `$scenario->getAllOrderings()`. For example the following code

```
$scenario = Mangoweb\PgDeadlockPlayground\Scenario::fromArray([
	['SELECT 123',   NULL       ],
	[NULL,          'SELECT 456'],
	[NULL,          'SELECT 789'],
]);

foreach ($scenario->getAllOrderings() as $scenarioVariant) {
    $scenarioVariant->dump();
}
```

will output

```
SELECT 123
             SELECT 456
             SELECT 789
-----------------------
             SELECT 456
SELECT 123
             SELECT 789
-----------------------
             SELECT 456
             SELECT 789
SELECT 123

```

### Executing Scenario

[](#executing-scenario)

To execute a scenario you need an instance of `ScenarioExecutor`.

```
$executor = Mangoweb\PgDeadlockPlayground\ScenarioExecutor::create([
    'dbname' => 'deadlock_playground',
    'user' => 'postgres',
    'password' => '',
]);
```

Calling `$executor->execute($scenario)` will always return instance of `ScenarioExecutionResult`. You can inspect the result by calling `$result->dump()`.

```
$result = $executor->execute($scenario);
$result->dump();
```

### Understanding Results

[](#understanding-results)

The output of `$result->dump()` is similar to `$scenario->dump()` but each step is prefixed with important tag.

TagMeaning`OK`Query was successfully completed`FAILED`Query failed`WAITING...`Query execution has started but cannot be completed because it is waiting on a lock`...SUCCESS`A previously waiting query was successfully completed`...FAILURE`A previously waiting query failed`DELAYED`Query cannot yet be executed because the previous query is still waiting on a lockExample
-------

[](#example)

### Usage

[](#usage)

```
$config = [
    'host' => '127.0.0.1',
    'dbname' => 'deadlock_playground',
    'user' => 'postgres',
    'password' => '',
];

$initQueries = [
    'DROP TABLE IF EXISTS users',
    'CREATE TABLE users (id INTEGER NOT NULL, name TEXT NOT NULL)',
    'INSERT INTO users VALUES (1, \'Logan\')'
];

$executor = Mangoweb\PgDeadlockPlayground\ScenarioExecutor::create($config, $initQueries);
$verifier = new Mangoweb\PgDeadlockPlayground\ScenarioExpectationVerifier($executor);
$verifier->setVerbose();

$verifier->expectAlwaysOk(
    Scenario::fromArray([
        ['START TRANSACTION ISOLATION LEVEL REPEATABLE READ',   NULL],
        ['LOCK users IN SHARE MODE',                            NULL],
        ['SELECT * FROM users WHERE id = 1 FOR UPDATE',         NULL],
        ['COMMIT',                                              NULL],
        [NULL,                                                  'START TRANSACTION ISOLATION LEVEL REPEATABLE READ'],
        [NULL,                                                  'UPDATE users SET name = \'John\' WHERE id = 1'],
        [NULL,                                                  'COMMIT'],
    ])
);
```

### Output

[](#output)

```
...
SUCCESS: completed without error
in C:\Projects\deadlock-playground\examples\readme.php:25

   [OK]         START TRANSACTION ISOLATION LEVEL REPEATABLE READ
   [OK]         LOCK users IN SHARE MODE
   [OK]         SELECT * FROM users WHERE id = 1 FOR UPDATE
                                                                    [OK]         START TRANSACTION ISOLATION LEVEL REPEATABLE READ
   [OK]         COMMIT
                                                                    [OK]         UPDATE users SET name = 'John' WHERE id = 1
                                                                    [OK]         COMMIT
----------------------------------------------------------------------------------------------------------------------------------

SUCCESS: completed without error
in C:\Projects\deadlock-playground\examples\readme.php:25

   [OK]         START TRANSACTION ISOLATION LEVEL REPEATABLE READ
   [OK]         LOCK users IN SHARE MODE
   [OK]         SELECT * FROM users WHERE id = 1 FOR UPDATE
                                                                    [OK]         START TRANSACTION ISOLATION LEVEL REPEATABLE READ
                                                                    [WAITING...] UPDATE users SET name = 'John' WHERE id = 1
   [OK]         COMMIT
                                                                    [...SUCCESS]
                                                                    [OK]         COMMIT
...

```

###  Health Score

25

—

LowBetter than 36% of packages

Maintenance19

Infrequent updates — may be unmaintained

Popularity13

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 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 ~3 days

Total

2

Last Release

3410d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/6163a0eec16c2bfc9cce0c7c8801b5166cca9af81a146764676059a965044000?d=identicon)[JanTvrdik](/maintainers/JanTvrdik)

---

Top Contributors

[![JanTvrdik](https://avatars.githubusercontent.com/u/175109?v=4)](https://github.com/JanTvrdik "JanTvrdik (7 commits)")

---

Tags

deadlockplaygroundpostgresqltransactions

### Embed Badge

![Health badge](/badges/mangoweb-pg-deadlock-playground/health.svg)

```
[![Health](https://phpackages.com/badges/mangoweb-pg-deadlock-playground/health.svg)](https://phpackages.com/packages/mangoweb-pg-deadlock-playground)
```

###  Alternatives

[nette/caching

⏱ Nette Caching: library with easy-to-use API and many cache backends.

43719.1M394](/packages/nette-caching)[nette/mail

📧 Nette Mail: A handy library for creating and sending emails in PHP.

49310.1M268](/packages/nette-mail)[symplify/monorepo-builder

Not only Composer tools to build a Monorepo.

5275.7M110](/packages/symplify-monorepo-builder)[nette/component-model

⚛ Nette Component Model

28816.8M101](/packages/nette-component-model)[nette/security

🔑 Nette Security: provides authentication, authorization and a role-based access control management via ACL (Access Control List)

3779.6M307](/packages/nette-security)[ssch/typo3-rector

Instant fixes for your TYPO3 PHP code by using Rector.

2603.0M382](/packages/ssch-typo3-rector)

PHPackages © 2026

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