-
-
Notifications
You must be signed in to change notification settings - Fork 86
RG-T117 Chat fix, web ui fixes, rabbitmq fix #456
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,35 +34,46 @@ public static async Task<bool> VerifyAndCreateClients(string clientName) | |
|
|
||
| try | ||
| { | ||
| _factory = new ConnectionFactory() { HostName = ServiceBusConfig.RabbitHostname, UserName = ServiceBusConfig.RabbitUsername, Password = ServiceBusConfig.RabbbitPassword }; | ||
| _connection = await _factory.CreateConnectionAsync(clientName); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| Logging.LogException(ex); | ||
|
|
||
| if (!String.IsNullOrWhiteSpace(ServiceBusConfig.RabbitHostname2)) | ||
| // Re-check inside the lock: concurrent callers (e.g. several publishers recovering | ||
| // through ForceResetAsync at once) all pass the unsynchronized null check above and | ||
| // queue on the semaphore. Without this re-check each waiter would create its own | ||
| // IConnection in turn — orphaning the previous one undisposed and inflating the | ||
| // broker's connection count. Only the first acquirer may create the connection. | ||
| if (_connection == null) | ||
| { | ||
| try | ||
| { | ||
| _factory = new ConnectionFactory() { HostName = ServiceBusConfig.RabbitHostname2, UserName = ServiceBusConfig.RabbitUsername, Password = ServiceBusConfig.RabbbitPassword }; | ||
| _factory = new ConnectionFactory() { HostName = ServiceBusConfig.RabbitHostname, UserName = ServiceBusConfig.RabbitUsername, Password = ServiceBusConfig.RabbbitPassword }; | ||
| _connection = await _factory.CreateConnectionAsync(clientName); | ||
| } | ||
| catch (Exception ex2) | ||
| catch (Exception ex) | ||
| { | ||
| Logging.LogException(ex2); | ||
| Logging.LogException(ex); | ||
|
|
||
| if (!String.IsNullOrWhiteSpace(ServiceBusConfig.RabbitHostname3)) | ||
| if (!String.IsNullOrWhiteSpace(ServiceBusConfig.RabbitHostname2)) | ||
| { | ||
| try | ||
| { | ||
| _factory = new ConnectionFactory() { HostName = ServiceBusConfig.RabbitHostname3, UserName = ServiceBusConfig.RabbitUsername, Password = ServiceBusConfig.RabbbitPassword }; | ||
| _factory = new ConnectionFactory() { HostName = ServiceBusConfig.RabbitHostname2, UserName = ServiceBusConfig.RabbitUsername, Password = ServiceBusConfig.RabbbitPassword }; | ||
| _connection = await _factory.CreateConnectionAsync(clientName); | ||
| } | ||
| catch (Exception ex3) | ||
| catch (Exception ex2) | ||
| { | ||
| Logging.LogException(ex3); | ||
| throw; | ||
| Logging.LogException(ex2); | ||
|
|
||
| if (!String.IsNullOrWhiteSpace(ServiceBusConfig.RabbitHostname3)) | ||
| { | ||
| try | ||
| { | ||
| _factory = new ConnectionFactory() { HostName = ServiceBusConfig.RabbitHostname3, UserName = ServiceBusConfig.RabbitUsername, Password = ServiceBusConfig.RabbbitPassword }; | ||
| _connection = await _factory.CreateConnectionAsync(clientName); | ||
| } | ||
| catch (Exception ex3) | ||
| { | ||
| Logging.LogException(ex3); | ||
| throw; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -239,6 +250,43 @@ await channel.QueueDeclareAsync( | |
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Disposes the shared connection and clears cached state so the next CreateConnection call | ||
| /// builds a fresh one. Needed when the connection is open but unusable — e.g. its channel | ||
| /// numbers are exhausted (ChannelAllocationException) — which the IsOpen guards can never | ||
| /// detect. Raises ConnectionReset so cached declaration state is cleared. | ||
| /// </summary> | ||
| public static async Task ForceResetAsync() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Race condition in if (_connection == null)
{
await _semaphore.WaitAsync();
try
{
if (_connection == null) // re-check inside the lock: a prior holder may have already created it
{
_factory = new ConnectionFactory() { ... };
_connection = await _factory.CreateConnectionAsync(clientName);
}
}Prompt for LLMTalk to Kody by mentioning @kody Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction. |
||
| { | ||
| IConnection connection; | ||
|
|
||
| await _semaphore.WaitAsync(); | ||
| try | ||
| { | ||
| connection = _connection; | ||
| _connection = null; | ||
| _factory = null; | ||
| } | ||
| finally | ||
| { | ||
| _semaphore.Release(); | ||
| } | ||
|
|
||
| RaiseConnectionReset(); | ||
|
|
||
| if (connection != null) | ||
| { | ||
| try | ||
| { | ||
| await connection.DisposeAsync(); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| Logging.LogException(ex); | ||
| } | ||
| } | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| public static async Task<IConnection> CreateConnection(string clientName) | ||
| { | ||
| if (_connection == null) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,8 +32,51 @@ public class RabbitInboundEventProvider : IRabbitInboundEventProvider | |
|
|
||
| public async Task Start(string clientName, string queueName) | ||
| { | ||
| await VerifyAndCreateClients(clientName); | ||
| await StartMonitoring(queueName); | ||
| // Dispose any channel from a previous Start (the host watchdog re-calls Start after a | ||
| // disconnect). Disposal also removes it from automatic-recovery tracking, so a late | ||
| // connection recovery can't resurrect the old consumer alongside the new one and | ||
| // double-deliver events. | ||
| await DisposeChannelAsync(); | ||
|
|
||
| if (!await VerifyAndCreateClients(clientName)) | ||
| return; | ||
|
|
||
| // _channel stays null when the connection couldn't be created; skip monitoring so the | ||
| // caller sees IsConnected() == false and can retry instead of an NRE killing the task. | ||
| if (_channel == null) | ||
| return; | ||
|
|
||
| try | ||
| { | ||
| await StartMonitoring(queueName); | ||
| } | ||
| catch | ||
| { | ||
| // If consumer registration fails the channel is open but consumes nothing, so | ||
| // IsConnected() would report healthy and the host watchdog would never rebuild. | ||
| // Tear the channel down (nulled field makes IsConnected() false) and rethrow for | ||
| // the caller's retry path. | ||
| await DisposeChannelAsync(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unhandled exception in Kody rule violation: Handle async operations with proper error handling Prompt for LLMTalk to Kody by mentioning @kody Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction. |
||
| throw; | ||
| } | ||
| } | ||
|
|
||
| private async Task DisposeChannelAsync() | ||
| { | ||
| var channel = _channel; | ||
| _channel = null; | ||
|
|
||
| if (channel == null) | ||
| return; | ||
|
|
||
| try | ||
| { | ||
| await channel.DisposeAsync(); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| Logging.LogException(ex); | ||
| } | ||
| } | ||
|
|
||
| private async Task<bool> VerifyAndCreateClients(string clientName) | ||
|
|
@@ -55,6 +98,13 @@ private async Task<bool> VerifyAndCreateClients(string clientName) | |
| catch (Exception ex) | ||
| { | ||
| Framework.Logging.LogException(ex); | ||
|
|
||
| // Exhausted channel numbers leave the connection open but unusable, and the host | ||
| // watchdog's retry would get the same connection back forever — reset it so the | ||
| // next Start builds a fresh one. | ||
| if (ex is RabbitMQ.Client.Exceptions.ChannelAllocationException) | ||
| await RabbitConnection.ForceResetAsync(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unhandled exception vulnerability exists in the catch block because Kody rule violation: Handle async operations with proper error handling Prompt for LLMTalk to Kody by mentioning @kody Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unhandled exception risk in Kody rule violation: Add try-catch blocks for external calls Prompt for LLMTalk to Kody by mentioning @kody Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction. |
||
|
|
||
| return false; | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicated logic across the connection-factory creation and
CreateConnectionAsyncsequence (lines 46-47, 57-58, 68-69) complicates maintenance if factory options change. Extract a helper such asstatic async Task<bool> TryConnectAsync(string hostname, string clientName)to build the factory and attempt connections.Kody rule violation: Extract duplicated logic into functions
Prompt for LLM
Talk to Kody by mentioning @kody
Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.