I have a Spring based Wicket app.
There's a pooled datasource bean.
Now, when MySQL is dead, I get a default Wicket error page with a stacktrace.
I'd like to handle this situation and to only allow some pages to fully display (the static ones), and to show a custom error page for the others.
How should I efficiently implement this?
I know I could catch exceptions in the page's code, but this is kind of unreliable MySQL instance and it's down quite often :) Or, think of other kind of unreliable resource.
Putting an if for each page seems inefficient. I'd like some list of pages that need the resource, and redirecting requests to it to a custom error page.
I was thinking about having some global boolean isResourceReady, and some thread which would start upon that error and periodically check for availability, and eventually allow the dynamic pages when the resource is back.
Thanks for tips.
Root cause:
java.net.ConnectException: Connection refused
at ... java.net stuff
... JDBC stuff
... Spring stuff
... DBCP and Pool stuff
... Hibernate stuff
at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:88)
at cz.oz.wicket.stack.dao.TestEntityDaoImpl$1.doInJpa(TestEntityDaoImpl.java:36)
at org.springframework.orm.jpa.JpaTemplate.execute(JpaTemplate.java:184)
at cz.oz.wicket.stack.dao.TestEntityDaoImpl.createSyntheticTestEntity(TestEntityDaoImpl.java:32)
at cz.oz.wicket.stack.pages.home.HomePage.<init>(HomePage.java:31)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.apache.wicket.session.DefaultPageFactory.createPage(DefaultPageFactory.java:188)
at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:65)
at org.apache.wicket.request.target.component.BookmarkablePageRequestTarget.newPage(BookmarkablePageRequestTarget.java:298)
at org.apache.wicket.request.target.component.BookmarkablePageRequestTarget.getPage(BookmarkablePageRequestTarget.java:320)
at org.apache.wicket.request.target.component.BookmarkablePageRequestTarget.processEvents(BookmarkablePageRequestTarget.java:234)
at org.apache.wicket.request.AbstractRequestCycleProcessor.processEvents(AbstractRequestCycleProcessor.java:92)
at org.apache.wicket.RequestCycle.processEventsAndRespond(RequestCycle.java:1250)
at org.apache.wicket.RequestCycle.step(RequestCycle.java:1329)
at org.apache.wicket.RequestCycle.steps(RequestCycle.java:1428)
at org.apache.wicket.RequestCycle.request(RequestCycle.java:545)
at org.apache.wicket.protocol.http.WicketFilter.doGet(WicketFilter.java:479)
at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:312)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230)
at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:926)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:549)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410)
at org.mo
You might be best off using the normal error page handling in Wicket.
But if you want to anticipate the exception instead of reacting to it, this seems like a natural application of a ServletFilter. Particularly if you're already using the spring OpenSessionInViewFilter, you might subclass that and override the
protected Session getSession(SessionFactory sessionFactory)
to detect that you've got no database connection and forward to a special page.
If you're doing it by a filter, the decision of whether to go to the error page or not might still have to be driven by some sort of global, but this might just be a list of your static pages that you maintain in your WebApplication object, which is already a singleton.
Make as low as possible in contructor.
Do more in onInitialize(), has better control over errors.
Related
I have a strange behaviour which I can't find any solution for days..
The behaviour I experience is the classic LazyInitializationException with no session or session was closed
which is usual when there's no contextual session and trying to access lazy loaded properties/collections, but this in not my case because I have:
Session-per-request session bounded with Spring.NET OpenSessionInViewModule
A session opened and bounded to the context (web request)
Entities with collection as "list" (mapping list collection) with lazy="extra" or with "set" (mapping set collection) (The issue is caused mainly with lazy=extra..)
It seems that the Count statement for extra cound be done, but accessing the whole collection throws the exception
After investigating the usual issues:
no session opened
the object is not bounded to any session
a call to Session.Clear or Session.Evict was made (so any lazy for the evicted instance will work)
the Spring.NET WebSupportModule is not registered
I found no explicit reasons of why this happen..
A strange behaviour is if I profile in NHprof, I see the exception in a new session, in other words, the contextual session works correctly,
but when the exception is thrown, that exception is visualized in a secondary session.. but NO code open a session, and a single, contextual session
is opened..
Anyone knows what other reasons could cause a situation like that?
Thanks in advance
It's difficult to diagnose without seeing some code, but the problem sounds very similar to this. In the linked case OpenSessionInView was being used in addition to setting the session context in another location (similar to your first two bullet points) and WebSupportModule was not registered (as in your last point).
On the other hand, I know nothing about Spring.NET.
I get the following error within Magento CE 1.6.1.0
Warning: session_start() [<a href='function.session-start'>function.session-start</a>]: Cannot send session cookie - headers already sent by (output started at /home/dev/env/var/www/user/dev/wdcastaging/lib/Zend/Controller/Response/Abstract.php:586) in /home/dev/env/var/www/user/dev/wdcastaging/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php on line 119
when accessing /api/soap/?wsdl
Apparently, a session_start() is being attempted after the entire contents of the WSDL file have already been output, resulting in the error.
Why is magento attempting to start a session after outputting all the datums? I'm glad you asked. So it looks like controller_front_send_response_after is being hooked by Mage_Persistent in order to call synchronizePersistentInfo(), which in turn ends up getting that session_start() to fire.
The interesting thing is that this wasn't always happening, initially the WSDL loaded just fine for me, initially I racked my brains to try and see what customization may have been made to our install to cause this, but the tracing I've done seems to indicate that this is all happening entirely inside of core.
We have also experienced a tiny bit of (completely unrelated) strangeness with Mage_Persistent which makes me a little more willing to throw my hands up at this point and SO it.
I've done a bit of searching on SO and have found some questions related to the whole "headers already sent" thing in general, but not this specific case.
Any thoughts?
Oh, and the temporary workaround I have in place is simply disabling Mage_Persistent via the persistent/options/enable config data. I also did a little bit of digging as to whether it might be possible to observe an event in order to disable this module only for the WSDL controller (since that seems to be the only one having problems), but it looks like that module relies exclusively on this config flag to determine it's enabled status.
UPDATE: Bug has been reported: http://www.magentocommerce.com/bug-tracking/issue?issue=13370
I'd report this is a bug to the Magento team. The Magento API controllers all route through standard Magento action controller objects, and all these objects inherit from the Mage_Api_Controller_Action class. This class has a preDispatch method
class Mage_Api_Controller_Action extends Mage_Core_Controller_Front_Action
{
public function preDispatch()
{
$this->getLayout()->setArea('adminhtml');
Mage::app()->setCurrentStore('admin');
$this->setFlag('', self::FLAG_NO_START_SESSION, 1); // Do not start standart session
parent::preDispatch();
return $this;
}
//...
}
which includes setting a flag to ensure normal session handling doesn't start for API methods.
$this->setFlag('', self::FLAG_NO_START_SESSION, 1);
So, it sounds like there's code in synchronizePersistentInf that assumes the existence of a session object, and when it uses it the session is initialized, resulting in the error you've seen. Normally, this isn't a problem as every other controller has initialized a session at this point, but the API controllers explicitly turns it off.
As far as fixes go, your best bet (and probably the quick answer you'll get from Magento support) will be to disable the persistant cart feature for the default configuration setting, but then enable it for specific stores that need it. This will let carts
Coming up with a fix on your own is going to be uncharted territory, and I can't think of a way to do it that isn't terribly hacky/unstable. The most straight forward way would be a class rewrite on the synchronizePersistentInf that calls it's parent method unless you've detected this is an API request.
This answer is not meant to replace the existing answer. But I wanted to drop some code in here in case someone runs into this issue, and comments don't really allow for code formatting.
I went with a simple local code pool override of Mage_Persistent_Model_Observer_Session to exit out of the function for any URL routes that are within /api/*
Not expecting this fix to need to be very long-lived or upgrade-friendly, b/c I'm expecting them to fix this in the next release or so.
public function synchronizePersistentInfo(Varien_Event_Observer $observer)
{
...
if ($request->getRouteName() == 'api') {
return;
}
...
}
I need some insights and thoughts about a refactoring I'm about to do to our web-app.
We initially used the session-per-request pattern with NHibernate and ActiveRecord by using the On_BeginRequest / On_EndRequest in the HttpApplication to create and dispose the session. Later on, we realized that any DB-related exceptions got thrown outside of our monorail-context, meaning that our rescues didn't kick in. As another sideeffect, we didn't have the option to fully skip creation of NHibernate sessions in any action, which in some cases would be desirable.
So we rewrote it to create sessions in Initialize() / Contextualize() in our base controller, and disposed them in the Dispose() of our base controller. We also Rollback the session in our rescue controller to prevent any half written changes to the DB. So far, so good. The reason for doing it in the Dispose() is because we want it to live through the view-rendering, because of lazy-loading reasons aswell as viewcomponents that needs to get a session (we could switch to units-of-work for the viewcomponents, but they don't seem to have a Dispose()...)
However, I'm experiencing some deadlock issues where we have started transacations in the DB that isn't getting rollbacked nor committed and I can't get my head around it, mostly because of the mess we've made with this approach...
So I found this article: http://hackingon.net/post/NHibernate-Session-Per-Request-with-ASPNET-MVC.aspx
And I thought, "Filters, we can use that in MonoRail too!", because it can kick in on BeforeAction and AfterRendering.
My questions then are:
What happens if an Exception occurs in the filter?
Will AfterRendering fire even if an Exception occurs in the action or the rendering?
Would you recommend this approach, if not, what are your suggestion instead?
Any pointers are very much appreciated!
You need an application error handler to care of exception handling.
Attach a debugger and find out.
Probably not (even though it is my article). It doesn't work with RenderAction. Best to use an IoC container to control the lifetime of connections.
I'm running two glassfish v2 domains containing stateless session EJBs. In a few cases, an EJB in one domain has to call one in the other.
My problem is that when the called EJB aborts with an exception, the caller does not receive the message of the exception and instead reports an internal error that is not helpful at all in diagnosing the problem. What happens seems to be this:
At the transport layer, a org.omg.CORBA.portable.ApplicationException is created,which already loses all detail information about the exception except its class.
Inside com.sun.jts.CosTransactions.TopCoordinator.get_txcontext(), the status of the transaction ass rolled back causes a org.omg.CosTransactions.Unavailable to be thrown, which gets wrapped and passed around a few times and eventually results into this error being displayed to the user:
org.omg.CORBA.INVALID_TRANSACTION: vmcid: 0x0 minor code: 0 completed: No
at com.sun.jts.CosTransactions.CurrentTransaction.sendingRequest(CurrentTransaction.java:807)
at com.sun.jts.CosTransactions.SenderReceiver.sending_request(SenderReceiver.java:139)
at com.sun.jts.pi.InterceptorImpl.send_request(InterceptorImpl.java:344)
at com.sun.corba.ee.impl.interceptors.InterceptorInvoker.invokeClientInterceptorStartingPoint(InterceptorInvoker.java:271)
at com.sun.corba.ee.impl.interceptors.PIHandlerImpl.invokeClientPIStartingPoint(PIHandlerImpl.java:348)
at com.sun.corba.ee.impl.protocol.CorbaClientRequestDispatcherImpl.beginRequest(CorbaClientRequestDispatcherImpl.java:284)
at com.sun.corba.ee.impl.protocol.CorbaClientDelegateImpl.request(CorbaClientDelegateImpl.java:184)
at com.sun.corba.ee.impl.presentation.rmi.StubInvocationHandlerImpl.privateInvoke(StubInvocationHandlerImpl.java:186)
at com.sun.corba.ee.impl.presentation.rmi.StubInvocationHandlerImpl.invoke(StubInvocationHandlerImpl.java:152)
at com.sun.corba.ee.impl.presentation.rmi.bcel.BCELStubBase.invoke(BCELStubBase.java:225)
Is there anything I can do here to preserve information about the actual cause of the problem?
The cause of the problem should be available in the server log of the domains hosting the EJB that had a problem.
It sounds like getting more info back from the other end may be difficult... I do not know which issue tracker would be the right one for the info lost when the ApplicationException is created/thrown.
A total hack would be to create a set of custom exception classes in the project that has the ejb that has failed. You would make them very fine grained to cover the likely causes of the problem and provide enough detail in their name to identify the actual location of the problem, too. Yucky... but that may be the only choice until an issue gets filed and the fix is distributed.
Is there anything I can do here to
preserve information about the actual
cause of the problem?
Unfortunately, no. The ORB does not use normal object serialization for system exceptions (i.e., org.omg.CORBA.*), which means that causes are lost. As #vkraemer said, you'll need to rely on server logs.
I finally got to the bottom of this: actually, Glassfish transmits exceptions through IIOP quite correctly and everything works as it should... unless you do something idiotic like this:
try{
ejb.getFoo();
}catch (Exception e){
// try again
ejb.getFoo();
}
Yeah, it was our own damn code that swallowed the exception and tried to call a transaction-requiring EJB method within a distributed transaction that's been rolled back due to the exception.
Is there a way to catch all SQL exceptions in a project? I have several gridviews and multiple sqldatasources and most of the errors are going to occur when a user enters something incorrectly or in the wrong column. So how do I stop the Server Error in /Project page from showing up?
The simple answer is, validate the input before you send it to SQL Server. That way, there won't be any exceptions thrown.
If you wish to handle all your errors centrally (which is not the ideal solution for this particular problem), you can set up custom error handling in your web.config file.
I would suggest catching error in the Application_Error event inside your Global.asax in your web application.
The easiest way to catch all exceptions is to do it in Application_error event handler in global.asax, and utilize the web.config custom error handling to show a friendly error page. These are already mentioned by mikeware.
If you want to put all your validation logic in one place / separate them from your aspx pages, you could do it by making your website multi-layered and put your custom validation logic in the middle layer. By using this method, your data will get validated in that layer no matter which page is accessing your data. You can also use objectdatasource to do select/insert/update/delete operation. Obviously it requires some work, but it can clearly separate your data and your UI.