-
Notifications
You must be signed in to change notification settings - Fork 384
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Laravel Octane with Rabbitmq - broken pipe or closed connection error and CHANNEL_ERROR - expected 'channel.open'(60, 40) #460
Comments
@TahsinAbrar You managed to solve the problem? I have the same mistake. How did you solve the problem? |
The issue occurs because this package is not able to reconnect when the channel is automatically closed due to inactivity from RabbitMQ. As with laravel octane, we are planning to do connection pooling, thus, it is not able to reconnect when the error occurred. To do a quick fix to resolve the issue, I had to manually connect AMQP. The issue resolving code will be found here: Though I am planning to find a solution with this package, that's why I didn't make it in package structure yet. We will get the idea with this code if you want a work-around. |
Since the issue was marked fix in te previous PRs, I am closing it. Re-open if still experiencing the issue. |
@khepin I had the same issue till now but I managed a solution for it and I wanted to share it here so it can be a reference for anyone will have the same issue. Describe Bug Solution
here we can see that I configured rabbitmq as one of the connectors in Laravel so it can be made as a singleton to create a new connection every time a replica is created to serve a request.
|
@johnabil so the close connection is happening on the publish side right? Not on consumers? While constantly re-creating solutions would work, I'd rather we explore a different approach. The great thing about Octane is to not have to constantly re-build expensive resources and an SSL connection is about as expensive as it gets to create. Would prefer we try establishing a new connection only when necessary. |
@khepin yes it mainly happens on the publish side but I think it won't happen on the consumers. The consumers has it's own connection when you run On the other Side what happens on the publish side is that when you want to publish a message it creates a connection to the rabbit server and after the message is published the connection is not closed but it can be unexpectedly closed depending on the server specs and configs so what happens with octane is that when the original container create a connection to publish a message it won't be closed but after a while the rabbitmq server shuts the connection cause of inactivity or maybe other reasons, every new clone from the original container in octane tries to publish a message it gives the broke pipe error and even if you tried to handle this exception and create another connection it will still have the same error cause you are trying to create a new connection on the cloned app not the original one and that is the core of the problem and to make the octane app re-establish a connection you need then to restart the server so the original container will be started and will have a new connection established. Solution From what I read from you the approach you want to try is to track if the connection is down in the original container only then you want to create a new connection on the original container. Suggestion The approach that I did which is while constantly I am creating an SSL connection it has cons that it will be expensive to create SSL connection every time a cloned app makes a connection but it has a slight positive thing the you will have by max 2 connections only on the rabbitmq server. one is from the original container and the other is from the cloned app that gets created to serve each request but the cloned app connection will be closed after the request is terminated.
|
This is just a proof of concept right now, but I believe something like this would work: https://github.com/vyuldashev/laravel-queue-rabbitmq/compare/octane?expand=1 |
That's great I hope this can be merged soon this is a really way better than creating connections and I will see if I can help to improve this merge request so it can be released soon. |
@khepin @johnabil
As an alternative we could (just as Horizon) support Octane by adding the extra class. |
@adm-bome I think theoretically this is possible but we should look into after the timeout cause when it times out or the connection was closed by any cause it can not reestablish a new connection. |
<?php
namespace App\Queue\Octane;
use PhpAmqpLib\Exception\AMQPChannelClosedException;
use PhpAmqpLib\Exception\AMQPConnectionClosedException;
use PhpAmqpLib\Exception\AMQPProtocolChannelException;
use VladimirYuldashev\LaravelQueueRabbitMQ\Queue\RabbitMQQueue as BaseRabbitMQQueue;
class RabbitMQQueue extends BaseRabbitMQQueue
{
private function reconnect()
{
$this->connection->reconnect();
$this->channel = $this->connection->channel();
}
private function withReconnect(callable $callback, callable $exceptionCallback = null)
{
try {
return $callback();
} catch (AMQPConnectionClosedException|AMQPChannelClosedException|AMQPProtocolChannelException $exception) {
$this->reconnect();
return $exceptionCallback ? $exceptionCallback() : $callback();
}
}
/**
* {@inheritdoc}
*/
public function pushRaw($payload, $queue = null, array $options = []): int|string|null
{
return $this->withReconnect(fn () => parent::pushRaw($payload, $queue, $options));
}
/**
* {@inheritdoc}
*/
public function laterRaw($delay, string $payload, $queue = null, int $attempts = 0): int|string|null
{
return $this->withReconnect(fn () => parent::laterRaw($delay, $payload, $queue, $attempts));
}
/**
* {@inheritdoc}
*/
public function bulk($jobs, $data = '', $queue = null): void
{
$this->withReconnect(fn () => parent::bulk($jobs, $data, $queue), fn () => $this->getChannel()->publish_batch());
}
} with config 'connections' => [
// ...
'rabbitmq-octane' => [
// ...
'worker' => \App\Queue\Octane\RabbitMQQueue::class
],
// ...
], |
@adm-bome we should add rabbitmq connection in 'warm' => [
...Octane::defaultServicesToWarm(),
'rabbitmq',
], IMPORTANT NOTEAs the code mentioned in the documentation.
<?php
namespace App\Queue;
use PhpAmqpLib\Exception\AMQPChannelClosedException;
use PhpAmqpLib\Exception\AMQPConnectionClosedException;
use VladimirYuldashev\LaravelQueueRabbitMQ\Queue\RabbitMQQueue as BaseRabbitMQQueue;
class RabbitMQQueue extends BaseRabbitMQQueue
{
protected function publishBasic($msg, $exchange = '', $destination = '', $mandatory = false, $immediate = false, $ticket = null): void
{
try {
parent::publishBasic($msg, $exchange, $destination, $mandatory, $immediate, $ticket);
} catch (AMQPConnectionClosedException|AMQPChannelClosedException) {
$this->reconnect();
parent::publishBasic($msg, $exchange, $destination, $mandatory, $immediate, $ticket);
}
}
protected function publishBatch($jobs, $data = '', $queue = null): void
{
try {
parent::publishBatch($jobs, $data, $queue);
} catch (AMQPConnectionClosedException|AMQPChannelClosedException) {
$this->reconnect();
parent::publishBatch($jobs, $data, $queue);
}
}
protected function createChannel(): AMQPChannel
{
try {
return parent::createChannel();
} catch (AMQPConnectionClosedException) {
$this->reconnect();
return parent::createChannel();
}
}
}
'connections' => [
// ...
'rabbitmq' => [
// ...
/* Set to a class if you wish to use your own. */
'worker' => \App\Queue\RabbitMQQueue::class,
],
// ...
], |
- issue #460 - rework based on [comment](#531 (comment))
@johnabil the master was updated. (not yet a release) #528 Could you test a bit. see what it brings for your use-cases.
But in the new version the connection class is created without opening a real connection and channel, until an action (like: push, pop , size) is executed. so the cached class should not have an open connection, which is already dead. it should connect and open a channel normally each time. |
!! UPDATE !!
<?php
namespace App\Queue;
use PhpAmqpLib\Exception\AMQPChannelClosedException;
use PhpAmqpLib\Exception\AMQPConnectionClosedException;
use PhpAmqpLib\Exception\AMQPProtocolChannelException;
use VladimirYuldashev\LaravelQueueRabbitMQ\Queue\RabbitMQQueue as BaseRabbitMQQueue;
class RabbitMQQueue extends BaseRabbitMQQueue
{
protected function publishBasic($msg, $exchange = '', $destination = '', $mandatory = false, $immediate = false, $ticket = null): void
{
try {
parent::publishBasic($msg, $exchange, $destination, $mandatory, $immediate, $ticket);
} catch (AMQPConnectionClosedException|AMQPChannelClosedException) {
$this->reconnect();
parent::publishBasic($msg, $exchange, $destination, $mandatory, $immediate, $ticket);
}
}
protected function publishBatch($jobs, $data = '', $queue = null): void
{
try {
parent::publishBatch($jobs, $data, $queue);
} catch (AMQPConnectionClosedException|AMQPChannelClosedException) {
$this->reconnect();
parent::publishBatch($jobs, $data, $queue);
}
}
protected function createChannel(): AMQPChannel
{
try {
return parent::createChannel();
} catch (AMQPConnectionClosedException) {
$this->reconnect();
return parent::createChannel();
}
}
} with config 'connections' => [
// ...
'rabbitmq-with-reconnect' => [
// ...
'worker' => \App\Queue\RabbitMQQueue::class
],
// ...
], |
Describe the bug
While pushing the event data to RabbitMQ via using this package, I am getting these two errors:
Steps To Reproduce
This scenario is happening after a certain time of app deployment, that means - this issue is not happening all the time. After a certain period (exactly not sure how much) of time, these errors are popping up.
Current behavior
Weirdly, this error occurs every other times. And, when getting success, the queue data are getting lost even though it does not provide any error (not available in rabbitmq queue).
Additional context
I have also checked the RabbitMQ memory usage and it is 5% of total memory.
The text was updated successfully, but these errors were encountered: