My previous question on Polly and Oracle Connectivity is as below
async await throwing error for Polly code while connecting to Oracle DB
Extending this, I am trying to handle multiple Oracle Exceptions based on connectivity along with FTP connection. It is able to handle FTP Exceptions properly. But when it comes to Oracle, it is not able to handle 0RA-03113 and ORA-03114
This is the code I have implemented..
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();
});
});
});
}
Could you please throw light on this... why it is not able to handle particular Oracle Exceptions..I mean if I break the connection between Program and Oracle DB, it should go silent without throwing that exceptions and again when connection is available, it should be able to retrieve the database records..
Why it is not going silent and why it is breaking...for ORA-03113 & ORA-03114. The error thrown is shown below..
The detailed exception is as below..
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
This is the final code I have prepared but still it is not throwing OracleException message
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());
}
});
Got the below message after adding .Or<Exception>()
to the Final Code
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: I think the root cause of your problem is the swallowed exception.
try
{
ApplicationMain applicationMain = new ApplicationMain();
applicationMain.Start();
}
catch (OracleException oraEx)
{
MessageBox.Show(oraEx.Message.ToString());
}
When an OracleException
is thrown then it is shown on the UI
but then the method ends and will not trigger any policy.
In order to be able to reproduce your problem I've changed the following things:
FtpInvalidStateException
>> NotSupportedException
OracleException
>> ArgumentException
onRetry
to print out the exception message when the policy is triggeredFaultyMethod
FaultyMethod
really faulty :)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);
}
}
If you run this application you will see the following:
ORA-03113
Finished
ArgumentException
is thrown with message ORA-03113
FaultyMethod
and its message is printed outPolicy
's Execute
that's why Finished is printedNow let's change the code to throw NotSupportedException
instead
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);
}
}
Then the output will be:
Specified method is not supported.
Specified method is not supported.
Specified method is not supported.
System.NotSupportedException: Specified method is not supported.
...
FaultyMethod
throws NotSupportedException
NotSupportedException
Main
's try-catch will catch that and it will print it out then exitsSo, if you remove the try-catch from the FaultyMethod
static void FaultyMethod()
{
if (++errorCount >= retryableErrorCodes.Length)
throw new NotSupportedException();
throw new ArgumentException($"{retryableErrorCodes[errorCount]}");
}
then the output will look like this:
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
is handled by the inner policy without exceeding its retry count (infinite)NotSupportedException
is handled by the outer policy before exceeding its retry count (3)