Skip to content

0.6@dev: Consumption delayed ~15s with EventLoop timer; shutdown callback runs twice #192

@pulmer-cp

Description

@pulmer-cp

Summary

While migrating to Bunny 0.6@dev I’m seeing two issues around consuming and shutdown:

  1. When I use a ReactPHP EventLoop while consuming, the first message is only consumed after ~15 seconds (reproducible). Without the loop, consuming starts immediately.
  2. My shutdown callback executes twice.

Environment

  • PHP 8.4 (CLI)
  • Bunny 0.6@dev0.6.x-dev

Minimal working baseline (consumption starts immediately)

use Bunny\Channel;
use Bunny\Message;

$startTime = microtime(true);
$queueName = 'foo_queue';

$channel = $client->channel();

echo "Declare queue $queueName\n";
$channel->queueDeclare($queueName);

echo "Publish message 'bar' to queue $queueName\n";
$channel->publish('bar1', [], '', $queueName);
$channel->publish('bar2', [], '', $queueName);

echo "Start consuming queue $queueName\n";
$channel->consume(
    function (Message $message, Channel $channel) use ($startTime): void {
        $elapsedTime = microtime(true) - $startTime;
        echo "Consumed (after " . number_format($elapsedTime, 1) . " sec): " . $message->content . "\n";
        $channel->ack($message);
    },
    $queueName
);

echo "[*] Waiting for messages. To exit press CTRL+C\n";

Attempt to emulate bounded runtime via EventLoop timer (problematic)

use React\EventLoop\Loop;

$loop = Loop::get();
$loop->addTimer(
    20,
    function () use ($loop, $channel, $client, $queueName) {
        echo "Closing...";
        try {
            $channel->close();
            $client->channel()->queueDelete($queueName, false, true);
            $client->disconnect();
        } catch (Throwable $e) {
            echo $e->getMessage();
        }

        $loop->stop();
        echo "done\n";
    }
);
$loop->run();

Observed output (PHP 8.4):

Declare queue foo_queue
Publish message 'bar' to queue foo_queue
Start consuming queue foo_queue
Consumed (after 15.0 sec): bar1
Consumed (after 15.0 sec): bar2
Closing...Closing...

Problems:

  1. First consumption starts ~15s after consume() when the timer/loop is used.
  2. Shutdown runs twice (Closing...Closing...).
  3. The process exits early (no done) and I hit a react/async assertion:

Terminating because of uncaught exception: assert(is_callable($ret)) in vendor/react/async/src/SimpleFiber.php line 72


Expected behavior

If using an EventLoop timer to close resources

  • consuming should start immediately (no ~15s delay)
  • the shutdown callback should run once
  • the process should exit cleanly after printing done.

Workaround for closing issue

Make close() blocking and idempotent. If Channel::close() (and/or the client’s disconnect()) completes all protocol teardown synchronously before returning and guards against re-entrancy, the second invocation of the closing logic would be a no-op.

Userland workaround that helped: Adding an $isClosing lock in the timer callback ensures the shutdown path runs only once; with this lock in place, closing proceeds cleanly. The ~15s consumption delay still remains, so this only addresses the double-invoke/done issues.


Questions

Is this a misuse of the EventLoop with Bunny 0.6’s fiber-backed client, or a bug in Bunny 0.6@dev around consumption timing/shutdown?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions