From 1a61b18b2d0ac14f99188eccfeac008a5067dacc Mon Sep 17 00:00:00 2001 From: Fred Heinecke Date: Sun, 27 Apr 2025 09:52:43 +0000 Subject: [PATCH] Fix Backend service crash when RabbitMQ queues are predeclared Signed-off-by: Fred Heinecke --- back/src/Kyoo.RabbitMq/RabbitProducer.cs | 30 +++++++++++++++++++++-- back/src/Kyoo.RabbitMq/ScannerProducer.cs | 30 +++++++++++++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/back/src/Kyoo.RabbitMq/RabbitProducer.cs b/back/src/Kyoo.RabbitMq/RabbitProducer.cs index f3809dfd..f7433dd7 100644 --- a/back/src/Kyoo.RabbitMq/RabbitProducer.cs +++ b/back/src/Kyoo.RabbitMq/RabbitProducer.cs @@ -30,7 +30,8 @@ public class RabbitProducer { _channel = rabbitConnection.CreateModel(); - _channel.ExchangeDeclare("events.resource", ExchangeType.Topic); + if (!doesExchangeExist(rabbitConnection, "events.resource")) + _channel.ExchangeDeclare("events.resource", ExchangeType.Topic); _ListenResourceEvents("events.resource"); _ListenResourceEvents("events.resource"); _ListenResourceEvents("events.resource"); @@ -39,7 +40,8 @@ public class RabbitProducer _ListenResourceEvents("events.resource"); _ListenResourceEvents("events.resource"); - _channel.ExchangeDeclare("events.watched", ExchangeType.Topic); + if (!doesExchangeExist(rabbitConnection, "events.watched")) + _channel.ExchangeDeclare("events.watched", ExchangeType.Topic); IWatchStatusRepository.OnMovieStatusChangedHandler += _PublishWatchStatus("movie"); IWatchStatusRepository.OnShowStatusChangedHandler += _PublishWatchStatus("show"); IWatchStatusRepository.OnEpisodeStatusChangedHandler += _PublishWatchStatus( @@ -47,6 +49,30 @@ public class RabbitProducer ); } + /// + /// Checks if the exchange exists. Needed to avoid crashing when re-declaring an existing + /// queue with different parameters. + /// + /// The RabbitMQ connection. + /// The name of the channel. + /// True if the queue exists, false otherwise. + private bool doesExchangeExist(IConnection rabbitConnection, string exchangeName) + { + // If the queue does not exist when QueueDeclarePassive is called, + // an exception will be thrown. According to the docs, when this + // happens, the entire channel should be thrown away. + using var channel = rabbitConnection.CreateModel(); + try + { + channel.ExchangeDeclarePassive(exchangeName); + return true; + } + catch (Exception) + { + return false; + } + } + private void _ListenResourceEvents(string exchange) where T : IResource, IQuery { diff --git a/back/src/Kyoo.RabbitMq/ScannerProducer.cs b/back/src/Kyoo.RabbitMq/ScannerProducer.cs index 1034a2c5..0411e250 100644 --- a/back/src/Kyoo.RabbitMq/ScannerProducer.cs +++ b/back/src/Kyoo.RabbitMq/ScannerProducer.cs @@ -31,8 +31,34 @@ public class ScannerProducer : IScanner public ScannerProducer(IConnection rabbitConnection) { _channel = rabbitConnection.CreateModel(); - _channel.QueueDeclare("scanner", exclusive: false, autoDelete: false); - _channel.QueueDeclare("scanner.rescan", exclusive: false, autoDelete: false); + if (!doesQueueExist(rabbitConnection, "scanner")) + _channel.QueueDeclare("scanner", exclusive: false, autoDelete: false); + if (!doesQueueExist(rabbitConnection, "scanner.rescan")) + _channel.QueueDeclare("scanner.rescan", exclusive: false, autoDelete: false); + } + + /// + /// Checks if the queue exists. Needed to avoid crashing when re-declaring an existing + /// queue with different parameters. + /// + /// The RabbitMQ connection. + /// The name of the channel. + /// True if the queue exists, false otherwise. + private bool doesQueueExist(IConnection rabbitConnection, string queueName) + { + // If the queue does not exist when QueueDeclarePassive is called, + // an exception will be thrown. According to the docs, when this + // happens, the entire channel should be thrown away. + using var channel = rabbitConnection.CreateModel(); + try + { + channel.QueueDeclarePassive(queueName); + return true; + } + catch (Exception) + { + return false; + } } private Task _Publish(T message, string queue = "scanner")