Question Comment accélérer le délai d'expiration de SqlConnection


J'utilise une chaîne de connexion SQL avec SqlClient.SqlConnection et en spécifiant le délai de connexion = 5 dans la chaîne, mais il attend toujours 30 secondes avant de renvoyer une erreur. Comment puis-je l'abandonner et revenir plus vite? Je suis sur un réseau local rapide et je ne veux pas attendre 30 secondes. Les serveurs qui ne sont pas sous tension prennent 30 secondes pour tomber en panne. Ceci est juste un programme utilitaire rapide qui fonctionnera toujours uniquement sur ce réseau local.

modifier: Désolé si je n'étais pas clair. Je veux que SqlConnection.Open échoue plus rapidement. J'espère que cela pourrait être déduit du fait que les serveurs que je veux échouer plus rapidement sont désactivés.

modifier: Il semble que le réglage échoue parfois. Comme il connaît l'adresse IP du serveur, et utilise TCP / IP pour lui parler (pas local) mais ne peut pas contacter SQL Server à cette adresse? Je ne sais pas quel est le modèle, mais je ne vois pas le problème lors de la connexion locale avec SQL Server arrêté, et je ne le vois pas lorsque vous essayez de vous connecter à un serveur inexistant. Je l'ai vu lors de la tentative de contact avec un serveur sur lequel le pare-feu Windows 2008 bloque SQL Server.


14
2017-09-01 14:51


origine


Réponses:


Il semble que tous les cas qui ont causé de longs retards ont pu être résolus beaucoup plus rapidement en essayant une connexion directe comme ceci:

foreach (string svrName in args)
{
   try
   {
      System.Net.Sockets.TcpClient tcp = new System.Net.Sockets.TcpClient(svrName, 1433);
      if (tcp.Connected)
         Console.WriteLine("Opened connection to {0}", svrName);
      else
         Console.WriteLine("{0} not connected", svrName);
      tcp.Close();
   }
   catch (Exception ex)
   {
      Console.WriteLine("Error connecting to {0}: {1}", svrName, ex.Message);
   }
}

Je vais utiliser ce code pour vérifier si le serveur répond sur le port SQL Server et tenter uniquement d'ouvrir une connexion si c'est le cas. Je pensais (sur la base de l'expérience des autres) qu'il y aurait un délai de 30 secondes, même à ce niveau, mais je reçois un message indiquant que la machine "a activement refusé la connexion".

Modifier: Et si la machine n'existe pas, cela me dit tout de suite aussi. Pas de retards de 30 secondes que je peux trouver.

Modifier: Les machines qui étaient sur le réseau mais qui ne sont pas éteintes prennent encore 30 secondes pour échouer, je suppose. Les machines avec pare-feu échouent plus rapidement, cependant.

Modifier: Voici le code mis à jour. J'ai l'impression qu'il est plus propre de fermer une socket que d'interrompre un thread:

static void TestConn(string server)
{
   try
   {
      using (System.Net.Sockets.TcpClient tcpSocket = new System.Net.Sockets.TcpClient())
      {
         IAsyncResult async = tcpSocket.BeginConnect(server, 1433, ConnectCallback, null);
         DateTime startTime = DateTime.Now;
         do
         {
            System.Threading.Thread.Sleep(500);
            if (async.IsCompleted) break;
         } while (DateTime.Now.Subtract(startTime).TotalSeconds < 5);
         if (async.IsCompleted)
         {
            tcpSocket.EndConnect(async);
            Console.WriteLine("Connection succeeded");
         }
         tcpSocket.Close();
         if (!async.IsCompleted)
         {
            Console.WriteLine("Server did not respond");
            return;
         }
      }
   }
   catch(System.Net.Sockets.SocketException ex)
   {
      Console.WriteLine(ex.Message);
   }
}

11
2017-09-02 21:20



Mise à jour 2 Je suggère de lancer votre propre timeout. Quelque chose comme ça:

internal static class Program
{
    private static void Main(string[] args)
    {
        Console.WriteLine(SqlServerIsRunning("Server=foobar; Database=tempdb; Integrated Security=true", 5));
        Console.WriteLine(SqlServerIsRunning("Server=localhost; Database=tempdb; Integrated Security=true", 5));
    }

    private static bool SqlServerIsRunning(string baseConnectionString, int timeoutInSeconds)
    {
        bool result;

        using (SqlConnection sqlConnection = new SqlConnection(baseConnectionString + ";Connection Timeout=" + timeoutInSeconds))
        {
            Thread thread = new Thread(TryOpen);
            ManualResetEvent manualResetEvent = new ManualResetEvent(false);
            thread.Start(new Tuple<SqlConnection, ManualResetEvent>(sqlConnection, manualResetEvent));
            result = manualResetEvent.WaitOne(timeoutInSeconds*1000);

            if (!result)
            {
                thread.Abort();
            }

            sqlConnection.Close();
        }

        return result;
    }

    private static void TryOpen(object input)
    {
        Tuple<SqlConnection, ManualResetEvent> parameters = (Tuple<SqlConnection, ManualResetEvent>)input;

        try
        {
            parameters.Item1.Open();
            parameters.Item1.Close();
            parameters.Item2.Set();
        }
        catch
        {
            // Eat any exception, we're not interested in it
        }
    }
}

Mise à jour 1

Je viens de tester ceci sur mon propre ordinateur en utilisant ce code:

internal static class Program
{
    private static void Main(string[] args)
    {
        SqlConnection con = new SqlConnection("Server=localhost; Database=tempdb; Integrated Security=true;Connection Timeout=5");
        Console.WriteLine("Attempting to open connection with {0} second timeout, starting at {1}.", con.ConnectionTimeout, DateTime.Now.ToLongTimeString());

        try
        {
            con.Open();
            Console.WriteLine("Successfully opened connection at {0}.", DateTime.Now.ToLongTimeString());
        }
        catch (SqlException)
        {
            Console.WriteLine("SqlException raised at {0}.", DateTime.Now.ToLongTimeString());
        }
    }
}

et il obéit à la Connection Timeout valeur dans la chaîne de connexion. C'était avec .NET 4 contre SQL Server 2008 R2. Certes, c'est une connexion localhost qui peut donner des résultats différents mais cela signifie que je ne peux pas reproduire le problème.

Je ne peux que suggérer d'essayer un morceau de code similaire dans votre environnement réseau et de voir si vous continuez à voir de longs délais d'attente.

Ancienne (incorrecte) réponse Je pensais à tort que le ConnectionTimeout la propriété était définissable, mais ce n'est pas le cas.

Essayez de définir SqlConnection.ConnectionTimeout au lieu d'utiliser la chaîne de connexion.


3
2017-09-01 14:54



Le délai de commande et le délai de connexion sont deux choses différentes.

SqlConnection.ConnectionTimeout est "le temps (en secondes) à attendre qu'une connexion s'ouvre. La valeur par défaut est 15 secondes." C'est seulement utilisé lorsque vous appelez SqlConnection.Open ().

SqlCommand.CommandTimeout fait ce que vous voulez faire.


0
2017-09-01 15:14