public static void SendSubscriptionDocuments(TcpConnectionOptions tcpConnectionOptions)
        {
            var remoteEndPoint = tcpConnectionOptions.TcpClient.Client.RemoteEndPoint;

            Task.Run(async() =>
            {
                using (tcpConnectionOptions)
                    using (var connection = new SubscriptionConnection(tcpConnectionOptions))
                        using (tcpConnectionOptions.ConnectionProcessingInProgress("Subscription"))
                        {
                            try
                            {
                                bool gotSemaphore;
                                if ((gotSemaphore = tcpConnectionOptions.DocumentDatabase.SubscriptionStorage.TryEnterSemaphore()) == false)
                                {
                                    throw new SubscriptionClosedException(
                                        $"Cannot open new subscription connection, max amount of concurrent connections reached ({tcpConnectionOptions.DocumentDatabase.Configuration.Subscriptions.MaxNumberOfConcurrentConnections})");
                                }
                                try
                                {
                                    await connection.InitAsync();
                                    await connection.ProcessSubscriptionAsync();
                                }
                                finally
                                {
                                    if (gotSemaphore)
                                    {
                                        tcpConnectionOptions.DocumentDatabase.SubscriptionStorage.ReleaseSubscriptionsSemaphore();
                                    }
                                }
                            }
                            catch (Exception e)
                            {
                                if (connection._logger.IsInfoEnabled)
                                {
                                    connection._logger.Info(
                                        $"Failed to process subscription {connection.SubscriptionId} / from client {remoteEndPoint}",
                                        e);
                                }
                                try
                                {
                                    await ReportExceptionToClient(connection, connection.ConnectionException ?? e);
                                }
                                catch (Exception)
                                {
                                    // ignored
                                }
                            }
                            finally
                            {
                                if (connection._logger.IsInfoEnabled)
                                {
                                    connection._logger.Info(
                                        $"Finished processing subscription {connection.SubscriptionId} / from client {remoteEndPoint}");
                                }
                            }
                        }
            });
        }
 private static async Task ReportExceptionToClient(SubscriptionConnection connection, Exception ex, int recursionDepth = 0)
 {
     if (recursionDepth == 2)
     {
         return;
     }
     try
     {
         if (ex is SubscriptionDoesNotExistException)
         {
             await connection.WriteJsonAsync(new DynamicJsonValue
             {
                 [nameof(SubscriptionConnectionServerMessage.Type)]      = nameof(SubscriptionConnectionServerMessage.MessageType.ConnectionStatus),
                 [nameof(SubscriptionConnectionServerMessage.Status)]    = nameof(SubscriptionConnectionServerMessage.ConnectionStatus.NotFound),
                 [nameof(SubscriptionConnectionServerMessage.Message)]   = ex.Message,
                 [nameof(SubscriptionConnectionServerMessage.Exception)] = ex.ToString()
             });
         }
         else if (ex is SubscriptionClosedException)
         {
             await connection.WriteJsonAsync(new DynamicJsonValue
             {
                 [nameof(SubscriptionConnectionServerMessage.Type)]      = nameof(SubscriptionConnectionServerMessage.MessageType.ConnectionStatus),
                 [nameof(SubscriptionConnectionServerMessage.Status)]    = nameof(SubscriptionConnectionServerMessage.ConnectionStatus.Closed),
                 [nameof(SubscriptionConnectionServerMessage.Message)]   = ex.Message,
                 [nameof(SubscriptionConnectionServerMessage.Exception)] = ex.ToString()
             });
         }
         else if (ex is SubscriptionInvalidStateException)
         {
             await connection.WriteJsonAsync(new DynamicJsonValue
             {
                 [nameof(SubscriptionConnectionServerMessage.Type)]      = nameof(SubscriptionConnectionServerMessage.MessageType.ConnectionStatus),
                 [nameof(SubscriptionConnectionServerMessage.Status)]    = nameof(SubscriptionConnectionServerMessage.ConnectionStatus.Invalid),
                 [nameof(SubscriptionConnectionServerMessage.Message)]   = ex.Message,
                 [nameof(SubscriptionConnectionServerMessage.Exception)] = ex.ToString()
             });
         }
         else if (ex is SubscriptionInUseException)
         {
             await connection.WriteJsonAsync(new DynamicJsonValue
             {
                 [nameof(SubscriptionConnectionServerMessage.Type)]      = nameof(SubscriptionConnectionServerMessage.MessageType.ConnectionStatus),
                 [nameof(SubscriptionConnectionServerMessage.Status)]    = nameof(SubscriptionConnectionServerMessage.ConnectionStatus.InUse),
                 [nameof(SubscriptionConnectionServerMessage.Message)]   = ex.Message,
                 [nameof(SubscriptionConnectionServerMessage.Exception)] = ex.ToString()
             });
         }
         else if (ex is SubscriptionDoesNotBelongToNodeException subscriptionDoesNotBelongException)
         {
             if (connection._logger.IsInfoEnabled)
             {
                 connection._logger.Info("Subscription does not belong to current node", ex);
             }
             await connection.WriteJsonAsync(new DynamicJsonValue
             {
                 [nameof(SubscriptionConnectionServerMessage.Type)]    = nameof(SubscriptionConnectionServerMessage.MessageType.ConnectionStatus),
                 [nameof(SubscriptionConnectionServerMessage.Status)]  = nameof(SubscriptionConnectionServerMessage.ConnectionStatus.Redirect),
                 [nameof(SubscriptionConnectionServerMessage.Message)] = ex.Message,
                 [nameof(SubscriptionConnectionServerMessage.Data)]    = new DynamicJsonValue
                 {
                     [nameof(SubscriptionConnectionServerMessage.SubscriptionRedirectData.RedirectedTag)] = subscriptionDoesNotBelongException.AppropriateNode
                 }
             });
         }
         else if (ex is SubscriptionChangeVectorUpdateConcurrencyException subscriptionConcurrency)
         {
             if (connection._logger.IsInfoEnabled)
             {
                 connection._logger.Info("Subscription change vector update concurrency error", ex);
             }
             await connection.WriteJsonAsync(new DynamicJsonValue
             {
                 [nameof(SubscriptionConnectionServerMessage.Type)]      = nameof(SubscriptionConnectionServerMessage.MessageType.ConnectionStatus),
                 [nameof(SubscriptionConnectionServerMessage.Status)]    = nameof(SubscriptionConnectionServerMessage.ConnectionStatus.ConcurrencyReconnect),
                 [nameof(SubscriptionConnectionServerMessage.Message)]   = ex.Message,
                 [nameof(SubscriptionConnectionServerMessage.Exception)] = ex.ToString()
             });
         }
         else if (ex is CommandExecutionException commandExecution && commandExecution.InnerException is SubscriptionException)
         {
             await ReportExceptionToClient(connection, commandExecution.InnerException, recursionDepth - 1);
         }
         else
         {
             if (connection._logger.IsInfoEnabled)
             {
                 connection._logger.Info("Subscription error", ex);
             }
             await connection.WriteJsonAsync(new DynamicJsonValue
             {
                 [nameof(SubscriptionConnectionServerMessage.Type)]      = nameof(SubscriptionConnectionServerMessage.MessageType.Error),
                 [nameof(SubscriptionConnectionServerMessage.Status)]    = nameof(SubscriptionConnectionServerMessage.ConnectionStatus.None),
                 [nameof(SubscriptionConnectionServerMessage.Message)]   = ex.Message,
                 [nameof(SubscriptionConnectionServerMessage.Exception)] = ex.ToString()
             });
         }
     }
 private static async Task ReportExceptionToClient(SubscriptionConnection connection, Exception ex)
 {
     try
     {
         if (ex is SubscriptionDoesNotExistException)
         {
             await connection.WriteJsonAsync(new DynamicJsonValue
             {
                 [nameof(SubscriptionConnectionServerMessage.Type)]      = nameof(SubscriptionConnectionServerMessage.MessageType.ConnectionStatus),
                 [nameof(SubscriptionConnectionServerMessage.Status)]    = nameof(SubscriptionConnectionServerMessage.ConnectionStatus.NotFound),
                 [nameof(SubscriptionConnectionServerMessage.Message)]   = ex.Message,
                 [nameof(SubscriptionConnectionServerMessage.Exception)] = ex.ToString()
             });
         }
         else if (ex is SubscriptionClosedException)
         {
             await connection.WriteJsonAsync(new DynamicJsonValue
             {
                 [nameof(SubscriptionConnectionServerMessage.Type)]      = nameof(SubscriptionConnectionServerMessage.MessageType.ConnectionStatus),
                 [nameof(SubscriptionConnectionServerMessage.Status)]    = nameof(SubscriptionConnectionServerMessage.ConnectionStatus.Closed),
                 [nameof(SubscriptionConnectionServerMessage.Message)]   = ex.Message,
                 [nameof(SubscriptionConnectionServerMessage.Exception)] = ex.ToString()
             });
         }
         else if (ex is SubscriptionInvalidStateException)
         {
             await connection.WriteJsonAsync(new DynamicJsonValue
             {
                 [nameof(SubscriptionConnectionServerMessage.Type)]      = nameof(SubscriptionConnectionServerMessage.MessageType.ConnectionStatus),
                 [nameof(SubscriptionConnectionServerMessage.Status)]    = nameof(SubscriptionConnectionServerMessage.ConnectionStatus.Invalid),
                 [nameof(SubscriptionConnectionServerMessage.Message)]   = ex.Message,
                 [nameof(SubscriptionConnectionServerMessage.Exception)] = ex.ToString()
             });
         }
         else if (ex is SubscriptionInUseException)
         {
             await connection.WriteJsonAsync(new DynamicJsonValue
             {
                 [nameof(SubscriptionConnectionServerMessage.Type)]      = nameof(SubscriptionConnectionServerMessage.MessageType.ConnectionStatus),
                 [nameof(SubscriptionConnectionServerMessage.Status)]    = nameof(SubscriptionConnectionServerMessage.ConnectionStatus.InUse),
                 [nameof(SubscriptionConnectionServerMessage.Message)]   = ex.Message,
                 [nameof(SubscriptionConnectionServerMessage.Exception)] = ex.ToString()
             });
         }
         else if (ex is SubscriptionDoesNotBelongToNodeException subscriptionDoesNotBelongException)
         {
             if (connection._logger.IsInfoEnabled)
             {
                 connection._logger.Info("Subscription does not belong to current node", ex);
             }
             await connection.WriteJsonAsync(new DynamicJsonValue
             {
                 [nameof(SubscriptionConnectionServerMessage.Type)]    = nameof(SubscriptionConnectionServerMessage.MessageType.ConnectionStatus),
                 [nameof(SubscriptionConnectionServerMessage.Status)]  = nameof(SubscriptionConnectionServerMessage.ConnectionStatus.Redirect),
                 [nameof(SubscriptionConnectionServerMessage.Message)] = ex.Message,
                 [nameof(SubscriptionConnectionServerMessage.Data)]    = new DynamicJsonValue
                 {
                     [nameof(SubscriptionConnectionServerMessage.SubscriptionRedirectData.RedirectedTag)] = subscriptionDoesNotBelongException.AppropriateNode
                 }
             });
         }
         else
         {
             await connection.WriteJsonAsync(new DynamicJsonValue
             {
                 [nameof(SubscriptionConnectionServerMessage.Type)]      = nameof(SubscriptionConnectionServerMessage.MessageType.Error),
                 [nameof(SubscriptionConnectionServerMessage.Status)]    = nameof(SubscriptionConnectionServerMessage.ConnectionStatus.None),
                 [nameof(SubscriptionConnectionServerMessage.Message)]   = ex.Message,
                 [nameof(SubscriptionConnectionServerMessage.Exception)] = ex.ToString()
             });
         }
     }
     catch
     {
         // ignored
     }
 }
Exemple #4
0
        public static void SendSubscriptionDocuments(TcpConnectionOptions tcpConnectionOptions)
        {
            Task.Run(async() =>
            {
                var connection = new SubscriptionConnection(tcpConnectionOptions);
                tcpConnectionOptions.DisposeOnConnectionClose.Add(connection);
                try
                {
                    if (await connection.InitAsync() == false)
                    {
                        return;
                    }
                    await connection.ProcessSubscriptionAysnc();
                }
                catch (Exception e)
                {
                    if (connection._logger.IsInfoEnabled)
                    {
                        connection._logger.Info($"Failed to process subscription {connection._options?.SubscriptionId} / from client {connection.TcpConnection.TcpClient.Client.RemoteEndPoint}",
                                                e);
                    }
                    try
                    {
                        if (connection.ConnectionException != null)
                        {
                            return;
                        }
                        using (var writer = new BlittableJsonTextWriter(tcpConnectionOptions.Context, tcpConnectionOptions.Stream))
                        {
                            tcpConnectionOptions.Context.Write(writer, new DynamicJsonValue
                            {
                                ["Type"]      = "Error",
                                ["Exception"] = e.ToString()
                            });
                        }
                    }
                    catch (Exception)
                    {
                        // ignored
                    }
                }
                finally
                {
                    if (connection._options != null && connection._logger.IsInfoEnabled)
                    {
                        connection._logger.Info($"Finished proccessing subscription {connection._options?.SubscriptionId} / from client {connection.TcpConnection.TcpClient.Client.RemoteEndPoint}");
                    }

                    if (connection.ConnectionException != null)
                    {
                        try
                        {
                            var status = "None";
                            if (connection.ConnectionException is SubscriptionClosedException)
                            {
                                status = "Closed";
                            }

                            using (var writer = new BlittableJsonTextWriter(tcpConnectionOptions.Context, tcpConnectionOptions.Stream))
                            {
                                tcpConnectionOptions.Context.Write(writer, new DynamicJsonValue
                                {
                                    ["Type"]      = "Error",
                                    ["Status"]    = status,
                                    ["Exception"] = connection.ConnectionException.ToString()
                                });
                            }
                        }
                        catch
                        {
                            // ignored
                        }
                    }
                    tcpConnectionOptions.Dispose();
                }
            });
        }