PHPackages                             innmind/mantle - 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. [Queues &amp; Workers](/categories/queues)
4. /
5. innmind/mantle

Abandoned → [innmind/async](/?search=innmind%2Fasync)ArchivedLibrary[Queues &amp; Workers](/categories/queues)

innmind/mantle
==============

Async orchestration

2.1.0(2y ago)03.6k[6 issues](https://github.com/Innmind/mantle/issues)4MITPHPPHP ~8.2

Since Feb 11Pushed 10mo ago1 watchersCompare

[ Source](https://github.com/Innmind/mantle)[ Packagist](https://packagist.org/packages/innmind/mantle)[ Docs](http://github.com/innmind/mantle)[ RSS](/packages/innmind-mantle/feed)WikiDiscussions develop Synced today

READMEChangelog (4)Dependencies (6)Versions (7)Used By (4)

Mantle
======

[](#mantle)

[![Build Status](https://github.com/innmind/mantle/workflows/CI/badge.svg?branch=master)](https://github.com/innmind/mantle/actions?query=workflow%3ACI)[![codecov](https://camo.githubusercontent.com/aa433a41db396c3e6443252570b7ae5e827d0d4dd6de5b28212af76d6a84b67b/68747470733a2f2f636f6465636f762e696f2f67682f696e6e6d696e642f6d616e746c652f6272616e63682f646576656c6f702f67726170682f62616467652e737667)](https://codecov.io/gh/innmind/mantle)[![Type Coverage](https://camo.githubusercontent.com/1298c0e774bfdcf04269ad0e42c9657857b48f0b0a5eee18b4cd06d481830370/68747470733a2f2f73686570686572642e6465762f6769746875622f696e6e6d696e642f6d616e746c652f636f7665726167652e737667)](https://shepherd.dev/github/innmind/mantle)

Important

This package has been replaced by .

Abstraction on top of `Fiber`s to coordinate multiple tasks asynchronously.

The goal is to easily move the execution of any code built using [`innmind/operating-system`](https://packagist.org/packages/innmind/operating-system) from a synchronous context to an async one. This means that it's easier to experiment running a piece of code asynchronously and then move back if the experiment is not successful. This also means that you can test each part of an asynchronous system synchronously.

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

[](#installation)

```
composer require innmind/mantle
```

Usage
-----

[](#usage)

```
use Innmind\Mantle\{
    Forerunner,
    Task,
    Source\Continuation,
};
use Innmind\OperatingSystem\{
    Factory,
    OperatingSystem,
};
use Innmind\Filesystem\Name;
use Innmind\HttpTransport\Success;
use Innmind\Http\{
    Request,
    Method,
    ProtocolVersion,
};
use Innmind\Url\{
    Url,
    Path,
};
use Innmind\Immutable\Sequence;

$run = Forerunner::of(Factory::build());
[$users] = $run(
    [0, 0, false],
    static function(array $carry, OperatingSystem $os, Continuation $continuation, Sequence $results): Continuation {
        [$users, $finished, $launched] = $carry;

        if (!$launched) {
            return $continuation
                ->carryWith([$users, $finished, true])
                ->launch(Sequence::of(
                    Task::of(
                        static fn(OperatingSystem $os): int => $os
                            ->remote()
                            ->http()(Request::of(
                                Url::of('http://some-service.tld/users/count'),
                                Method::get,
                                ProtocolVersion::v11,
                            ))
                            ->map(static fn(Success $success): string => $success->response()->body()->toString())
                            ->match(
                                static fn(string $response): int => (int) $response,
                                static fn() => throw new \RuntimeException('Failed to count the users'),
                            ),
                    ),
                    Task::of(
                        static fn(OperatingSystem $os): int => $os
                            ->filesystem()
                            ->mount(Path::of('some/directory/'))
                            ->get(Name::of('users.csv'))
                            ->map(static fn($file) => $file->content()->lines())
                            ->match(
                                static fn(Sequence $lines) => $lines->reduce(
                                    0,
                                    static fn(int $total): int => $total + 1,
                                ),
                                static fn() => throw new \RuntimeException('Users file not found'),
                            ),
                    ),
                ));
        }

        $finished += $results->size();
        $users = $results->reduce(
            $users,
            static fn(int $total, int $result): int => $total + $result,
        );
        $continuation = $continuation->carryWith([$users, $finished, $launched]);

        if ($finished === 2) {
            $continuation = $continuation->terminate();
        }

        return $continuation;
    },
);
```

This example counts a number of `$users` coming from 2 sources.

The `Forerunner` object behaves as a *reduce* operation, that's why it has 2 arguments: a carried value and a reducer (called a source in this package).

The carried value here is an array that holds the number of fetched users, the number of finished tasks and whether it already launched the tasks or not.

The source will launch 2 tasks if not already done; the first one does an HTTP call and the second one counts the number of lines in a file. The source will be called again once a task finishes and their results will be available inside the fourth argument `$results`, it will add the number of finished tasks and the number of users to the carried value array. If both tasks are finished then the source calls `$continuation->terminate()` to instruct the loop to stop.

When the source calls `->terminate()` and that all tasks are finished then `$run()` returns the carried value. Here it will assign the aggregation of both tasks results to the value `$users`.

> **Note**As long as you use the `$os` abstraction passed as arguments the system will automatically suspend your code when necessary. This means that you don't even need to think about it.

> **Note**The source `callable` is also run asynchronously. This means that you can use it to build a socket server and wait indefinitely for new connections without impacting the execution of already started tasks.

> **Warning**Do NOT return the `$os` variable outside of the tasks or the source as it may break your code.

> **Note**Since this package has been designed by only passing arguments (no global state) it means that you can compose the use of `Forerunner`, this means that you can run a new instance of `Forerunner` inside a task and it will behave transparently. (Although this feature as not been tested yet!)

Limitations
-----------

[](#limitations)

### Signals

[](#signals)

Signals like `SIGINT`, `SIGTERM`, etc... that are normally handled via `$os->process()->signals()` is not yet supported. This may result in unwanted behaviours.

### HTTP calls

[](#http-calls)

Currently HTTP calls are done via `curl` but it can't be integrated in the same loop as other streams. To allow the coordination of multiple tasks when doing HTTP calls the system use a timeout of `10ms` and switches between tasks at this max rate.

To fix this limitation a new implementation entirely based on PHP streams needs to be created.

Meanwhile if your goal is to make multiple concurrent HTTP calls you don't need this package. [`innmind/http-transport`](https://packagist.org/packages/innmind/http-transport) already support concurrent calls on it's own (without the limitation mentionned above).

### SQL queries

[](#sql-queries)

SQL queries executed via `$os->remote()->sql()` are still executed synchronously.

To fix this limitation a new implementation entirely based on PHP streams needs to be created.

### Number of tasks

[](#number-of-tasks)

It seems that the current implementation of this package has a [limit of around 10K concurrent tasks](https://twitter.com/baptouuuu/status/1720092619496378741) before it starts slowing down drastically.

###  Health Score

35

—

LowBetter than 77% of packages

Maintenance39

Infrequent updates — may be unmaintained

Popularity17

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity62

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

Total

5

Last Release

846d ago

Major Versions

1.1.0 → 2.0.02023-11-05

PHP version history (2 changes)1.0.0PHP ~8.1

1.1.0PHP ~8.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/851425?v=4)[Baptiste Langlade](/maintainers/Baptouuuu)[@Baptouuuu](https://github.com/Baptouuuu)

---

Top Contributors

[![Baptouuuu](https://avatars.githubusercontent.com/u/851425?v=4)](https://github.com/Baptouuuu "Baptouuuu (68 commits)")

---

Tags

async

###  Code Quality

Static AnalysisPsalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/innmind-mantle/health.svg)

```
[![Health](https://phpackages.com/badges/innmind-mantle/health.svg)](https://phpackages.com/packages/innmind-mantle)
```

###  Alternatives

[amphp/amp

A non-blocking concurrency framework for PHP applications.

4.4k133.8M435](/packages/amphp-amp)[react/socket

Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP

1.3k135.6M459](/packages/react-socket)[revolt/event-loop

Rock-solid event loop for concurrent PHP applications.

92553.8M226](/packages/revolt-event-loop)[spatie/async

Asynchronous and parallel PHP with the PCNTL extension

2.8k5.0M45](/packages/spatie-async)[react/dns

Async DNS resolver for ReactPHP

537133.1M104](/packages/react-dns)[amphp/parallel

Parallel processing component for Amp.

85251.9M98](/packages/amphp-parallel)

PHPackages © 2026

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