Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Event Loop Laravel Package

revolt/event-loop

Revolt is a rock-solid event loop for concurrent PHP 8.1+ apps using fibers. It enables non-blocking I/O with synchronous code, serving as a minimal, shared scheduler base for libraries like Amp and ReactPHP.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package with Composer:

composer require revolt/event-loop

Requires PHP 8.1+ (fibers are mandatory). Begin with the official docs at revolt.run—especially the Suspend & Resume guide, which explains how to block a fiber without blocking the entire process. Start with EventLoop::run() to bootstrap your event loop and use EventLoop::getSuspension() inside a fiber to suspend execution until resumed (e.g., after I/O completes).

First use case: run a simple non-blocking timer in a fiber:

EventLoop::run(function (): void {
    EventLoop::defer(fn() => fwrite(STDOUT, "Hello after tick\n"));
    
    $suspension = EventLoop::getSuspension();
    EventLoop::delay(1000, fn() => $suspension->resume());
    $suspension->suspend(); // Pauses *this fiber* only
});

Implementation Patterns

  • Fiber-local context: Use FiberLocal to carry request-scoped data (e.g., request ID, user context) across suspensions without passing it explicitly:

    $context = new FiberLocal();
    $context->set('requestId', uniqid());
    // Later, even across suspensions:
    $id = $context->get('requestId');
    
  • Suspending & resuming manually: Encapsulate async operations (HTTP, DB, streams) by creating a suspension, initiating the operation, and resuming in a callback:

    function waitForFile(string $path, int $timeoutMs = 1000): ?string {
        $suspension = EventLoop::getSuspension();
        $fd = fopen($path, 'r');
        if ($fd === false) throw new RuntimeException("Failed to open $path");
    
        $timer = EventLoop::delay($timeoutMs, fn() => $suspension->resume(null));
        $watcher = EventLoop::onReadable($fd, fn() => [
            $data = stream_get_contents($fd),
            $suspension->resume($data),
            EventLoop::cancel($timer),
            EventLoop::cancel($watcher),
            fclose($fd),
        ]);
    
        return $suspension->suspend();
    }
    
  • Cooperative concurrency: Run multiple I/O tasks concurrently without threads:

    EventLoop::run(static function (): void {
        $tasks = [];
        foreach (['https://api-a.com', 'https://api-b.com'] as $url) {
            $tasks[] = (function () use ($url): void {
                // ... simulate async HTTP call with suspension ...
            })();
        }
        // All tasks suspend and yield control, letting others proceed
        EventLoop::run(static fn() => EventLoop::getSuspension()->suspend());
    });
    
  • Integration with libraries: Libraries like Amp, ReactPHP, or custom HTTP clients can use revolt/event-loop as their underlying scheduler—no need to wrap promises or callbacks if targeting PHP 8.1+. Focus on Suspension and FiberLocal for low-level async primitives.

Gotchas and Tips

  • Never forget to resume suspensions: If a suspension is never resumed (e.g., due to a bug or early exit), it leaks memory and may hang the loop. Use EventLoop::onSignal(SIGINT, fn() => ...) to log pending suspensions via debug helpers (e.g., EventLoop::getSuspension()->getFiber()->getTraceAsString()).
  • Avoid nesting EventLoop::run(): Running the loop recursively (e.g., calling EventLoop::run() inside EventLoop::run()) leads to subtle bugs. Use defer(), delay(), or onReadable() instead to chain logic.
  • Resuming the same suspension multiple times is fatal: You’ll get UnhandledThrowable—always guard resumption or use flags ($resumed = false; if (!$resumed) { $resumed = true; $suspension->resume(); }).
  • Clean shutdowns: Handle uncaught exceptions and ensure timers/watches are cancelled before stopping. Use EventLoop::setErrorHandler() to log errors during shutdown where error contexts might otherwise be lost.
  • Driver introspection: Use EventLoop::getType(), getIdentifiers(), isEnabled() to debug driver selection. Need higher performance with many file descriptors? Install ext-uv or ext-ev and explicitly enable them.
  • FiberLocal cleanup: Call unset() when done to release memory (especially in long-running processes); FiberLocal holds references until explicitly unset or fiber ends.
  • Never suspend in destructors: Destructors may run after the loop stops; suspending there causes undefined behavior. Defer cleanup to onStop() or explicit shutdown hooks.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport