flytachi/winter-thread
Composer 安装命令:
composer require flytachi/winter-thread
包简介
A lightweight process engine for PHP — Java-like control of background tasks as isolated OS processes, without heavy extensions (no swoole/pthreads/parallel).
关键字:
README 文档
README
Winter Thread is a process engine for PHP: a clean, object-oriented, Java-like API for running and controlling background tasks as isolated OS processes — for parallel and long-running work.
It's an engine — the foundation you build on. A small, dependable core, not a batteries-included framework: the layer your queues, pools, schedulers and workers sit on top of. You bring the higher-level concurrency; the engine handles the hard, boring parts — spawning, signals, isolation, transports.
A
Threadhere is a process, not a PHP thread. The name is a deliberate nod to a familiar API — just as Python'smultiprocessing.Processmirrors its threading interface. EveryThreadis one fully isolated OS process wearing a clean, thread-like face (start(),join(),isAlive()) — so there's no shared state to corrupt and nothing to leak between tasks.
No heavy extensions. Unlike pthreads, ext-parallel, or Swoole, it needs
no ZTS build and no exotic runtime — just proc_open and the standard POSIX
extensions (ext-pcntl, ext-posix) that ship with nearly every PHP install.
Each task runs in a fresh, isolated PHP process, so there is no shared state to
corrupt and no inherited connections to break.
Key Features
- No heavy extensions: No swoole / parallel / pthreads, no ZTS build — just
proc_open+ standard POSIX. Runs on a normal PHP install. - Clean process isolation: Each task runs in a brand-new PHP process — no inherited DB connections, sockets, or global state to corrupt.
- Fluent, Object-Oriented API: Manage background processes as objects.
- Full Process Control:
start(),join(),pause(),resume(),terminate(), andkill(). - Advanced Process Naming: Identify your processes easily with namespaces, names, and tags.
- Safe by Default: Output goes to
/dev/nullby default — no Broken pipe risk for fire-and-forget jobs. - Swoole / Event-Loop Compatible: Pluggable payload transports (pipe, temp-file, shared-memory); the default engine auto-detects an active Swoole runtime and avoids fd corruption under
SWOOLE_HOOK_ALL. - Zombie-free fire-and-forget: Optional detached mode (
fork+setsid) reparents workers to init, so long-lived parents (FPM, daemons) never accumulate zombies. - Pluggable backend: Swap the payload transport or the whole spawn strategy through a single
Launcher— build custom backends (Docker, SSH, …) without touchingThread. - Java-like API: Familiar method names like
isAlive()andjoin()for an easy learning curve.
Requirements
- PHP >= 8.4
ext-pcntlext-posixopis/closure^4.5 (required; enables safe serialization of anonymous classes and closures)ext-shmop(optional; only for the shared-memory transport)
Installation
composer require flytachi/winter-thread
Quick Start
<?php require 'vendor/autoload.php'; use Flytachi\Winter\Thread\Runnable; use Flytachi\Winter\Thread\Thread; // 1. Define your task by implementing Runnable. // Logic inside run() executes in a separate process. class VideoProcessingTask implements Runnable { public function __construct(private string $videoFile) {} public function run(array $args): void { $quality = $args['quality'] ?? 'high'; // output goes to /dev/null by default — use outputTarget for logging sleep(5); // simulate encoding } } // 2. Create a Thread with optional metadata for OS process identification. $thread = new Thread( new VideoProcessingTask('movie.mp4'), 'Media', // namespace 'VideoProcessor', // name 'job-42' // tag ); // 3. Start the thread. // Default outputTarget='/dev/null' — safe for fire-and-forget. // Pass outputTarget: '/path/to/file.log' to capture output. // Pass outputTarget: null ONLY when actively reading via readOutput(). $pid = $thread->start(['quality' => 'hd']); echo "Processing started (PID: $pid)\n"; // Main script continues immediately. echo "Doing other work...\n"; // 4. Optionally wait for the task to finish. $exitCode = $thread->join(); echo "Task finished with exit code: $exitCode\n";
Configuration — the Launcher
Configuration goes through a single Launcher, bound once at bootstrap with
Thread::bindLauncher(). When you bind nothing, a self-configuring CliLauncher
is used (CliLauncher::adaptive()), adapting to the current environment (CLI / FPM).
use Flytachi\Winter\Thread\Launch\CliLauncher; use Flytachi\Winter\Thread\Payload\TempFileTransport; // Zero-config: a self-configuring CliLauncher is the default — nothing to do. $thread = new Thread(new MyTask()); $thread->start(); // Explicit configuration when you need it: Thread::bindLauncher(new CliLauncher( binaryPath: '/usr/bin/php', runnerPath: __DIR__ . '/vendor/flytachi/winter-thread/wRunner', transport: new TempFileTransport(), // omit to auto-detect per launch secret: 'your-signing-secret', // signs serialized closures )); // Custom backend (Docker/SSH/…): implement Launcher and bind it directly. Thread::bindLauncher(new MyCustomLauncher());
Swoole / Event-Loop Compatibility
When its transport is left unset, CliLauncher::adaptive() picks a pipe-free
transport (TempFileTransport) if it detects an active Swoole runtime — pipe file
descriptors from proc_open do not survive SWOOLE_HOOK_ALL intact.
Swoole support is under active development. A safe transport is necessary but not sufficient for running from inside a live Swoole coroutine worker: native
proc_opencontends with the Swoole reactor over the process file-descriptor table. Treat in-coroutine dispatch as experimental for now. Plain CLI and FPM are unaffected. See docs/08.
| Transport | Delivery | Parent pipe fd | Requires |
|---|---|---|---|
PipeTransport |
stdin pipe (default in CLI) | yes | — |
TempFileTransport |
temp file as stdin | none | — |
ShmTransport |
shared memory | none | ext-shmop |
Detached (zombie-free) fire-and-forget
For a long-lived parent (FPM worker, daemon) that dispatches background tasks and never
joins them, pass detached: true. The launcher exits immediately and the real worker is
reparented to init (pid 1), so no zombie ever accumulates under the parent:
$thread = new Thread(new SendEmailBatch($ids)); $thread->start(detached: true); // returns at once; worker owned by init
Signal control still works via the worker's self-reported PID (write getmypid() from
inside the task to your own store), since the engine's control model is PID-based.
Output Modes
$outputTarget |
Use case |
|---|---|
'/dev/null' (default) |
Fire-and-forget: safe, output discarded |
'/path/to/file.log' |
Persistent logging for staging/production |
null (explicit) |
Piped to parent: read via readOutput() / readError() |
Note: With
null,join()andreap()drain the pipes internally while they wait, so a barejoin()never deadlocks on a large output — andreadOutput()after it returns the full buffered output. Use an explicitreadOutput()poll loop only when you want the output live as it is produced.
Process Control
$thread->pause(); // SIGSTOP — suspend execution $thread->resume(); // SIGCONT — resume after pause $thread->terminate(); // SIGTERM — graceful shutdown request $thread->kill(); // SIGKILL — force kill (last resort) $thread->interrupt(); // SIGINT — Ctrl+C equivalent $thread->isAlive(); // bool — check if still running
Running Tests
Tests come in two tiers (mirroring the winter-kernel layout):
Default — runs on any machine; unsupported extensions self-skip:
composer install composer test # base (class correctness) + working (scenarios) composer test-base # only unit-level class correctness composer test-working # only end-to-end scenarios composer test-detail # human-readable (testdox) output
Containered — heavy, environment-specific checks (leak / timing / nested / battle-run, with Cli / FPM / Swoole), run inside Docker across a list of PHP versions:
tests/run-container.sh # default versions: 8.4 8.5 tests/run-container.sh 8.4 # a single version tests/run-container.sh 8.4 8.5 8.6 # a custom list # Or, inside an environment that already has swoole/shmop: composer test-container # phpunit --testsuite container
CI (.github/workflows/ci.yml) runs the default suite via setup-php and the container
suite via the bundled tests/docker/Dockerfile, on a PHP 8.4 / 8.5 matrix.
Documentation
Full documentation lives in /docs:
- Introduction — philosophy, the no-heavy-ext story, when to use it
- Installation & Requirements
- Quickstart — a complete parallel example in 5 minutes
- Basic Usage
- Output & Debugging
- Process Control & Lifecycle — signals, graceful shutdown
- The Launcher
- Payload Transports
- Detached Mode
- Security
- Architecture & Internals
- Patterns — pools, returning results, retries
- Troubleshooting
- API Reference
- Testing
Contributing
Contributions are welcome! Please submit a pull request or open an issue for bugs, questions, or feature requests.
License
This library is open-source software licensed under the MIT license.
flytachi/winter-thread 适用场景与选型建议
flytachi/winter-thread 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 509 次下载、GitHub Stars 达 1, 最近一次更新时间为 2025 年 12 月 18 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「threads」 「process」 「background」 「signals」 「worker」 「parallel」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 flytachi/winter-thread 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 flytachi/winter-thread 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 flytachi/winter-thread 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Doctrine implementation of the MetaborStd (Statemachine) for PHP 8.2+
Provides a background task processing module.
Shell command module for PHP.
Swoole server process management
This Bundle provides threaded comment functionality for Symfony applications
Inbox pattern process implementation for your Laravel Applications
统计信息
- 总下载量: 509
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 2
- 点击次数: 33
- 依赖项目数: 1
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-12-18