2016-02-25 10 views
9

私はデータベース呼び出し(C#とデータベースにアクセスするためのMicrosoft技術を使用)にいくつかのラッパーコードを書きたいと思いますが、一時的な例外で自動再試行します。一時的には、最終的に(論理的にはうまくいかないエラーでは)解決できる可能性があるということです。私は考えることができる例としては、Sqlサーバーの一時的な例外番号

  • デッドロック、私はこれらを発見するSqlExceptionがのエラー番号を使用して計画していた

  • 接続タイムアウト
  • コマンドタイムアウト。ですから、例えば:

    List<RunStoredProcedureResultType> resultSet = null; 
    int limit = 3; 
    for (int i = 0; i < limit; ++i) 
    { 
        bool isLast = i == limit - 1; 
        try 
        { 
         using (var db = /* ... */) 
         { 
          resultSet = db.RunStoredProcedure(param1, param2).ToList(); 
         } 
         //if it gets here it was successful 
         break; 
        } 
        catch (SqlException ex) 
        { 
         if (isLast) 
         { 
          //3 transient errors in a row. So just kill it 
          throw; 
         } 
         switch (ex.Number) 
         { 
          case 1205: //deadlock 
          case -2: //timeout (command timeout?) 
          case 11: //timeout (connection timeout?) 
           // do nothing - continue the loop 
           break; 
          default: 
           //a non-transient error. Just throw the exception on 
           throw; 
         } 
        } 
        Thread.Sleep(TimeSpan.FromSeconds(1)); //some kind of delay - might not use Sleep 
    } 
    return resultSet; 
    

    (。どんなバグのためにすみません - 私はその場であることを書いている私も、私はうまくそれを包むことができ実感...)

    だから、重要な質問です:私は「一時的」と考えなければなりません(私は一時的なものと考えていることは、他の人々が一時的と考えるものとは異なる可能性があることを理解しています)。

    https://msdn.microsoft.com/en-us/library/cc645603.aspx

    が、非常に便利な、その巨大なノート:私はここで素敵なリストを見つけました。 誰かが同じようなもののために使うリストを作りましたか?

    UPDATE

    最後に、私たちは「悪いリスト」を選んだ - これは通常、プログラマエラーです - エラーが知られている「非一時的なエラー」のリストのいずれかである場合。私は答えとして使用している数字のリストを含めました。

  • +1

    私たちは何か似たようなことをしました。それを「回復可能な例外」と呼びます。接続エラー、タイムアウト、デッドロックなどがあります。デッドロックは、コールを3回繰り返すだけで、可変遅延やその他のデッドロック解決メソッドを追加することを検討しても、辛抱強くなりそうです。すぐに2回の再試行を行うと、過負荷による接続タイムアウトが悪化する可能性があります。 – dlatikay

    +0

    ああ、私は遅れを計画していた。ありがとう@dlatikay - 上記を更新します – thab

    +0

    残念ながら、あなたが推薦を求めているのは、プログラマがあなたのケースに有益なものについて別の意見を持っている可能性があるためです。それは現在編集中ですそれは話題です。敬具。 – jclozano

    答えて

    2

    私自身の質問にお答えして申し訳ありませんが、まだ誰かが興味があれば、私たちはエラーコードの独自のリストを作成し始めました。理想的ではありませんが、これはあまり頻繁に起こるべきではないと考えました。

    私たちは、質問に暗示されている「良いリスト」の代わりに、「悪いリスト」アプローチを選択しました。我々がこれまで持っているIDSは以下のとおりです。私たちは気づい

    PARAMETER_NOT_SUPPLIED = 201; 
    CANNOT_INSERT_NULL_INTO_NON_NULL = 515; 
    FOREGIN_KEY_VIOLATION = 547; 
    PRIMARY_KEY_VIOLATION = 2627; 
    MEMORY_ALLOCATION_FAILED = 4846; 
    ERROR_CONVERTING_NUMERIC_TO_DECIMAL = 8114; 
    TOO_MANY_ARGUMENTS = 8144; 
    ARGUMENT_IS_NOT_A_PARAMETER = 8145; 
    ARGS_SUPPLIED_FOR_PROCEDURE_WITHOUT_PARAMETERS = 8146; 
    STRING_OR_BINARY_TRUNCATED = 8152; 
    INVALID_POINTER = 10006; 
    WRONG_NUMBER_OF_PARAMETERS = 18751; 
    

    もう一つは、あなたのうち、接続プールの時間は、SQLExceptionを取得しない場合ということです - ではなく、あなたが「タイムアウトの期限が切れ」報告InvalidOperationExceptionがを取得します。それは残念ですが、SqlExceptionではなく、キャッチする価値があります。

    これを最新の状態に保つよう努めます。

    1

    再試行可能コードの正規のリストはありません。これまで他のチームもこの問題を抱えていました。 EFチームは再試行戦略を策定しました。コードを盗もうと思うかもしれません。しかし、リストは完全ではありません。私はGitHubでEFがコミットしてリストを修正したのを見ました。

    この問題もありました。私はSELECT * FROM sys.messages WHERE language_id = 1033 AND text LIKE '%...%'から掘り出した明らかなエラーコードをいくつか追加しました。次に、アプリに遭遇したときにコードを追加しました。

    また、タイムアウトとネットワークエラーのために特別なエラー番号を再試行する必要があります。接続が切断されるため、サーバはその番号を生成できません。私は数字が-2だったと思うが、確かめる必要がある。

    SQL Serverで定義されているエラーレベルは、この目的では(ほとんどの場合一般的に)役に立たないものです。

    6

    一時的なフォールト処理のためにAzureにクラス[SqlDatabaseTransientErrorDetectionStrategy.cs]があります。これは、一時的と見なすことができるほとんどすべてのタイプの例外コードをカバーします。また、それはRetry strategyの完全な実装です。

    は、今後の参考のためにここにスニペットを追加:さらに

    /// <summary> 
    /// Error codes reported by the DBNETLIB module. 
    /// </summary> 
    private enum ProcessNetLibErrorCode 
    { 
        ZeroBytes = -3, 
    
        Timeout = -2, 
        /* Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. */ 
    
        Unknown = -1, 
    
        InsufficientMemory = 1, 
    
        AccessDenied = 2, 
    
        ConnectionBusy = 3, 
    
        ConnectionBroken = 4, 
    
        ConnectionLimit = 5, 
    
        ServerNotFound = 6, 
    
        NetworkNotFound = 7, 
    
        InsufficientResources = 8, 
    
        NetworkBusy = 9, 
    
        NetworkAccessDenied = 10, 
    
        GeneralError = 11, 
    
        IncorrectMode = 12, 
    
        NameNotFound = 13, 
    
        InvalidConnection = 14, 
    
        ReadWriteError = 15, 
    
        TooManyHandles = 16, 
    
        ServerError = 17, 
    
        SSLError = 18, 
    
        EncryptionError = 19, 
    
        EncryptionNotSupported = 20 
    } 
    

    スイッチケースをエラー番号がSQL例外で返さかどうかを確認するために:

    switch (err.Number) 
    { 
        // SQL Error Code: 40501 
        // The service is currently busy. Retry the request after 10 seconds. Code: (reason code to be decoded). 
        case ThrottlingCondition.ThrottlingErrorNumber: 
         // Decode the reason code from the error message to determine the grounds for throttling. 
         var condition = ThrottlingCondition.FromError(err); 
    
         // Attach the decoded values as additional attributes to the original SQL exception. 
         sqlException.Data[condition.ThrottlingMode.GetType().Name] = 
          condition.ThrottlingMode.ToString(); 
         sqlException.Data[condition.GetType().Name] = condition; 
    
         return true; 
    
        // SQL Error Code: 10928 
        // Resource ID: %d. The %s limit for the database is %d and has been reached. 
        case 10928: 
        // SQL Error Code: 10929 
        // Resource ID: %d. The %s minimum guarantee is %d, maximum limit is %d and the current usage for the database is %d. 
        // However, the server is currently too busy to support requests greater than %d for this database. 
        case 10929: 
        // SQL Error Code: 10053 
        // A transport-level error has occurred when receiving results from the server. 
        // An established connection was aborted by the software in your host machine. 
        case 10053: 
        // SQL Error Code: 10054 
        // A transport-level error has occurred when sending the request to the server. 
        // (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.) 
        case 10054: 
        // SQL Error Code: 10060 
        // A network-related or instance-specific error occurred while establishing a connection to SQL Server. 
        // The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server 
        // is configured to allow remote connections. (provider: TCP Provider, error: 0 - A connection attempt failed 
        // because the connected party did not properly respond after a period of time, or established connection failed 
        // because connected host has failed to respond.)"} 
        case 10060: 
        // SQL Error Code: 40197 
        // The service has encountered an error processing your request. Please try again. 
        case 40197: 
        // SQL Error Code: 40540 
        // The service has encountered an error processing your request. Please try again. 
        case 40540: 
        // SQL Error Code: 40613 
        // Database XXXX on server YYYY is not currently available. Please retry the connection later. If the problem persists, contact customer 
        // support, and provide them the session tracing ID of ZZZZZ. 
        case 40613: 
        // SQL Error Code: 40143 
        // The service has encountered an error processing your request. Please try again. 
        case 40143: 
        // SQL Error Code: 233 
        // The client was unable to establish a connection because of an error during connection initialization process before login. 
        // Possible causes include the following: the client tried to connect to an unsupported version of SQL Server; the server was too busy 
        // to accept new connections; or there was a resource limitation (insufficient memory or maximum allowed connections) on the server. 
        // (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.) 
        case 233: 
        // SQL Error Code: 64 
        // A connection was successfully established with the server, but then an error occurred during the login process. 
        // (provider: TCP Provider, error: 0 - The specified network name is no longer available.) 
        case 64: 
        // DBNETLIB Error Code: 20 
        // The instance of SQL Server you attempted to connect to does not support encryption. 
        case (int)ProcessNetLibErrorCode.EncryptionNotSupported: 
         return true; 
    } 
    

    は、完全なsource hereを参照してください。

    +1

    これは良いことです。このリストはまだ完全ではないというメモを追加するだけです。 EFは他の誰と同じようにこれについてまったく無知です。彼らはアイテムを忘れる。例:スナップショット分離書き込みの競合。また、私はそのリストにデッドロックは見られません。それは非常に疑わしい値のリストを意味します。 – usr

    +0

    はい。私は同意します!しかしそれはまずは​​良いリストです。 – vendettamit

    +0

    ありがとう@vendettamit - うまく見えますが、usrが言及すると、デッドロックが逃れたという事実は、それがおそらく私が再試行に興味を持っている主要なものの1つであることを疑いを感じさせます。おそらくEFが自動的に再試行することができるのではないかと思いますか? – thab

    関連する問題