# Pheanstalk: PHP Client for Beanstalkd Work Queues

> Pheanstalk is a typed PHP client for beanstalkd 1.12 and later, aimed at applications that need producer, worker, or both roles for a work queue. Its explicit command flow keeps protocol state visible, while connection handling and broker deployment remain the application operator's responsibility.

**pheanstalk/pheanstalk** — PHP client for beanstalkd queue

- Repository: https://github.com/pheanstalk/pheanstalk
- Stars: 1,918 · Forks: 280
- Language: PHP
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/pheanstalk-pheanstalk

## Pheanstalk's Role in a Beanstalkd Application

Pheanstalk solves the client-side problem of communicating with beanstalkd from PHP. Beanstalkd provides a work queue, while Pheanstalk translates PHP calls into that service's protocol and represents tube names and job IDs as typed values. Its users include PHP producers that place work into queues, PHP consumers that reserve and process jobs, and applications that perform both roles.

The documented compatibility boundary is specific: the README describes Pheanstalk 5 as a pure PHP 8.1+ client for beanstalkd 1.12 and later. It also says the project was almost completely rewritten across 2021, 2022, and 2023, with fully typed APIs, strict static-analysis goals, and separate components for different roles. Pheanstalk is therefore a protocol client, not a complete queue platform. The README assumes that a beanstalkd endpoint exists. Its Docker Compose file starts beanstalkd containers for repository development and testing, but that file does not document a production deployment procedure.

Pheanstalk is most relevant when beanstalkd is already part of the architecture or when its tube, reserve, delete, release, touch, and bury semantics match the required workflow. It is a poor fit if the application expects a database-backed library that installs and operates its own queue server. The README does not describe replication, message history, queue queries, or an operations dashboard. It also does not establish that Pheanstalk supports the HTTP API expected by many managed queue services.

The separation of client and server responsibilities has a direct operational consequence. Installing Pheanstalk does not, by itself, install a production broker, configure persistence, or define authentication controls for it. An adopting team still needs a reachable beanstalkd instance and a deployment process suited to its infrastructure.

## Producer State Changes and Documented Job Options

The producer API depends on a connection whose current tube is meaningful. Pheanstalk is created for a host, a `TubeName` value is constructed, and `useTube()` selects the destination before `put()` sends a payload. The second producer call shows that callers can supply data, priority, delay, and time-to-release values. Delaying a job makes it unavailable for immediate reservation, while the time-to-release value establishes the server-side processing window used during reservation.

This design exposes protocol state instead of hiding it inside a combined operation such as `putInTube`. The project history says those older side-effecting functions were removed because switching tubes and placing a job changed the connection state in a way that was difficult to reason about. In the README example, `useTube()` is called before both operations. Repeating the selection may appear redundant to someone accustomed to stateless APIs, but it keeps the required state transition visible.

The producer payload can be a plain string or application-generated JSON. The README does not document automatic serialization, payload schema validation, idempotency keys, transactional publication, or dead-letter routing. Those concerns remain with the application. It also does not define behavior for an empty payload, an unavailable server, or a partially completed `put()` call. An application team should therefore avoid treating the examples as evidence of delivery guarantees beyond the documented command sequence.

The API still offers enough control for scheduled and prioritized work through its named arguments. Priority uses `Pheanstalk::DEFAULT_PRIORITY` in the example, delay is set to `30`, and `timeToRelease` is set to `60`. The project history confirms that the fourth parameter of `put()` changed from `ttr` to `timeToRelease`, which matters to callers using named arguments.

## Reservation, Leases, and Worker Recovery

A worker explicitly watches its chosen tube before reserving work. The documented `reserve()` call blocks until a job is produced. Once the job arrives, the worker reads its payload, performs work, calls `touch()` if processing continues beyond the available window, and calls `delete()` after success. The catch block in the introductory example calls `release()` so another worker can retry the job.

The touch operation matters when processing takes long enough for the job's time-to-release window to expire. Without a timely touch, beanstalkd can make the job available for another worker while the original process is still executing it. That can create duplicate work. Pheanstalk exposes the protocol operation, but application-level idempotency is a separate concern. The README does not prescribe an idempotency strategy or an exactly-once processing model.

The runner in the project history uses `reserveWithTimeout(50)` rather than a blocking reservation. It deletes successful jobs and calls `bury()` when a `Throwable` occurs. Its stated connection policy is that connection errors cause the process to exit so a task manager can restart it. This is a deliberate operational boundary. Pheanstalk does not conceal dropped connections behind an automatic, unlimited socket retry loop.

The examples also establish a practical distinction between `release()` and `bury()`. Release makes the job available for another attempt. Bury removes it from normal consideration without deleting it. However, the README does not document a rollback command, a buried-job inspection interface, or a procedure for returning buried jobs. Operators should not interpret `bury()` as a complete archival workflow without consulting separate beanstalkd operations documentation.

## Running Pheanstalk Producers and Workers for the First Time

The README does not provide a Composer installation command or a Composer configuration snippet. It directs readers to the Packagist package `pda/pheanstalk`, so installation must be resolved through that package listing and the application's Composer setup. Version selection also needs care: the README describes the rewritten client as Pheanstalk 5, while the repository's recent release list uses v8.0.x. The README does not explain that version relationship.

The first producer sequence can be placed in a PHP script connected to the documented default host. The following code selects `testtube` and places two payloads in it. The second payload is generated as JSON and receives the documented priority, delay, and time-to-release values.

```php
use Pheanstalk\Pheanstalk;
use Pheanstalk\Values\TubeName;

$pheanstalk = Pheanstalk::create('127.0.0.1');
$tube = new TubeName('testtube');
$pheanstalk->useTube($tube);
$pheanstalk->put("job payload goes here\n");
```

A worker must select the same tube before waiting for a job. This is the core of the README worker example, with the application work reduced to reading the payload.

```php
use Pheanstalk\Pheanstalk;
use Pheanstalk\Values\TubeName;

$pheanstalk = Pheanstalk::create('127.0.0.1');
$tube = new TubeName('testtube');
$pheanstalk->watch($tube);
$job = $pheanstalk->reserve();
$jobPayload = $job->getData();
```

The worker blocks at `reserve()` until a job is available, then exposes the payload through `getData()`. After processing, successful workers call `delete($job)`, while the introductory failure path calls `release($job)`. Long-running workers call `touch($job)` before the server-side processing window expires.

The README documents `composer test` for running the test suite. It first requires Docker Compose, and the repository's `docker-compose.yml` supplies beanstalkd services plus a PHPUnit environment. This command belongs to contributor or integration testing, not to production installation.

## Connection Failures and the Persistent Socket Trade-off

Pheanstalk dropped persistent connections because reusing a TCP connection can leave the beanstalkd protocol in an incorrect state. The project history gives a concrete example: after `PUT 0 4000`, the server expects 4,000 payload bytes. If PHP fails during that write, a later request may receive the same socket and append more bytes to an incomplete job. Reusing such a connection could therefore corrupt the next command's interpretation.

Dropped-connection detection is another constraint. The README says some socket implementations cannot enable TCP keepalive. Without it, the operating system may wait as long as 15 minutes to identify a silent broken connection. Implementations that support read and write timeouts can detect failures earlier, but beanstalkd can also remain silent during a legitimate idle interval. The documented options are to catch connection exceptions and reconnect, or to use a reservation timeout shorter than the socket read and write timeouts.

This policy makes connection state visible, but it places worker supervision outside Pheanstalk. The included systemd unit runs `/usr/bin/php /var/www/html/worker.php` and uses `Restart=always` to restart the process. The README explicitly says the unit does not cover every deployment scenario. It does not define graceful shutdown, concurrency limits, retry counts, readiness checks, or deployment-user permission requirements beyond the shown service configuration.

The older Pheanstalk 4 history lists support for streams, socket, and `fsockopen` socket implementations. That flexibility matters when deciding whether the available PHP runtime can support the timeout behavior a worker expects. The README does not provide a current matrix showing which implementation is selected by default or how to configure one in an application.

## Pheanstalk Versus a Hosted Queue API Client

A real alternative approach is a PHP HTTP client for a managed queue service. Such a client sends network requests to a provider's endpoint and delegates authentication, routing, retention, and broker operation to that service. Pheanstalk instead communicates with beanstalkd over its socket protocol and exposes connection state such as the selected tube.

The distinction affects deployment. A managed queue client can remove the responsibility for running a broker, but its API and delivery semantics will differ. Pheanstalk does not require a vendor-hosted endpoint and provides direct commands such as `delete()`, `release()`, `bury()`, and `touch()`. At the same time, the client does not supply server durability, backups, replication, monitoring, or access control. Those concerns belong to the beanstalkd deployment.

Pheanstalk may fit a PHP codebase that has deliberately selected beanstalkd and values direct control over tube and job commands. A managed-service HTTP client may fit a team that wants the provider to operate queue infrastructure and prefers documented HTTP authentication. The repository README does not compare either approach in detail, so this distinction comes from their documented architecture rather than a project-authored feature matrix.

## Pheanstalk Releases, Upgrade Changes, and MIT Terms

The repository is not archived, and its last push was on 2026-09-28. Its listed recent releases are v8.0.0 on 2025-10-06, v8.0.1 on 2025-10-13, and v8.0.2 on 2025-11-11. These dates show recent development activity, although the README does not define a support policy or a formal release cadence.

The version labels need reconciliation before upgrading an existing application. Code written against earlier APIs may use strings for tube names, chain `watch`, `ignore`, and reservation calls, or pass the fourth `put()` argument as `ttr`. The documented migration replaces chaining with separate calls, requires `TubeName`, and renames the argument to `timeToRelease`. Constants also moved from `PheanstalkInterface` to interfaces such as `SocketFactoryInterface` and `PheanstalkPublisherInterface`.

Those changes can require source edits rather than only a Composer dependency update. Applications using unnamed positional arguments may behave differently from code using the old parameter name. Static analysis and tests can catch unresolved interfaces, but the README does not document a complete upgrade checklist for v8.

The repository declares the MIT license. Its standard terms permit use, modification, distribution, and sublicensing under stated conditions, while preserving the copyright and license notice and supplying the disclaimer. That is a summary rather than legal advice. An organization should review its own attribution and distribution policies before including Pheanstalk in a product.

## Conclusion

PHP applications already using beanstalkd can adopt Pheanstalk when explicit connection state and an externally operated beanstalkd service fit their architecture. Do not choose it from the README alone for a queue that needs persistent HTTP connections, server lifecycle tooling, or a documented one-command installation. Before adoption, verify the installed package version against the differing version references in the README and recent release list, then test the producer and worker lifecycle against the intended beanstalkd deployment.

## FAQ

### What PHP and beanstalkd versions does Pheanstalk support?

The README describes Pheanstalk 5 as a pure PHP 8.1+ client for beanstalkd 1.12 and later. The repository's recent release list uses v8.0.x, but the README does not explain the version relationship.

### How should a Pheanstalk worker handle a long-running job?

Call `touch()` while processing continues so beanstalkd does not make the job available before the worker finishes. Call `delete()` after success, or use the documented `release()` or `bury()` paths according to the intended retry policy.

### Does Pheanstalk install beanstalkd for production use?

The README does not document a production installation procedure or a command that provisions beanstalkd. Its `docker-compose.yml` defines beanstalkd services for repository development and test workflows, not a documented production deployment.

## Sources

- [Issues](https://github.com/pheanstalk/pheanstalk/issues)
- [License: MIT](https://github.com/pheanstalk/pheanstalk/blob/master/LICENSE)
- [pheanstalk/pheanstalk on GitHub](https://github.com/pheanstalk/pheanstalk)
- [README](https://github.com/pheanstalk/pheanstalk/blob/master/README.md)
- [Releases](https://github.com/pheanstalk/pheanstalk/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pheanstalk-pheanstalk
