diff --git a/src/Managing.Core/Exceptions/OrleansExceptionHelper.cs b/src/Managing.Core/Exceptions/OrleansExceptionHelper.cs
new file mode 100644
index 00000000..1494263a
--- /dev/null
+++ b/src/Managing.Core/Exceptions/OrleansExceptionHelper.cs
@@ -0,0 +1,119 @@
+using Microsoft.Extensions.Logging;
+
+namespace Managing.Core.Exceptions;
+
+///
+/// Helper class to detect and handle Orleans-specific exceptions
+///
+public static class OrleansExceptionHelper
+{
+ ///
+ /// Checks if an exception is an Orleans-specific exception
+ ///
+ public static bool IsOrleansException(Exception ex)
+ {
+ if (ex == null) return false;
+
+ var exceptionTypeName = ex.GetType().Name;
+ var exceptionMessage = ex.Message ?? string.Empty;
+
+ // Check for Orleans exception type names
+ if (exceptionTypeName.Contains("Orleans", StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+
+ // Check for Orleans-specific exception messages
+ if (exceptionMessage.Contains("Orleans", StringComparison.OrdinalIgnoreCase) ||
+ exceptionMessage.Contains("grain", StringComparison.OrdinalIgnoreCase) ||
+ exceptionMessage.Contains("silo", StringComparison.OrdinalIgnoreCase) ||
+ exceptionMessage.Contains("activation", StringComparison.OrdinalIgnoreCase) ||
+ exceptionMessage.Contains("forwarding failed", StringComparison.OrdinalIgnoreCase) ||
+ exceptionMessage.Contains("Unable to create local activation", StringComparison.OrdinalIgnoreCase) ||
+ exceptionMessage.Contains("Request timeout", StringComparison.OrdinalIgnoreCase) ||
+ exceptionMessage.Contains("Deadlock", StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+
+ // Check inner exception recursively
+ if (ex.InnerException != null)
+ {
+ return IsOrleansException(ex.InnerException);
+ }
+
+ return false;
+ }
+
+ ///
+ /// Converts an Orleans exception to a user-friendly message
+ ///
+ public static string GetUserFriendlyMessage(Exception ex, string operation = "operation")
+ {
+ if (!IsOrleansException(ex))
+ {
+ return ex.Message;
+ }
+
+ var exceptionTypeName = ex.GetType().Name;
+ var exceptionMessage = ex.Message ?? string.Empty;
+
+ // Handle timeout exceptions
+ if (ex is TimeoutException || ex is TaskCanceledException ||
+ exceptionMessage.Contains("timeout", StringComparison.OrdinalIgnoreCase) ||
+ exceptionMessage.Contains("timed out", StringComparison.OrdinalIgnoreCase))
+ {
+ return $"The {operation} timed out. This may occur when closing positions takes longer than expected. Please try again in a moment.";
+ }
+
+ // Handle deadlock exceptions
+ if (exceptionMessage.Contains("deadlock", StringComparison.OrdinalIgnoreCase))
+ {
+ return $"The {operation} could not complete due to a system conflict. Please try again in a moment.";
+ }
+
+ // Handle activation/grain errors
+ if (exceptionMessage.Contains("activation", StringComparison.OrdinalIgnoreCase) ||
+ exceptionMessage.Contains("grain", StringComparison.OrdinalIgnoreCase) ||
+ exceptionMessage.Contains("forwarding failed", StringComparison.OrdinalIgnoreCase))
+ {
+ return $"The {operation} encountered a temporary system issue. Please try again in a moment.";
+ }
+
+ // Generic Orleans error
+ return $"The {operation} encountered a temporary system issue. Please try again in a moment. If the problem persists, contact support.";
+ }
+
+ ///
+ /// Wraps an async operation with timeout and Orleans exception handling
+ ///
+ public static async Task ExecuteWithTimeoutAndOrleansHandling(
+ Func> operation,
+ TimeSpan timeout,
+ string operationName,
+ ILogger logger = null)
+ {
+ try
+ {
+ using var cts = new CancellationTokenSource(timeout);
+ var task = operation();
+ var timeoutTask = Task.Delay(timeout, cts.Token);
+
+ var completedTask = await Task.WhenAny(task, timeoutTask);
+ if (completedTask == timeoutTask)
+ {
+ throw new TimeoutException($"The {operationName} timed out after {timeout.TotalSeconds} seconds.");
+ }
+
+ return await task;
+ }
+ catch (Exception ex) when (IsOrleansException(ex) || ex is TimeoutException)
+ {
+ logger?.LogError(ex, "Orleans exception or timeout during {OperationName}: {ExceptionType} - {Message}",
+ operationName, ex.GetType().Name, ex.Message);
+ var userMessage = GetUserFriendlyMessage(ex, operationName);
+ throw new ServiceUnavailableException(userMessage);
+ }
+ }
+}
+