Polly 没有正确处理 OracleExceptions ORA-03113 和 ORA-03114
Polly not handling OracleExceptions ORA-03113 and ORA-03114 properly
我之前关于 Polly 和 Oracle Connectivity 的问题如下
对此进行扩展,我正在尝试根据连接以及 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,为什么它没有静音以及为什么它会中断...。抛出的错误如下所示..
具体异常如下..
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,
OracleConnection conn, String procedure, IntPtr opsErrCtx, 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,
Object[] parameterValues, FillResultType fillResultType) in
C:\Data\MetaRecord.cs:line 1537
at Data.MetaRecord.FillWithComposites(RecordCommandCompositeCollection
recordCommandComposites, RecordCommandComposite parentRecordCommandComposite,
Object[] parameterValues, FillResultType fillResultType) in
C:\Data\MetaRecord.cs:line 1551
at Data.MetaRecord.FillWithComposites(RecordCommandCompositeCollection
recordCommandComposites, RecordCommandComposite parentRecordCommandComposite,
Object[] parameterValues, 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-03114", "ORA-12543", "ORA-12170", "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, OracleConnection conn, IntPtr opsErrCtx, OpoSqlValCtx* pOpoSqlValCtx, Object src, String procedure, Boolean bCheck)
at Oracle.DataAccess.Client.OracleException.HandleError(Int32 errCode, OracleConnection conn, String procedure, IntPtr opsErrCtx, OpoSqlValCtx* pOpoSqlValCtx, 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, Int32& availableProcessCount, 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
ArgumentException
抛出消息 ORA-03113
- 异常在
FaultyMethod
中被捕获并打印出它的消息
- None 个重试策略被触发
Policy
的 Execute
没有抛出异常,这就是打印 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.
...
FaultyMethod
抛出 NotSupportedException
- 它的 catch 块没有捕获这个异常
- 内部重试策略从它的角度检查它是否是一个已处理的异常
- 不,不是这就是为什么它将问题升级到外部策略
- 外部重试策略从它的角度检查它是否是一个已处理的异常
- 是的,就是这就是为什么它在启动新的重试之前等待 1 秒的原因
- 这个完全相同的序列(从 1 到 6)再重复 2 次
- 当外部策略达到其重试计数阈值时,它将抛出原始异常
NotSupportedException
Main
的 try-catch 会捕捉到它,然后打印出来 exits
因此,如果您从 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
都由内部策略处理而不超过其重试次数(无限次)
- 所有
NotSupportedException
在超过其重试计数之前由外部策略处理 (3)
我之前关于 Polly 和 Oracle Connectivity 的问题如下
对此进行扩展,我正在尝试根据连接以及 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,为什么它没有静音以及为什么它会中断...。抛出的错误如下所示..
具体异常如下..
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,
OracleConnection conn, String procedure, IntPtr opsErrCtx, 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,
Object[] parameterValues, FillResultType fillResultType) in
C:\Data\MetaRecord.cs:line 1537
at Data.MetaRecord.FillWithComposites(RecordCommandCompositeCollection
recordCommandComposites, RecordCommandComposite parentRecordCommandComposite,
Object[] parameterValues, FillResultType fillResultType) in
C:\Data\MetaRecord.cs:line 1551
at Data.MetaRecord.FillWithComposites(RecordCommandCompositeCollection
recordCommandComposites, RecordCommandComposite parentRecordCommandComposite,
Object[] parameterValues, 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-03114", "ORA-12543", "ORA-12170", "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, OracleConnection conn, IntPtr opsErrCtx, OpoSqlValCtx* pOpoSqlValCtx, Object src, String procedure, Boolean bCheck)
at Oracle.DataAccess.Client.OracleException.HandleError(Int32 errCode, OracleConnection conn, String procedure, IntPtr opsErrCtx, OpoSqlValCtx* pOpoSqlValCtx, 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, Int32& availableProcessCount, 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
ArgumentException
抛出消息ORA-03113
- 异常在
FaultyMethod
中被捕获并打印出它的消息 - None 个重试策略被触发
Policy
的Execute
没有抛出异常,这就是打印 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.
...
FaultyMethod
抛出NotSupportedException
- 它的 catch 块没有捕获这个异常
- 内部重试策略从它的角度检查它是否是一个已处理的异常
- 不,不是这就是为什么它将问题升级到外部策略
- 外部重试策略从它的角度检查它是否是一个已处理的异常
- 是的,就是这就是为什么它在启动新的重试之前等待 1 秒的原因
- 这个完全相同的序列(从 1 到 6)再重复 2 次
- 当外部策略达到其重试计数阈值时,它将抛出原始异常
NotSupportedException
Main
的 try-catch 会捕捉到它,然后打印出来 exits
因此,如果您从 FaultyMethod
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
都由内部策略处理而不超过其重试次数(无限次) - 所有
NotSupportedException
在超过其重试计数之前由外部策略处理 (3)