2009-06-26 9 views
0

J'utilise un service Web xml sur mon application Web et le serveur distant ne parvient pas à répondre à temps. Je suis venu avec l'idée de re-demander si la première tentative échoue. Pour éviter la boucle je veux limiter la demande simultanée à 2. Je veux avoir une opinion si ce que j'ai fait ci-dessous est correct et fonctionnerait comme je l'attendais.Réessayer la requête si la première a échoué

public class ScEngine 
{ 
    private int _attemptcount = 0; 
    public int attemptcount 
    { 
     get 
     { 
      return _attemptcount; 
     } 
     set 
     { 
      _attemptcount = value; 
     } 
    } 

    public DataSet GetStat(string q, string job) 
    { 

     try 
     { 
      //snip.... 
      attemptcount += attemptcount; 
      return ds; 

     } 
     catch 
     { 
      if (attemptcount>=2) 
      { 
      return null; 
      } 
      else 
      { 
       return GetStat(q, job); 
      } 

     } 

    } 
} 
+1

Soyez très, très prudent avec cette approche; il ne "niche" pas bien. Supposons que vous ayez une méthode de bas niveau qui réessaie une opération cinq fois avant d'abandonner. Son appelant réessaie cinq fois avant d'abandonner. Et son appelant réessaye cinq fois avant d'abandonner. Soudain, vous réessayez 125 avant d'abandonner. Nous avons eu des situations dans le monde réel où le code qui aurait dû renvoyer un code d'erreur en moins d'une seconde est resté en place dans des tentatives profondément imbriquées pendant plus d'une semaine, semblant bloquer l'application. Il est généralement préférable d'échouer rapidement et laisser l'utilisateur décider quand réessayer. –

Répondre

1
public class ScEngine 
{ 
    public DataSet GetStat(string q, string job) 
    { 
     int attemptCount; 
     while(attemptCount < 2) 
     { 
      try 
      { 
       attemptCount++; 
       var ds = ...//web service call 
       return ds; 
      } 
      catch {} 
     } 
     //log the error 
     return null; 
    } 
} 
+1

Cela supprime les exceptions et ne les enregistre jamais. Très mauvais s'il s'avère que l'exception n'est pas "Timeout" ou quelque chose de bénin comme ça. –

+0

Bien sûr, vous pouvez ajouter la journalisation dans la capture si vous le souhaitez. Vous pouvez également enregistrer le nombre de tentatives. – RedFilter

1

Vous avez oublié d'incrémenter le compteur de tentatives. De plus, s'il y a une erreur sur la deuxième exécution, elle ne sera pas interceptée (elle devient donc une exception non gérée).

+0

En outre, devrait être trycount> = 2, sinon il essayera 3 fois ... – RedFilter

+0

En fait, l'erreur sur la deuxième exécution * sera * attrapée parce qu'elle serait exécutée dans un deuxième try/catch parce qu'il appelle le GetStat méthode à nouveau. –

0

Je ne voudrais pas recurse afin de réessayer. De plus, je n'attraperais et n'ignorerais pas toutes les exceptions. Je voudrais savoir quelles exceptions indiquent une erreur qui devrait être retentée, et les attraperait. Vous allez ignorer les erreurs graves, comme votre code l'indique.

0

Vous ne voulez pas le résoudre de cette façon. Vous allez juste mettre plus de charge sur les serveurs et provoquer plus de timeouts.

Vous pouvez augmenter le délai d'expiration du service Web via httpRuntime. Les services Web renvoient généralement beaucoup de données en un seul appel, ce qui fait que je me retrouve souvent à le faire. Ne pas oublier d'augmenter combien de temps le client est prêt à attendre du côté du client.

0

Voici une version qui n'utilise pas la récursivité mais qui obtient le même résultat. Il comprend également un délai afin que vous puissiez donner au serveur le temps de récupérer s'il y a un problème de hic.

/// <summary> 
    /// The maximum amount of attempts to use before giving up on an update, delete or create 
    /// </summary> 
    private const int MAX_ATTEMPTS = 2; 

    /// <summary> 
    /// Attempts to execute the specified delegate with the specified arguments. 
    /// </summary> 
    /// <param name="operation">The operation to attempt.</param> 
    /// <param name="arguments">The arguments to provide to the operation.</param> 
    /// <returns>The result of the operation if there are any.</returns> 
    public static object attemptOperation(Delegate operation, params object[] arguments) 
    { 
     //attempt the operation using the default max attempts 
     return attemptOperation(MAX_ATTEMPTS, operation, arguments); 
    } 

    /// <summary> 
    /// Use for creating a random delay between retry attempts. 
    /// </summary> 
    private static Random random = new Random(); 

    /// <summary> 
    /// Attempts to execute the specified delegate with the specified arguments. 
    /// </summary> 
    /// <param name="operation">The operation to attempt.</param> 
    /// <param name="arguments">The arguments to provide to the operation.</param> 
    /// <param name="maxAttempts">The number of times to attempt the operation before giving up.</param> 
    /// <returns>The result of the operation if there are any.</returns> 
    public static object attemptOperation(int maxAttempts, Delegate operation, params object [] arguments) 
    { 
     //set our initial attempt count 
     int attemptCount = 1; 

     //set the default result 
     object result = null; 

     //we've not succeeded yet 
     bool success = false; 

     //keep trying until we get a result 
     while (success == false) 
     { 
      try 
      { 
       //attempt the operation and get the result 
       result = operation.DynamicInvoke(arguments); 
       //we succeeded if there wasn't an exception 
       success = true; 
      } 
      catch 
      { 
       //if we've got to the max attempts and still have an error, give up an rethrow it 
       if (attemptCount++ == maxAttempts) 
       { 
        //propogate the exception 
        throw; 
       } 
       else 
       { 
        //create a random delay in milliseconds 
        int randomDelayMilliseconds = random.Next(1000, 5000); 
        //sleep for the specified amount of milliseconds 
        System.Threading.Thread.Sleep(randomDelayMilliseconds); 
       } 
      } 
     } 

     //return the result 
     return result; 
    } 
Questions connexes