0

これは以前に何度か尋ねられたことは知っていますが、別の解決策があるかもしれないと思いました。ただし、それを機能させるには助けが必要です。

アイデア: ビジネス層はデータ層関数を呼び出します。データ層関数は、データベース コンテキストのストアド プロシージャ関数への呼び出しを再試行ポリシーでラップします。基本的に、ストアド プロシージャへの実際の呼び出しをインポートして管理する LINQ ツールが必要ですが、再試行可能なエラーの再試行ポリシーでロジックをラップすることを望みます。

この概念の多くは、SQLException をキャッチして再試行するための優れた C# コーディング スタイルとはから引用されていますが、これは LINQ to SQL コマンドに対してのみ機能し、DBML で生成されたストアド プロシージャ関数を呼び出すのではないようです。

古い方法:

Sub BLFunctionWithoutRetry()
    Using DB as CustDataContext
        DB.sp_GetCustomers()
    End Using
End Sub

再試行を伴う新しいロジック:

Sub BLFunctionWithRetry()
    GetCustomers()
End Sub

Function GetCustomers() As List(Of Customer)
    Return Retry(Of List(Of Customer))(sp_GetCustomers())
End Function

Function Retry(Of T)(FunctionToCall As Func(Of T)) As T
    Dim Attempt As Integer = 0
    While True
        Try
            Using DB as MyDataContext
                DB.FunctionToCall()
            End Using
        Catch ex as SQLException
            If Retryable() Then Attempt += 1
            If Attempt >= Max Or Not Retryable() Then Throw
        End Try
    End While

Function Retryable() As Boolean
    Return True
End Function

これが一般的な考え方です。ただし、上記の Retry 関数を書くには助けが必要です。明らかなエラーが発生していますFunctionToCall() is not a member of 'MyDataContext'。さらに、これを記述する方法がわからないため、任意の長さの入力パラメーターを持つストアドプロシージャで機能します。

4

2 に答える 2

1

このようなものを実装する必要が生じた後、先に進んでライブラリにしました: https://github.com/daveaglick/LinqToSqlRetry (MIT ライセンスで NuGet で利用可能)。これは標準の .NET ライブラリなので、VB からも使用できるはずです (ただし、以下の例は C# です。VB をよく知らないことをお許しください)。

代わりに次SubmitChanges()のように記述して、呼び出しを再試行できます。SubmitChangesRetry()

using(var context = new MyDbContext())
{
  context.Items.InsertOnSubmit(new Item { Name = "ABC" });
  context.SubmitChangesRetry();
}

Retry()拡張メソッドを使用してクエリを再試行することもできます。

using(var context = new MyDbContext())
{
  int count = context.Items.Where(x => x.Name == "ABC").Retry().Count();
}

特定の再試行ロジックは、ポリシーによって制御できます。内部では、再試行メカニズムは次のようになります。

int retryCount = 0;
while (true)
{
    try
    {
        return func();
    }
    catch (Exception ex)
    {
        TimeSpan? interval = retryPolicy.ShouldRetry(retryCount, ex);
        if (!interval.HasValue)
        {
            throw;
        }
        Thread.Sleep(interval.Value);
    }
    retryCount++;
}

func()呼び出し内の関数とretryPolicyオブジェクトは、用途に基づいて提供されることを理解してください。これにより、再試行ループ中に何が起こっているかがわかります。詳細については、リポジトリを参照してください。

于 2014-12-22T22:51:51.190 に答える
0

答えが質問にある場合もありますが、この場合は文字通りです。SQLException をキャッチして再試行するための優れた C# コーディング スタイルとはの関数 Retry は、実際にはストアド プロシージャの呼び出しでも機能します。まだ VB で作業している方のために、コードを次に示します。

Public Class DatabaseHelper

    Private Enum RetryableSqlErrors
        SqlConnectionBroken = -1
        SqlTimeout = -2
        SqlOutOfMemory = 701
        SqlOutOfLocks = 1204
        SqlDeadlockVictim = 1205
        SqlLockRequestTimeout = 1222
        SqlTimeoutWaitingForMemoryResource = 8645
        SqlLowMemoryCondition = 8651
        SqlWordbreakerTimeout = 30053
    End Enum


    Public Shared Sub Retry(Of T As {DataContext, New})(retryAction As Action(Of T), ByVal MaxAttempts As Integer, ByVal Delay As Integer)
        Dim retryCount = 0
        Using ctx = New T()
            While True
                Try
                    retryAction(ctx)
                    Exit Sub
                Catch ex As SqlException
                    If Not [Enum].IsDefined(GetType(RetryableSqlErrors), ex.Number) Then
                        Throw
                    End If

                    retryCount += 1
                    If retryCount > MaxAttempts Then
                        Throw
                    End If

                    Thread.Sleep(If(ex.Number = CInt(RetryableSqlErrors.SqlTimeout), Delay * 5, Delay))
                End Try
            End While
        End Using
    End Sub

    Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T
        target = value
        Return value
    End Function
End Class

次に、ストアド プロシージャを呼び出します。

Dim results = New YourType
Retry(Of YourDataContext)(Function(ctx) InlineAssignHelper(Of YourType)(results, ctx.YourStoredProc("Your", "Proc", "Inputs", 1).First), 3, .5)
Return results

オリジナルからのわずかな変更: 遅延値を 1 つだけ使用することにし、タイムアウトのために 5 を掛けました。

元の投稿をしてくれたデビッド・クラークに感謝します!非常に印象的な機能。

于 2013-01-14T23:23:14.067 に答える