-
Notifications
You must be signed in to change notification settings - Fork 106
Description
Summary
While migrating to Bunny 0.6@dev I’m seeing two issues around consuming and shutdown:
- When I use a ReactPHP EventLoop while consuming, the first message is only consumed after ~15 seconds (reproducible). Without the loop, consuming starts immediately.
- My shutdown callback executes twice.
Environment
- PHP 8.4 (CLI)
- Bunny 0.6@dev — 0.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:
- First consumption starts ~15s after
consume()when the timer/loop is used. - Shutdown runs twice (
Closing...Closing...). - The process exits early (no
done) and I hit areact/asyncassertion:
Terminating because of uncaught exception:
assert(is_callable($ret))invendor/react/async/src/SimpleFiber.phpline 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?