微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Polly 没有正确处理 OracleExceptions ORA-03113 和 ORA-03114 主要包含政策声明和用法待装饰函数

如何解决Polly 没有正确处理 OracleExceptions ORA-03113 和 ORA-03114 主要包含政策声明和用法待装饰函数

我之前关于 Polly 和 Oracle Connectivity 的问题如下

async await throwing error for Polly code while connecting to Oracle DB

扩展这一点,我正在尝试根据连接和 FTP 连接处理多个 Oracle 异常。它能够正确处理 FTP 异常。但是到了Oracle,就无法处理0RA-03113和ORA-03114

这是我实现的代码..

static void Main()
    {
        var retryTimes = 100;
        var retryableOracleErrorCodes = new[] { "ORA-03113","ORA-03114","ORA-12543","ORA-12170","ORA-12154"  };

        RetryPolicy retryPolicyFTP = Policy
            .Handle<Xceed.Ftp.FtpInvalidStateException>()
            .WaitAndRetry(retryTimes,_ => TimeSpan.FromSeconds(10));

        RetryPolicy retryPolicyFTP1 = Policy
            .Handle<Xceed.Ftp.FtpIOException>()
            .WaitAndRetry(retryTimes,_ => TimeSpan.FromSeconds(10));

        RetryPolicy retryPolicyOracle = Policy
            .Handle<OracleException>(ex => retryableOracleErrorCodes.Any(errorCode => ex.Message.Contains(errorCode)))
            .RetryForever();

        retryPolicyFTP.Execute(() =>
        {
            retryPolicyFTP1.Execute(() =>
            {
                retryPolicyOracle.Execute(() =>
                {
                    ApplicationMain applicationMain = new ApplicationMain();
                    applicationMain.Start();
                });
            });
        });
    }

能否请您解释一下...为什么它无法处理特定的 Oracle 异常...我的意思是如果我断开程序和 Oracle DB 之间的连接,它应该保持沉而不抛出异常,并在连接时再次可用,它应该能够检索数据库记录..

为什么它没有静,为什么它会中断...对于 ORA-03113 和 ORA-03114。抛出的错误如下所示..

enter image description here

详细的异常如下..

36722763    Source.FtpInternal1.Poll    Failed  2021-04-30 08:40:00 2021-04- 
30 08:40:04     Oracle.DataAccess.Client.OracleException ORA-03113: end-of- 
file on communication channel
Process ID: 149519
Session ID: 1655 Serial number: 65101    at 
Oracle.DataAccess.Client.OracleException.HandleErrorHelper(Int32 errCode,OracleConnection conn,IntPtr opsErrCtx,OposqlValCtx* pOposqlValCtx,Object 
src,String procedure,Boolean bCheck)
at Oracle.DataAccess.Client.OracleException.HandleError(Int32 errCode,OposqlValCtx* 
pOposqlValCtx,Object src,Boolean bCheck)
at Oracle.DataAccess.Client.OracleCommand.ExecuteReader(Boolean requery,Boolean fillRequest,CommandBehavior behavior)
at Oracle.DataAccess.Client.OracleCommand.ExecuteReader()
at Data.MetaRecord.Fill(DataTable dataTable,RecordCommand recordCommand,Object[] parameterValues,FillResultType fillResultType) in 
C:\Data\MetaRecord.cs:line 1348
at Data.MetaRecord.FillWithComposites(RecordCommandCompositecollection 
recordCommandComposites,RecordCommandComposite parentRecordCommandComposite,FillResultType fillResultType) in 
C:\Data\MetaRecord.cs:line 1537
at Data.MetaRecord.FillWithComposites(RecordCommandCompositecollection 
recordCommandComposites,FillResultType fillResultType) in 
C:\Data\MetaRecord.cs:line 1551
at Data.MetaRecord.FillWithComposites(RecordCommandCompositecollection 
recordCommandComposites,FillResultType fillResultType) in 
C:\Data\MetaRecord.cs:line 1551
at Data.MetaRecord.RetrieveByPrimaryKey(RecordRetrieveAttributes 
recordRetrieveAttributes,Object[] primarykeyvalues) in 
C:\Data\MetaRecord.cs:line 1830
at Data.MetaRecord.GetRecordByPrimaryKey(RecordGetAttributes 
recordGetAttributes,Object[] primarykeyvalues) in C:\Data\MetaRecord.cs:line 
873
at Data.MetaRecord.GetRecordByPrimaryKey(Object[] primarykeyvalues) in 
C:\Data\MetaRecord.cs:line 923
at Processors.ExecuteInfo.GetAndRegisterRecord(recordtype recordtype,Object[] primarykeyvalues) in C:\Core\Processors\ExecuteInfo.cs:line 143
at Processors.InternalPoll.ProcessExecute(DataTransaction dataTransaction,ExecuteInfo executeInfo,ProcessInfo processInfo) in 
C:\Core\Processors\InternalPoll.cs:line 67
at Processors.Processor.Execute(ExecuteInfo executeInfo,ProcessInfo 
processInfo) in C:\Core\Processors\Processor.cs:line 184

这是我准备的最终代码,但它仍然没有抛出 OracleException 消息

var retryTimes = 100;
var retryableOracleErrorCodes = new[] { "ORA-03113","ORA-12154" };

RetryPolicy retryPolicyFTP = Policy
    .Handle<Xceed.Ftp.FtpInvalidStateException>().Or<Xceed.Ftp.FtpIOException>()
    .WaitAndRetry(retryTimes,_ => TimeSpan.FromSeconds(10));

RetryPolicy retryPolicyOracle = Policy
    .Handle<OracleException>(ex => retryableOracleErrorCodes
                                    .Any(errorCode => ex.ToString().Contains(errorCode)))
    .RetryForever();

Policy.Wrap(retryPolicyFTP,retryPolicyOracle).Execute(() =>
{
    try
    {
         ApplicationMain applicationMain = new ApplicationMain();
         applicationMain.Start();
    }
    catch (OracleException oraEx)
    {
         MessageBox.Show(oraEx.Message.ToString());
    }
});

.Or<Exception>() 添加到最终代码后收到以下消息

Oracle.DataAccess.Client.OracleException ORA-03114: not connected to ORACLE    at Oracle.DataAccess.Client.OracleException.HandleErrorHelper(Int32 errCode,Boolean bCheck)
   at Oracle.DataAccess.Client.OracleException.HandleError(Int32 errCode,Object src)
   at Oracle.DataAccess.Client.OracleCommand.ExecuteNonQuery()
   at Data.OraclePackageCommand.ExecuteNonQuery(OracleTransaction transaction) in C:\Core\Data\OraclePackageCommand.cs:line 74
   at Data.OraclePackageCommand.ExecuteNonQuery() in C:\Core\Data\OraclePackageCommand.cs:line 63
   at Data.OraclePackage.ExecuteServerHeartbeat(Int32 serverId,Int32 heartbeatInterval,DateTime processtime,Int32& processingStatusId,DateTime& lastHeartbeatTime,DateTime& nextHeartbeatTime,Int32& availableProcessCount,Boolean& recordModificationExists) in C:\Core\Data\OraclePackage.cs:line 2385
   at Processors.ServerInfo.Heartbeat(DateTime processtime,ServerProcessingStatus& heartbeatProcessingStatus,Boolean& recordModificationExists) in C:\Core\Processors\ServerInfo.cs:line 252
   at Processors.ServerManager.ThreadStart() in C:\Core\Processors\ServerManager.cs:line 337

解决方法

TL;DR:我认为您的问题的根本原因是吞下异常。

try
{
     ApplicationMain applicationMain = new ApplicationMain();
     applicationMain.Start();
}
catch (OracleException oraEx)
{
     MessageBox.Show(oraEx.Message.ToString());
}

当抛出 OracleException 时,它会显示在 UI 上
但随后方法结束,不会触发任何策略。


为了能够重现您的问题,我更改了以下内容:

  • 我已将第 3 方例外替换为内置例外
    • FtpInvalidStateException >> NotSupportedException
    • OracleException >> ArgumentException
  • 我为每个 onRetry 定义了两个委托,以便在触发策略时打印出异常消息
  • 我已将重试之间的最大重试和等待时间更改为更短的时间
  • 我已将要装饰的代码段提取到一个名为 FaultyMethod
  • 的单独函数中
  • 最后我发现 FaultyMethod 真的有问题 :)

主要包含政策声明和用法

static readonly string[] retryableErrorCodes = 
    new[] { "ORA-03113","ORA-03114","ORA-12543","ORA-12170","ORA-12154" };
const int retryTimes = 3;

static void Main()
{
    RetryPolicy retryForNotSupported = Policy
        .Handle<NotSupportedException>()
        .WaitAndRetry(
            retryTimes,_ => TimeSpan.FromSeconds(1),(ex,ts) => Console.WriteLine(ex.Message));

    RetryPolicy retryForArgument = Policy
        .Handle<ArgumentException>(ex =>
            retryableErrorCodes.Any(errorCode => ex.Message.Contains(errorCode)))
        .RetryForever(ex => Console.WriteLine(ex.Message));

    try
    {
        Policy.Wrap(retryForNotSupported,retryForArgument).Execute(FaultyMethod);
    } catch (Exception ex)
    {
        Console.WriteLine(ex);
        Environment.Exit(-1);
    }
    Console.WriteLine("Finished");
}

待装饰函数

static int errorCount = -1;
static void FaultyMethod()
{
    try
    {
        if (++errorCount >= retryableErrorCodes.Length)
            throw new NotSupportedException();
        throw new ArgumentException($"{retryableErrorCodes[errorCount]}");
    }
    catch (ArgumentException ex)
    {
        Console.WriteLine(ex.Message);
    }
}

如果您运行此应用程序,您将看到以下内容:

ORA-03113
Finished
  1. ArgumentException 被抛出并带有消息 ORA-03113
  2. 异常在 FaultyMethod 中被捕获并打印出其消息
  3. 未触发任何重试策略
  4. PolicyExecute 不会抛出异常,这就是打印 Finished 的原因

现在让我们将代码改为抛出 NotSupportedException

static void FaultyMethod()
{
    try
    {
        if(++errorCount <= retryTimes)
            throw new NotSupportedException();
        
        //if (++errorCount >= retryableErrorCodes.Length) 
        //    throw new ArgumentException($"{retryableErrorCodes[errorCount]}");
    }
    catch (ArgumentException ex)
    {
        Console.WriteLine(ex.Message);
    }
}

那么输出将是:

Specified method is not supported.
Specified method is not supported.
Specified method is not supported.
System.NotSupportedException: Specified method is not supported.
...
  1. FaultyMethod 抛出 NotSupportedException
  2. 它的 catch 块没有捕获这个异常
  3. 内部重试策略从其角度检查它是否是已处理的异常
  4. 不,这不是这就是它把问题升级到外部政策的原因
  5. 外部重试策略从它的角度检查它是否是一个已处理的异常
  6. 是的,这是这就是为什么它在启动新的重试之前等待 1 秒
  7. 这个完全相同的序列(从 1 到 6)再重复 2 次​​li>
  8. 当外部策略达到其重试计数阈值时,它将抛出原始异常 NotSupportedException
  9. Main 的 try-catch 会捕捉到并打印出来,然后退出

因此,如果您从 FaultyMethod

中删除 try-catch
static void FaultyMethod()
{
    if (++errorCount >= retryableErrorCodes.Length)
        throw new NotSupportedException();
    throw new ArgumentException($"{retryableErrorCodes[errorCount]}");
}

然后输出将如下所示:

ORA-03113
ORA-03114
ORA-12543
ORA-12170
ORA-12154
Specified method is not supported.
Specified method is not supported.
Specified method is not supported.
System.NotSupportedException: Specified method is not supported.
  • 所有 ArgumentException 均由内部策略处理而不会超过其重试次数(无限)
  • 在超过重试次数 (3) 之前,所有 NotSupportedException 均由外部策略处理

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。