Scheduled task in a web application? [duplicate] - java

This question already has answers here:
What is recommended way for spawning threads from a servlet in Tomcat
(5 answers)
Closed 8 years ago.
I'm building a statistics apps for an online game, built using the servlet API in Java (to be deployed on Tomcat). It's easy enough to let the game send a message to the stats server every time a user logs in, because handling requests is what Servlets/Tomcat are for.
I also need to periodically initiate requests on the stats server though, for example to retrieve the number of online users from the game server or the number of fans from our Facebook page.
It would be easy to just start a thread in the app's main servlet and let that do the data retrieval once in a while, but it feels a bit strange because all other threads are created by Tomcat.
Is doing it like that ok?
If not, what is the recommended way of doing this?
Is it even correct to use servlets for something like this? What's the alternative?
Note after first answers: I'm not looking for a solution to the problem of timing or concurrency, because I can easily handle both. I just need to know how to properly start a pro-active process in a servlet container.

Quartz is your best bet, and most highly configurable. It has CRON based interface or a more dynamic way to generate jobs that are relative from a specific event, if your use case calls for it Quartz can do it. It has the ability to persist jobs to the database so they can survive restarts.
http://www.quartz-scheduler.org/
Make configurations in web.xml like this to auto-start it:
<servlet>
<servlet-name>QuartzInitializer</servlet-name>
<display-name>Quartz Initializer Servlet</display-name>
<servlet-class>org.quartz.ee.servlet.QuartzInitializerServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>shutdown-on-unload</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>start-scheduler-on-load</param-name>
<param-value>true</param-value>
</init-param>
</servlet>

You should consider:
Quartz
The "regular" TimerTask
If you're using spring on your webapp, there is a dedicated part for it
Don't bother reinventing the wheel, Quartz and other products already handle Threads/timeouts/concurrency issues for you!

Related

Vaadin 19/20 + official gradle plugin - custom servlet subpath to run within existing legacy web application along another Java framework

Environment
Spring 4.3 (no Spring Boot!), JDK 8/11, Tomcat 8.5.x, Vaadin 19/20-SNAPSHOT
I have a legacy webapp running another servlet-api-driven web framework at http://app.com. I want to add a path that adds a Vaadin-driven UI to this application - let's say at http://app.com/vaaadin-app . I'm using the newly developed official Gradle plugin. (Both Vaadin and non-Vaadin web applications should be run from single WAR, effectively sharing single classloader for shared state access, so no proxy/rewrite/etc solutions will help here).
Problem
After adding dependencies the Vaadin app is properly built and war created. Yet as soon as I call http://app.com (not http://app.com/vaadin-app) it looks like Vaadin servlet/whatever is taking over all requests. It looks like it is automatically initialized by (I guess) servlet 3.0 annotations.
Question
How can I enable Vaadin only for http://app.com/vaadin-app and keep it away from altering requests not directed there? I know with Vaadin 8 it was possible to achieve this with:
<servlet>
<servlet-name>vaadinServlet</servlet-name>
<servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
<init-param>
<param-name>UI</param-name>
<param-value>app.vaadin.additem.AddItemUI</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>vaadinServlet</servlet-name>
<url-pattern>/vaadin-app/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>vaadinServlet</servlet-name>
<url-pattern>/VAADIN/*</url-pattern>
</servlet-mapping>
In other words: how to prevent Vaadin 19/20 from spawning itself automatically for /* but to serve application only when user hits the /vaadin-app/* servlet path???
I think in case of maven plugin there was the "disable.automatic.servlet.registration" option to achieve this? But I don't see anything like this in case of Gradle plugin.
Thanks!
The servlet registration in Vaadin should have nothing related to Gradle, so applying the generic instructions should work. The automatic servlet registration is omitted if you define a VaadinServlet manually (extend it and map the servlet to your location of choice using #WebServlet).
Check this part of the documentation for more details: https://vaadin.com/docs/latest/flow/advanced/application-lifecycle/#automatic-servlet-registration

Asynchronous service calls on server startup

I'm trying to create a simple RESTful application that helps people create and retrieve certain objects. The objective of the service is to serve up these objects as quickly as possible, which is why I'm considering cheating a little by "pre-creating" the objects during the server startup time in an asynchronous fashion. I can get away with this model because I know that there are only 500 different flavors of objects that people can ask for so i'd rather have them readily sitting in my persistent store (redis) warmed up such that by the time a user is asking for it, it's ready to serve.
My question is around how to enable this "background/async" processing right around the server startup (for a server like jBoss/tomcat in a RESTful service written in java). Putting it into a static block in the class serving results doesn't work, so I was wondering if there's a config in the catalina files that can link to loading a class which in turn could do the needful.
I think you may be looking for load-on-startup in your web.xml file, and then if you use the Init method in your HttpServlet class you may get the behavior you want.
Load-on-startup is a directive to tell the container to start that class immediately upon startup.
<servlet>
<servlet-name>ServletOne</servlet-name>
<servlet-class>com.yourcomp.MainServlet</servlet-class>
<description>This servlet is an example servlet</description>
<load-on-startup>1</load-on-startup>
</servlet>

spring web services configuration in web.xml?

I am using spring-ws and I have the below configuration in my web.xml
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>**transformWsdlLocations**</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Here I have transformWsdlLocations configured. Please explain me the use of transformWsdlLocations here. I am using the dynamic WSDL generation concept.
Is transformWsdlLocations really required for dynamic WSDL generation?
Thanks!
Given that it only takes a couple of minutes to remove the value and redeploy your application, I would advise you to do that and see what happens. Just try accessing the WSDL through "localhost" and through "127.0.0.1", and see what differences there are.
However I'll explain what you should see here...
When you read the WSDL that is generated, you should find that there are URLs in there.
i.e. From the local machine you might use:
http://localhost:8080/myservice.wsdl
But when you go live, your service might be:
http://www.<yourdomain>.com/myservice.wsdl
You don't want someone downloading the WSDL from your production domain to have those values populated with "localhost:8080". Likewise, you can't test your service properly if the URL being returned in the WSDL is for your production server. Or you might have multiple production services with different URLs.
transformWsdlLocations ensures that this is generated dynamically based on whatever URL is being used to access the service.
It is not needed for dynamic WSDL generation, but I have always found it very useful to have it. However, it is not enabled by default, so if you do want those URLs to be generated dynamically then it's best to include it.

Web app and Tomcat 7 Memory Leak

I am (test) running my web app in Tomcat 7 and using their "Find Leak" button and of course it complains about memory leak when I stop / undeploy.
The following web applications were stopped (reloaded, undeployed),
but their classes from previous runs are still loaded in memory, thus
causing a memory leak (use a profiler to confirm):
/LeakyWebApp
So I used Java VisualVM (my first time trying this out)
on Tomcat startup with no deployment:
http://img15.imageshack.us/img15/4441/tomcatstartup.jpg
My web app involves:
Quartz 1.8.5
Hibernate 3.6.3
JAXB 2.2.4
Salesforce API
log4j
Immediately after deployment: http://img850.imageshack.us/img850/2951/tomcatafterdeployment.jpg
So I noticed it complains about Quartz and I also read somewhere to close Hibernate Session Factory on servlet destroy.
On stop / undeploy, The Visual VM does show the Quartz thread stopped, but the tomcat log says
"appears to have start a thread named ... and has failed to stop it"
So I created a new ServletContextListener and on contextDestroyed I call to Quartz factory scheduler to shutdown and also call close on Hibernate Session Factory. and doing another deploy/undeploy, there's no more complain from the tomcat log about Quartz thread problem as above.
However, when I use "find leaks" it still complains about the same thing
The following web applications were stopped (reloaded, undeployed),
but their classes from previous runs are still loaded in memory, thus
causing a memory leak (use a profiler to confirm):
/LeakyWebApp
Then i found another complain about JDBC driver (I have mysql connector jar in my war), so I tried removing that, the complain from tomcat log disappear but the "Find Leaks" still say the same thing that my web app has memory leaks
So my question would be - what else should I be looking at? and/or how can I use the Visual VM better to detect what's going?
Thanks
EDIT:
I fixed the issue with Quartz based on the post by David Feitosa, I was missing
<init-param>
<param-name>wait-on-shutdown</param-name>
<param-value>true</param-value>
</init-param>
from the Quartz properties in web.xml.
However - I still have issue with the JDBC driver - I need it for my web app, and seems like I have 2 solutions based on the answers from: To prevent a memory leak, the JDBC Driver has been forcibly unregistered
Put the mysql-connector jar in the tomcat/lib
Manually un-register the driver in the contextDestroyed.
Which way should I go and what's the best practice for this?
Most of the problems with memory leaks that I found in this kind of web app is related to Quartz. In order to solve this, try to use the proper Quartz Servlet to init the factory: http://quartz-scheduler.org/api/2.0.0/org/quartz/ee/servlet/QuartzInitializerServlet.html
As in the Quartz doc, try to use:
<servlet>
<servlet-name>
QuartzInitializer
</servlet-name>
<display-name>
Quartz Initializer Servlet
</display-name>
<servlet-class>
org.quartz.ee.servlet.QuartzInitializerServlet
</servlet-class>
<load-on-startup>
1
</load-on-startup>
<init-param>
<param-name>config-file</param-name>
<param-value>/some/path/my_quartz.properties</param-value>
</init-param>
<init-param>
<param-name>shutdown-on-unload</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>wait-on-shutdown</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>start-scheduler-on-load</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
Hope this can help you.

Shiro in a multi-threaded environment

The basic way that I understand Shiro's SecurityUtils.getSubject() to work is that it returns the subject which is bound to the currently executing thread. However, this just seems at odds with a servlet container like Tomcat which is using a thread pool to service requests.
If Tomcat is say using ThreadA to handle requests, any calls to SecurityUtils.getSubject() should work fine. But, as soon as ThreadB is selected, the user is lost, getSubject returns null and isAuthenticated is now false. This is even though the user is still logged in.
I have confirmed this in my application. I am using Shiro Core 1.2 and notice that my user is just miraculously being inauthenticated when I navigate through my app. If I look at the logs, the problem happens as soon as a different thread is used to service the request.
So, do I have Shiro configured incorrectly? It seems like the 'current user' should be bound to something a bit more longer-lasting than the current thread. I would expect it to be session-based. I know that Shiro has session management, but in all examples I've found, it says to get the current user by calling getSubject, which looks at the ThreadContext. Am I missing something?
So, it turns out that I just didn't have Shiro configured correctly. I have a web app, yet I was setting up the Security Manager in code. This resulted in the Security Manager being set up on a certain thread only. As long as requests were serviced by that same thread, it worked fine. But as soon as Tomcat chose a different thread, the user appeared inauthenticated.
Shiro has a filter for web apps that handles this scenario and binds the user to each incoming request. You should have your app configured as follows instead of doing the security manager in code:
<context-param>
<param-name>shiroConfigLocations</param-name>
<param-value>classpath:auth.ini</param-value>
</context-param>
<!-- Shiro Environment Listener -->
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<!-- Shiro Filter Configuration -->
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Categories