I'm trying to verify some conditions on application startup, such as the presence of critical files in the system.
To do this, I'm using a SerlvetContextListener, which tests for a bunch of conditions on startup.
How can I make so that the application rejects the deployment in Tomcat, if any of these conditions is not met? I could throw an exception, and catch that in the logs, but I'd like the application not to start at all.
Even failing Tomcat service startup would be a solution.
What's the simplest way? Should I try connecting to the Tomcat manager and undeploy the app?
Well...
According to your original question, you'd like the application to "not start at all" if certain files aren't there (or other conditions aren't met). Logically, it follows that the checking of the conditions can't possibly be a part of the application (if the checking is to be done as a part of the application - say, upon startup - then the application must be started for those checks to take place).
So:
If you don't want the application to start at all unless certain conditions are met, then your solution must be external to the application. For example, you could write your own Tomcat startup script that will check for your conditions first, and only then start Tomcat up.
If you don't mind the application starting and performing the checks, then the ServletContextListener is precisely what you should take advantage of. Throwing an exception from within contextInitialized() will result in the application being "unavailable" for serving requests. Alternatively, you could communicate with Tomcat's MBeans to stop the application if checks don't pass.
Related
In our project, we have several Spring-based modules which are deployed on WAS as web applications. We need to skip deployment, or stop a module if its Spring context initialization fails (i.e. ContextLoaderListener#contextInitialized or DispatcherServlet#init throws an exception). Now, if such happens, app is got deployed and starts, but returns HTTP 500 for any request.
Websphere 8.5.5
Related question: https://stackoverflow.com/a/272747/3459206
This APAR seems to be relevant:
https://www-01.ibm.com/support/docview.wss?uid=swg1PI58875
From the APAR text:
Listener exceptions typically should not stop the application
from starting up for service. However, some applications depend
on their listeners to do the necessary setup before the
application is started for service. Such applications prefer to
stop the application from starting up when there is any
exception in their listeners.
Problem conclusion
The WebContainer Container code was modified to provide an
option to stop the application when there is any listener
exception during the application starting up process.
A new WebContainer custom property needs to be set to enable the
behavior provided by this APAR:
For Full Profiles
com.ibm.ws.webcontainer.stopappstartuponlistenerexception = true
(default is false)
For Liberty Profile
stopappstartuponlistenerexception=true
The fix for this APAR is currently targeted for inclusion in
WebSphere Application Server fix packs 8.5.5.11 and 9.0.0.2,
and Liberty 16.0.0.3
See the APAR link for additional information.
You can use jenkins + maven.
Add the part you need to check under your test like junit.
Then if this module do not pass test, jenkins would not deploy it.
But I prefer fix bugs before deployment
Had a very similar issue.
The thing is - webfear - sorry could not resist ;-) does not initialize everything on startup.
To trigger a controlled request, I added a ScheduledEJB to the startup of the application. This bean itself triggered a http-request to a defined URL, which itself triggered:
any filters to get initialized in the chain
any contexts which are needed are initialized
And this itself ensured that my application (EAR or WAR) got very quickly tested after deployment. This works well with some small amout of requests per minute
If you work with high load, means tons of requests per second, you need to choose a different approach.
In this case I added a polling mechanism into the #Startup of the application, which polled every second or 250ms (depends on the load of the application).
This firing to the server ensured, that my #Startup bean was the very first which triggered the possible init issues in the application. If this happened I initialized a filter which always reported a 500 (or better fitting error) to the requestor.
Of course stop your firing bean, as soon as you get the 500, else your admins may like to kill you. (happend to me, since I produced tons or monitoring issues ;-) )
And of course on the regular operation, after your application started properly, you should also disable the polling
Look for a try-catch in the top level of your application code that is catching the Spring exception and allowing the application to continue running.
If the Spring exceptions being thrown are permitted to propagate to the top of the stack, the JVM will stop and there's no way it can keep running, far as I know.
I am facing the problem of finding the best place to put some handling where I can check some of the properties in application.yml and fail app startup of Spring Boot app if they are invalid.
The main point is to find the first place where I can check these properties without running the entire app and fail in the end.
I tried:
#EventListener, but here I was able only to trigger events when the app was started.
Throwing an exception in #PostConstruct in one of my classes with #Configuration. I like this one, but it looks like a messy one.
Maybe there are better ways?
#EventListener, but here I was able only to trigger events when the
app was started
There are many different type of events and where you hook in to the startup process depends on the type of event that you listen for. In your case, consider listening for an ApplicationEnvironmentPreparedEvent if you want to check properties as soon as they are available.
I would like Flyway to run whenever I deploy a new war to my server.
Does flyway automatically get run when a server is deployed? Do I have to always automate a script which would then the flyway migration command? Or what is the best way to do this?
Server:
The server is a Java Tomcat Server running on Elastic Beanstalk (AWS) that is connected to a MySQL database.
Deployment Process
We run our sql migration scripts on the database manually. Then we upload a new war of the server to Elastic Beanstalk.
This can be useful:
Auto-migration on startup : https://flywaydb.org/documentation/api/
So for Java all it takes is to create scripts (eg. V1__initial_schema.sql, ...), put them under /src/main/resources/db/migration/
and then:
Flyway flyway = new Flyway();
flyway.setDataSource(...);
flyway.migrate();
As the comments said, there may be multiple ways to do this.
ServletContextListener
One common way is to use the hook defined by the Java Servlet spec for being notified when your web app is launching and shutting-down. That hook is the ServletContextListener interface. Add a class to your project implementing the two methods in this interface, one for launch and one for shutdown. In the launch method, run your Flyway code.
The word “context” is the technical term meaning your web app.
contextInitializedYour web app is launching. No incoming web request has yet been handled, and will not be handled until your implementation of this method completes. Run your Flyway migrations here.
contextDestroyedYour web app is shutting down. The last remaining web request has been serviced, and no more will be accepted.
Annotating this class with #WebListener is the easiest of multiple ways to get your Servlet container to register an instance.
Pretty easy.
Your ServletContextListener is guaranteed to be called and run to completion before the first execution of any Servlet (or Filter) in your web app. So this is the perfect place to do setup work that you want finished before your servlets go to work. Flyway seems like a natural fit to me.
Search Stack Overflow for “ServletContextListener” to learn more and see examples, such as my own Question & Answer.
Handling failure
Be aware that stopping a web app’s deployment when something goes wrong (when your ServletContextListener encounters an Exception) is not well-defined in the Servlet spec.
An example might be your Flyway migrations failing for some reason, such as not able to connect to database. At that point you might want to halt deployment of your web app.
See my own Question and Answer and the group of related questions I list in that answer. Tomcat 8.0.33 halts the deployment, and un-deploys the web app, but unfortunately does not report the offending Exception (or at least I could not find any such report in the logs nor in the IDE console while in development mode). The behavior of other Servlet containers may vary.
I have to implement a special conditions check in the existing WAR application deployed in Tomcat 7. I have created a Servlet that perform necessary checks on it's init() method. So, during WAR startup everything is being checked.
Now, if I want the WAR application to be accessible only when all the conditions are met and some condition did not work - how can I stop the deployment of the WAR? In the other words how can I prevent access to the WAR application?
As an example of such condition: for example, I found that the database is not properly updated and therefore application will crash on attempt to access the DB.
My webapp is part of a larger EAR that is deployed into a websphere server. The server hosts number of other apps on the same virtual server. My webapp has some initialisation/health checks in a servletContextListener->contextInitialized method. I want to make the webapp unavailable if initialisation/health checks fail. What is a realiable way of doing this? Will throwing a RuntimeException from within contextInitialized suffice? Is the rest of the EAR still expected to be available? Thank you.
I'd recommend throwing a RuntimeException from ServletContextListener.contextInitialized.
Servlet 2.3 wasn't very clear on this, but Servlet 2.4 added the following detail:
Some exceptions do not occur under the
call stack of another component in the
application. An example of this is a
… ServletContextListener that
throws an unhandled exception during a
notification of servlet context
initialization…. In this case,
the Developer has no opportunity to
handle the exception. The container
may respond to all subsequent requests
to the Web application with an HTTP
status code 500 to indicate an
application error.
Since it says that the servlet engine "may" disable access to application, you might find a server that does something else. However, Tomcat and WebLogic both disable the application, and the only other reasonable thing I can think of would be to ignore the exception. I can't see a container that did that being very popular—so you'd better test it in WebSphere yourself.
Throwing a RuntimeException will probably make only that servlet unavailable. A safer way might be to implement something like a Spring interceptor that will forward to an error page or something if the checks didn't pan out. That way, you don't need to prevent the app from loading, but can handle it more gracefully at run time.