I have an ErrorHandler (DefaultErrorHandler) into which I have provided an onRedelivery ref. By default the ErrorHandler retries unlimited times. However, if a certain condition exists (currently determined by the onRedelivery ref) I would like to exit the redelivery loop and execute a different route.
My initial thought was to have the onRedelivery ref throw and exception and have an appropriate onException direct this to the appropriate route. However, I find that the RedeliveryErrorHandler catches this exception and keeps looping.
I have also found that I can set the Exchange.REDELIVERY_EXHAUSTED to true which will exit the redelivery loop but will not direct me to my recovery route.
Any suggestions?
Edit
So I have found that if I add the original exception type to the onException of the exception type in the RouteBuilder in which I have my ErrorHandler, and if I set the Exchange.REDELIVERY_EXHAUSTED to true, the original exception will be thrown to the RouteBuilder scope and caught by the onException. However, I would really prefer to throw and catch a new exception type so that the handling is explicit to this case.
Answer
So Peter's suggestion of using retryWhile was great in that it allows me to programmatically determine when to stop retrying. It's too. It only went half way thought. The second part was to send the failing exchange to a new / different route for error handling. This is accomplished by using the DeadLetterChannel instead of the DefaultErrorHandler.
Use retryWhile in combination with deadLetterChannel:
public class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() {
errorHandler(deadLetterChannel("direct:special")
.retryWhile(method(new MyPredicate())));
from("direct:start")
.log("Starting...")
.throwException(new Exception("dummy"));
from("direct:special")
.log("...Special");
}
}
public class MyPredicate implements Predicate {
#Override
public boolean matches(final Exchange exchange) {
AtomicInteger counter = exchange.getProperty("myCounter");
if (counter == null) {
counter = new AtomicInteger(0);
exchange.setProperty("myCounter", counter);
}
int count = counter.incrementAndGet();
LOG.info("Count = {}", count);
return count < 3; // or whatever condition is suitable
}
}
This prints:
INFO Starting...
INFO Count = 1
INFO Count = 2
INFO Count = 3
INFO ...Special
Related
Assume I have a class C that holds resources that need to be closed as member variables.
public class C {
private ClosableResource1 closableResource1;
private ClosableResource2 closableResource2;
.....
public C(){
closableResource1 = new ClosableResource1();
closableResource2 = new ClosableResource2();
.....
// some logic that can fail
}
close(){
closableResource1.close()
closableResource2.close()
.....
}
}
If the constructor succeeds I can be sure that close() will be called eventually by some entity manager and all the resources will be freed.
But how can I make sure I close the resources when the constructor fails? The failure can happen because I have additional logic in the constructor that can throw exception or I get some RuntimeException outside of my control?
Some things I though of:
Wrapping the constructor body with a try-catch block. Then, assuming I have a lot of closable members I'll have to have a big if statement in the catch block checking which resources were already initializing and only close them.
Offloading the ClosableResources creation to some init() function. Then I would have to make sure init() succeeded every time I try to use the object.
Is there some elegant solution? Or is this much more implementation specific then that?
You can do something like below:
public class C {
private List<AutoCloseable> closableResources = new ArrayList();
private ClosableResource1 closableResource1;
private ClosableResource2 closableResource2;
.....
public C() {
closableResource1 = new ClosableResource1();
closableResources.add(closableResource1)
closableResource2 = new ClosableResource2();
closableResources.add(closableResource2);
.....
try {
// some logic that can fail
} catch(Exception e) {
close();
}
}
close(){
for (AutoCloseable closableResource : closableResources) {
if (closableResource != null) {
closableResource.close();
}
}
}
}
Surrounding your code with try-catch and closing all your resources in catch is the correct solution here. Also read about method finalize() (Here is one tutorial). In general, I would recommend one method that cleans up all the resources (like you suggested method close(), I would call it though cleanup()) and call that method in your catch section and in your finalize() method
I asked and answered a very similar question here. It is very important that a constructor either succeeds or fails completely i.e. leaving no resources open. In order to achieve that I would follow each resource creation statement by a try-catch block. The catch block closes the resource and rethrows the exception so it is not lost:
public C() {
closableResource1 = new ClosableResource1();
closableResource2 = new ClosableResource2();
try {
// .....
// some logic that can fail and throw MyCheckedException or some RuntimeException
} catch (RuntimeException | MyCheckedException e) {
try {closableResource1.close();} catch (Exception ignore) {}
try {closableResource1.close();} catch (Exception ignore) {}
throw e;
}
}
If creating a resource can fail you need nested try-catch blocks as demonstrated here.
Here's a wild idea: create a class called something like DefusableCloser (that you can "defuse", like an explosive device being made safe):
class DefusableCloser implements AutoCloseable {
boolean active = true;
final AutoCloseable closeable;
DefusableCloser(AutoCloseable closeable) {
this.closeable = closeable;
}
#Override public void close() throws Exception {
if (active) closeable.close();
}
}
Now you can use this in a try-with-resources block:
c1 = new CloseableResource();
try (DefusableCloseable d1 = new DefusableCloseable(c1)) {
c2 = new CloseableResource();
try (DefusableCloseable d2 = new DefusableCloseable(c2)) {
// Do the other stuff which might fail...
// Finally, deactivate the closeables.
d1.active = d2.active = false;
}
}
If execution doesn't reach d1.active = d2.active = false;, the two closeables (or one, if the exception was in creating the second resource) will be closed. If execution does reach that line, they won't be closed and you can use them.
The advantage of doing it like this is that the exceptions will be correctly handled.
Note that the ordering is important: don't be tempted to create the two CloseableResources first, then the two DefusableCloseables: doing that won't handle an exception from creating the second CloseableResource. And don't put the creation of the CloseableResources into the TWR, as that would guarantee their closure.
For closing the resources in your class' close() method, you can also use try-with-resources to ensure that both resources are closed:
try (c1; c2) {}
You don't actually have to declare a new variable in the TWR syntax: you can just effectively say "close the resource for this existing variable afterwards", as shown here.
guys. Today I have done my custom realization for WebDriverEventListener. I need only onException() method which will create screenshot. But I got problem because I am using fluent wait.
new FluentWait<>(webDriver)
.withTimeout(Duration.ofSeconds(10))
.pollingEvery(Duration.ofMillis(500))
.ignoring(NoSuchElementException.class)
.until(someCondition)
So, finally, I have got screen for each ignoring(NoSuchElementException.class) - 20 screenshots for 1 fail ))). Had somebody the such problem or had someone resolve it?
when you use .ignoring(NoSuchElementException.class) you don't avoid that the exception is raised, you are just ignoring that exception. What is happening is that the exception is being raised by your FluentWait, but it is ignored (when you declare .ignoring(NoSuchElementException.class)).
You have three options here:
Capture the screen at the end of your test if the test failed [preferred].
Have a Try-Catch wherever you are using your FluentWait or any other Selenium code.
Use reflection to avoid capture when the event is raised from the method that implements the FluentWait.
This is an idea after what we have discussed:
private void ExceptionThrown(object sender, WebDriverExceptionEventArgs e)
{
if (e.ThrownException is NoSuchElementException)
{
// Get the stack trace from the current exception
StackTrace stackTrace = new StackTrace(e.ThrownException, true);
// Get the method stack frame index.
int stackTraceIndex = stackTrace.FrameCount - 1;
// Get the method name that caused the exception
string methodName = stackTrace.GetFrame(stackTraceIndex).GetMethod().Name;
if(methodName != "MyFindElement")
{
TakeSceenshot();
}
}
else
{
TakeSceenshot();
}
}
// This is an extension method of the DriverHelper interface
public IWebElement MyFindElement(this IWebDriver driver, By by, int timeOut = 0)
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut));
wait.IgnoreExceptionTypes(typeof(NoSuchElementException));
// I wait until the element exist
IWebElement result = wait.Until(drv => drv.FindElement(by) != null);
// it means that the element doesn't exist, so we throw the exception
if(result == null)
{
MyPersonalException(by);
}
}
// The parameter will help up to generate more accurate log
public void MyPersonalException(By by)
{
throw new NoSuchElementException(by.ToString());
}
This probably require changes in EventFiringWebDriver, because this class is without WebDriverWait instance and events for them. If you want avoid it, create bool variable in your EventFiringWebDriver extended class and check this value in your OnException like:
protected void OnException(WebDriverExceptionEventArgs e) {
if (IsWaitHandler)
return;
Your actions...
}
but this is not perfect solution.
I've got a WCF operation conceptually like this:
[OperationBehavior(TransactionScopeRequired = true)]
public void Foo()
{
try { DAL.Foo(); return Receipt.CreateSuccessReceipt(); }
catch (Exception ex) { return Receipt.CreateErrorReceipt(ex); }
}
If something goes wrong (say, foreign key constraint violaion) in executing the DAL code, control passes to the catch block as I'd expect. But when the method returns, it seems the transaction scope has sniffed out that the transaction failed, and it decides it better throw an exception to make sure to notify the caller about it.
In turn my client application does not get the receipt I want to return, but rather an exception:
System.ServiceModel.FaultException:
The transaction under which this method call was executing was asynchronously aborted.
What is wrong with my design?
I could have the service not catch anything, but this has it's own problems as the service needs to use exception shielding and the client (a batch tool internal to the system) needs to log the error information. The service logs errors too, but not in the same way and to the same place as the batch.
Be careful here! If you set TransactionAutoComplete=true then if the service returns normally the transaction will be committed. Only if there is an unhandled exception (which for the most part you don't have because you are catching exceptions and returning a receipt message) will the transaction be rolled back. See http://msdn.microsoft.com/en-us/library/system.servicemodel.operationbehaviorattribute.transactionautocomplete.aspx.
Think about a scenario where you successfully executed some DAL calls but some other exception (e.g. NullReferenceException) occurs. Now the transaction will be committed when the method completes because no unhandled exception has occurred but the client receives an ErrorReceipt.
For your scenario, I think you will have to manage the transactions yourself. For example:
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)]
public Receipt Foo()
{
// Create TransactionScope using the ambient transaction
using (var scope = new TransactionScope() )
{
try { DAL.Foo(); return Receipt.CreateSuccessReceipt(); scope.Complete(); }
catch (Exception ex) { return Receipt.CreateErrorReceipt(ex); }
}
}
You could eliminate boilerplate code by creating a helper method that wraps it all within the transaction or you could use policy injection/interception/aspects to manage transactions.
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)]
public Receipt Foo()
{
return ProcessWithTransaction(() =>
{
DAL.Foo();
return Receipt.CreateSuccessReceipt();
}
, (ex) =>
{
return Receipt.CreateErrorReceipt(ex);
}
);
}
T ProcessWithTransaction<T>(Func<T> processor, Func<Exception, T> exceptionHandler)
{
using (var scope = new TransactionScope())
{
try
{
T returnValue = processor();
scope.Complete();
return returnValue;
}
catch (Exception e)
{
return exceptionHandler(e);
}
}
}
You mention that you need to use exception shielding. If you are not averse to throwing faults when an error occurs then you could use Enterprise Library Exception Handling Block's exception shielding which also lets you log the information on the way out (if you desire).
If you decided to go that route your code would look something like this:
[OperationBehavior(TransactionScopeRequired = true)]
public void Foo()
{
// Resolve the default ExceptionManager object from the container.
ExceptionManager exManager = EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>();
exManager.Process(() =>
{
DAL.Foo();
return Receipt.CreateSuccessReceipt();
},
"ExceptionShielding");
}
Enterprise Library (via configuration) would then catch any exceptions and replace them with a new FaultException that is returned to the client.
[OperationBehavior(TransactionAutoComplete = true, TransactionScopeRequired = true)]
Presumably because the transaction is now rolled back as soon as the error occurs, rather than asynchronously when the scope goes out of scope :D, this behaves like I expected things to behave originally, and I can leave my design as it is.
(I had already written up the question when trying this occured to me. Hopefully posting it Q&A style will be more helpful than not posting the question at all.)
I am getting an error that begins as follows below. Is this something to do with the way my cascades are set up? Where is the proper place to start investigating? Right now I have a Role which hasMany RoleDuty. RoleDuty belongsTo Role. RoleDuty only has one field, duty, which is a nullable String. Role has a mapping of all-delete-orphan for the RoleDuties list.
06.12.2010 10:02:17 *ERROR* AssertionFailure: an assertion failure occured (this may indicate a bug in Hibernate, but is
more likely due to unsafe use of the session) (AssertionFailure.java, line 47)
org.hibernate.AssertionFailure: null id in RoleDuty entry (don't flush the Session after an exception occurs)
at org.hibernate.event.def.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:78)
at org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:187)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:14
3)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListen
er.java:99)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:49)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
at org.springframework.orm.hibernate3.HibernateAccessor.flushIfNecessary(HibernateAccessor.java:390)
at org.codehaus.groovy.grails.orm.hibernate.support.GrailsOpenSessionInViewInterceptor.flushIfNecessary(GrailsOp
enSessionInViewInterceptor.java:116)
at org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor.postHandle(OpenSessionInViewIntercept
or.java:181)
at org.codehaus.groovy.grails.orm.hibernate.support.GrailsOpenSessionInViewInterceptor.postHandle(GrailsOpenSess
ionInViewInterceptor.java:66)
at org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter.postHandle(WebRequestHandlerInter
ceptorAdapter.java:61)
at org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet.doDispatch(GrailsDispatcherServlet.java:303)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
Class definitions:
class RoleDuty
{
static belongsTo = [role:Role]
static constraints = {
duty(nullable: true)
}
static mapping = {
duty type:"text"
}
String duty;
boolean _deleted
static transients = ['_deleted']
#XmlValue
public String getDuty(){
return duty;
}
String toString()
{
return duty;
}
}
public class Role implements Comparable
{
static belongsTo = [project:Project]
static hasMany = [ roleDuties:RoleDuty]
static mapping = {
roleDuties cascade:"all-delete-orphan", lazy:false
}
List<RoleDuty> roleDuties = new ArrayList<RoleDuty>()
}
Hibernate's error message "don't flush the Session after an exception occurs" suggests that a Hibernate-related exception occurred on this Session but your code caught the exception and continued to use the Session. Hibernate's API states that if Hibernate throws an exception, you must roll back the transaction/close the Session and do whatever you want in a new Session.
It's hard to tell exactly what the issue is from just this stack trace and debugging Hibernate errors involves trial and error. I suggest you debug your code while looking for an exception prior to this one and figure out how to avoid it.
I have a task to perform an HttpWebRequest using
Task<WebResponse>.Factory.FromAsync(req.BeginGetRespone, req.EndGetResponse)
which can obviously fail with a WebException. To the caller I want to return a Task<HttpResult> where HttpResult is a helper type to encapsulate the response (or not). In this case a 4xx or 5xx response is not an exception.
Therefore I've attached two continuations to the request task. One with TaskContinuationOptions OnlyOnRanToCompletion and the other with OnlyOnOnFaulted. And then wrapped the whole thing in a Task<HttpResult> to pick up the one result whichever continuation completes.
Each of the three child tasks (request plus two continuations) is created with the AttachedToParent option.
But when the caller waits on the returned outer task, an AggregateException is thrown is the request failed.
I want to, in the on faulted continuation, observe the WebException so the client code can just look at the result. Adding a Wait in the on fault continuation throws, but a try-catch around this doesn't help. Nor does looking at the Exception property (as section "Observing Exceptions By Using the Task.Exception Property" hints here).
I could install a UnobservedTaskException event handler to filter, but as the event offers no direct link to the faulted task this will likely interact outside this part of the application and is a case of a sledgehammer to crack a nut.
Given an instance of a faulted Task<T> is there any means of flagging it as "fault handled"?
Simplified code:
public static Task<HttpResult> Start(Uri url) {
var webReq = BuildHttpWebRequest(url);
var result = new HttpResult();
var taskOuter = Task<HttpResult>.Factory.StartNew(() => {
var tRequest = Task<WebResponse>.Factory.FromAsync(
webReq.BeginGetResponse,
webReq.EndGetResponse,
null, TaskCreationOptions.AttachedToParent);
var tError = tRequest.ContinueWith<HttpResult>(
t => HandleWebRequestError(t, result),
TaskContinuationOptions.AttachedToParent
|TaskContinuationOptions.OnlyOnFaulted);
var tSuccess = tRequest.ContinueWith<HttpResult>(
t => HandleWebRequestSuccess(t, result),
TaskContinuationOptions.AttachedToParent
|TaskContinuationOptions.OnlyOnRanToCompletion);
return result;
});
return taskOuter;
}
with:
private static HttpDownloaderResult HandleWebRequestError(
Task<WebResponse> respTask,
HttpResult result) {
Debug.Assert(respTask.Status == TaskStatus.Faulted);
Debug.Assert(respTask.Exception.InnerException is WebException);
// Try and observe the fault: Doesn't help.
try {
respTask.Wait();
} catch (AggregateException e) {
Log("HandleWebRequestError: waiting on antecedent task threw inner: "
+ e.InnerException.Message);
}
// ... populate result with details of the failure for the client ...
return result;
}
(HandleWebRequestSuccess will eventually spin off further tasks to get the content of the response...)
The client should be able to wait on the task and then look at its result, without it throwing due to a fault that is expected and already handled.
In the end I took the simplest route I could think of: hide the exception. This is possible because WebException has a property Response which gives access to the HttpWebResponse I want:
var requestTask = Task<WebResponse>.Factory.FromAsync(
webReq.BeginGetResponse,
ia => {
try {
return webReq.EndGetResponse(ia);
} catch (WebException exn) {
requestState.Log(...);
return exn.Response;
}
});
And then handle errors, redirects and success responses in the continuation task.