PHPackages                             pogo/async - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. pogo/async

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

pogo/async
==========

Request-scoped parallel PHP jobs for FrankenPHP.

0.0.1(2mo ago)05[1 PRs](https://github.com/y-l-g/pogo/pulls)MITGoPHP &gt;=8.4CI passing

Since May 16Pushed 1mo agoCompare

[ Source](https://github.com/y-l-g/pogo)[ Packagist](https://packagist.org/packages/pogo/async)[ RSS](/packages/pogo-async/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependenciesVersions (2)Used By (0)

Pogo
====

[](#pogo)

Request-scoped parallel PHP tasks for FrankenPHP.

Pogo lets one PHP request spawn independent tasks in FrankenPHP worker pools, await their results, and return a response after the fan-out/fan-in work is done. It is built for bounded work such as independent API calls, CPU work, or response fragments.

Pogo is not a queue. Tasks are tied to the current request. There is no persistence, retry system, delay API, scheduler, event loop, fiber abstraction, or framework adapter in the core module.

API
---

[](#api)

Pogo exposes three native PHP functions:

```
function pogo_spawn(string $class, array $args = [], string $pool = 'default'): int;
function pogo_await(int $task, float $timeout = 5.0): mixed;
function pogo_pool_size(string $pool = 'default'): int;
```

Example:

```
$price = pogo_spawn(FetchPrice::class, ['sku' => $sku], 'external_api');
$stock = pogo_spawn(FetchStock::class, ['sku' => $sku], 'external_api');
$tax = pogo_spawn(CalculateTax::class, ['sku' => $sku], 'cpu');

$response = [
    'price' => pogo_await($price, 2.0),
    'stock' => pogo_await($stock, 2.0),
    'tax' => pogo_await($tax, 2.0),
];
```

`pogo_await()` throws `RuntimeException` for unknown tasks, timeouts, worker failures, invalid worker responses, and task exceptions returned by the worker. `pogo_pool_size()` throws `RuntimeException` when Pogo is not configured or the pool name is unknown.

Task Contract
-------------

[](#task-contract)

There is no required Composer package and no required interface. A task class only needs to be autoloadable by your worker and expose a public `handle(array $args): mixed` method:

```
final class FetchPrice
{
    public function handle(array $args): array
    {
        return ['sku' => $args['sku'], 'price' => 42];
    }
}
```

Arguments and return values must be JSON-compatible. Resources, closures, cyclic data, and unserializable objects are unsupported.

Worker Contract
---------------

[](#worker-contract)

Your application owns the worker bootstrap. The worker receives:

```
['class' => App\FetchPrice::class, 'args' => ['sku' => 'A-100']]
```

and must return one of these JSON-compatible envelopes:

```
['ok' => true, 'result' => $value]
['ok' => false, 'error' => 'message']
```

The example worker in `example/worker.php` is a small production template: it boots the app, validates the payload, instantiates the class, calls `handle(array $args)`, and converts exceptions to the error envelope.

Caddy
-----

[](#caddy)

Configure Pogo as a FrankenPHP/Caddy global option. The top-level worker is the `default` pool. Add named pools when you need isolation for slow APIs, CPU-heavy tasks, or critical work.

```
{
    frankenphp

    pogo {
        worker worker.php
        num_threads 8
        max_wait 30s

        pool external_api {
            worker worker.php
            num_threads 16
            max_wait 10s
        }

        pool cpu {
            worker worker.php
            num_threads 4
            max_wait 60s
        }
    }
}
```

Pool directives:

- `worker`: PHP worker script. Required.
- `num_threads`: FrankenPHP worker thread count. Optional.
- `max_wait`: maximum wait for `SendMessage` before the task fails. Optional, default `30s`.

Task IDs are globally unique, so `pogo_await()` does not need the pool name.

Production Notes
----------------

[](#production-notes)

Use Pogo for tasks that can safely fail with the request or be retried by the caller. Keep tasks bounded by request timeouts and pool `max_wait` values.

Use separate pools for workloads with different latency or capacity profiles. For example, do not run slow third-party API calls and CPU-heavy transforms in the same worker pool unless they can block each other safely.

Call `pogo_await()` for every task you need. Unawaited tasks are canceled at request shutdown.

Example
-------

[](#example)

Build and run the included smoke app:

```
docker build -f example/Dockerfile -t pogo-example .
docker run --rm -p 8080:8080 pogo-example
curl http://localhost:8080
```

The response should show two sleeping tasks finishing in roughly one sleep duration, not the sum of both sleeps.

Build
-----

[](#build)

Build a FrankenPHP binary that includes Pogo with `xcaddy`:

```
FROM dunglas/frankenphp:builder AS builder

COPY --from=caddy:builder /usr/bin/xcaddy /usr/bin/xcaddy

RUN CGO_ENABLED=1 \
    XCADDY_SETCAP=1 \
    XCADDY_GO_BUILD_FLAGS="-ldflags='-w -s' -tags=nobadger,nomysql,nopgx" \
    CGO_CFLAGS="$(php-config --includes)" \
    CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
    xcaddy build \
        --output /usr/local/bin/frankenphp \
        --with github.com/dunglas/frankenphp=./ \
        --with github.com/dunglas/frankenphp/caddy=./caddy \
        --with github.com/y-l-g/pogo/module@main

FROM dunglas/frankenphp AS runner

COPY --from=builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp
```

Then copy your app, worker script, and `Caddyfile` into the runner image.

Test
----

[](#test)

Run the full example smoke check:

```
bash scripts/smoke-example.sh
```

```
docker run --rm \
  -v "$PWD/module:/module" \
  -w /module \
  dunglas/frankenphp:1.12.3-builder-php8.5.6-trixie \
  sh -lc 'CGO_ENABLED=1 \
    CGO_CFLAGS="-D_GNU_SOURCE $(php-config --includes)" \
    CGO_CPPFLAGS="$(php-config --includes)" \
    CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
    /usr/local/go/bin/go test ./... -tags=nobadger,nomysql,nopgx,nowatcher'
```

Package
-------

[](#package)

Go module: `github.com/y-l-g/pogo/module`

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance90

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity41

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

Unknown

Total

1

Last Release

69d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/559468?v=4)[y-l](/maintainers/y-l)[@Y-L](https://github.com/Y-L)

---

Top Contributors

[![y-l-g](https://avatars.githubusercontent.com/u/116063953?v=4)](https://github.com/y-l-g "y-l-g (14 commits)")

### Embed Badge

![Health badge](/badges/pogo-async/health.svg)

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

PHPackages © 2026

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