/// <summary> /// Try to invoke the specified <paramref name="action"/> and handle any exception that occurs. /// If an exception occurs and <paramref name="shouldMitigate"/> is true, the specified <paramref name="mitigator"/> is used to apply a mitigation. /// </summary> /// <param name="action">The action to try.</param> /// <param name="entity">The entity being loaded/mitigated.</param> /// <param name="shouldMitigate">true if errors should be mitigated; otherwise, false.</param> /// <param name="mitigator">The mitigator to use if the failed action should be mitigated.</param> private void TryMitigate(Action action, ReactiveEntity entity, bool shouldMitigate, ReactiveEntityRecoveryFailureMitigator mitigator) { try { action(); } catch (Exception ex) { var error = new EntityLoadFailedException(entity.Uri, entity.Kind, ex); if (shouldMitigate && Parent._engine.OnEntityLoadFailed(entity.Uri, entity, entity.Kind, error, out ReactiveEntityRecoveryFailureMitigation mitigation)) { var trace = Parent.TraceSource; trace.Mitigation_Execute(entity.Uri, mitigation); #pragma warning disable IDE0079 // Remove unnecessary suppression. #pragma warning disable CA1031 // Do not catch general exception types. (Protecting against engine unavailability; last resort mitigation with tracing of errors.) try { if (!mitigator.DoMitigate(entity, mitigation)) { trace.Mitigation_NotAccepted(mitigation, entity.Uri, ex); } } catch (Exception mx) { trace.Mitigation_Failure(mitigation, entity.Uri, mx); } #pragma warning restore CA1031 #pragma warning restore IDE0079 // For this implementation, whenever a mitigation occurs, we will throw a // bail out exception. This is to prevent further processing of the // 'normal' recovery process from throwing additional errors that will // trigger additional mitigations. An unfortunate consequence is that the // mitigations must ensure all steps that would have occurred in the // 'normal' recovery process occur in the mitigation (esp. for things // mitigations like `Regenerate`. Right now, this is not a problem, as the // steps being mitigated are late in the recovery process. throw new MitigationBailOutException(); } // This may result in a second call to the `EntityLoadFailed` event. throw; } }
private void HandleError(ReactiveEntityKind kind, string key, IReactiveResource entity, Exception ex, Action <Exception> unhandled) { if (ex is EngineUnloadedException) { return; } var uri = new Uri(key); var error = new EntityLoadFailedException(uri, kind, ex); // TODO: support mitigation for any kind of artifact if (!_engine.OnEntityLoadFailed(uri, entity, kind, error, out _)) { unhandled(error); } }