In my test application (JSF, PrimeFaces, Wildfly 8) I have a simple messaging interface for writing a message and viewing those that were sent to me. I now would like to create an automatic respond for those messages that were not answered after 5 minutes. This automatic respond is meant to be independent of any person sitting behind the browser window and clicking the refresh button.
My current idea is to create a new class annotated with #ApplicationScoped. This class shall run an individual thread handling the responding process. Would that be a good approach? Or is there a functionality somewhere that already covers this matter?
I think the option worth considering would be to use javax.ejb.TimerService:
#Stateless
public class AutomaticResponseSender {
private static final Integer _5_MINS = 300000;
#Resource
private TimerService timerService;
public void waitFiveMinutes() {
Timer nextTimer = timerService.createSingleActionTimer(_5_MINS, null);
}
#Timeout
public void autoRespondForNotAnswered() {
// here send an auto response
}
public void cancel() {
timerService.cancel();
}
}
Upon sending the manual answer you need to call cancel() to avoid autoresponse or, alternatively, you can check in autoRespondForNotAnswered() method if the answer was send.
Another approach could be to use #Schedule and, let's say every 5 or 10 seconds, check for messages not answered in 5 mins and sending automatic answers for them.
Related
I've a scheduler class and another class a custom http client.
The scheduler is initialized on application start up and does the work in background for example querying a service (url) every 30 seconds and write the data to logs.
The http client is created with the url as well.
The url can change anytime so I need to make sure whenever it is the both log scheduler and http client are reinitialized with new url.
public class LogScheduler {
public log() {
synchronized(globallock) {
String url = getUrl();
//log some activity
}
}
}
We have another scheduler which is looking for new url every 30 minutes.
public class UrlScheduler {
private volatile String url;
public void check() {
String url = service.getNewUrl();
if(url!=this.url) {
synchronized(globallock) {
this.url=url;
reinitialize http client
}
}
}
public String getUrl(){
return url;
}
}
Right now I'm using global lock to make sure the log scheduler sees the value as soon it is changed by url scheduler. I really don't like the idea of using global lock as it breaks encapsulation along with other issues.
How could I change my set up to to reinitialize log scheduler and http client as soon the url is changed and sync them as it is changed in order ? I would like to avoid re-initialization if url hasn't changed.
Also how could I block the ui thread using http client if the url is being updated when the request was made.
This is a spring application.
Let me know if it is not clear and I'm happy to provide more details.
Working with limited information, if anything wouldn't work let me know and I'll change it.
To me the simplest thing is to decouple the HTTPClient from anything that may need it. Decoupling the client means you don't need to deal with synchronization issues in classes that are focused on other things(e.g. logging or pinging the service)
Here's a diagram. https://i.imgur.com/PWsXx2G.png
It seems like you'd be changing very little. The main differences is you'd create a wrapper for your HTTPClient, that way in the client you could synchronize it to make sure the HTTPClient is always the correct one.
An example wrapper, don't use this as it's very simple
public class HTTPClientProxy{
private final Object syncLock = new Object();
private HTTPClient client;
public HTTPClient getClient(){
synchronized(syncLock){
return client;
}
}
public void updateClient(URL url){
synchronized(syncLock){
client = new HTTPClient(url);
}
}
}
One potential issue, and one that I'm not sure about. Is if you have multiple services, and they all are bundler (e.g. are linked and need to use the same URL). Then you'll need to have something else on that side, so you can ensure they all use the same client. However this would be a good start as it stops you from worrying about getting bad data from the HTTPClient and moves that functionality into the proxy class.
I believe the observer pattern is useful here.
The URL scheduler, or whatever class is responsible for the knowing the state of the URL at any given point (called the subject), would maintain a list of observers (the other objects which wish to be notified when the URL changes), being the log scheduler and the other http client.
The observers simply implement an interface providing a notification function which accepts the new URL as a parameter. Whenever the url changes, the subject notifies everyone in its list of observers by calling their notification functions.
This makes it so that the log scheduler and other http client are only notified when the URL changes, and they are notified immediately.
If you wished to decouple the observers and subjects (generally more useful when there are many observers observing many subjects), you could build an event manager using a mediator pattern. However, this would probably be overkill given your requirements.
I would like to have the possibility to activate or deactivate jobs via:
a configuration file with specific ON/OFF for each job or
a mysql table with specific ON/OFF for each job.
Charging must take place at each change of status: for example, if a job is OFF when the ON setting (state change) the java app will be able to receive the status update.
Thanks for helping me out.
If I understood your question correctly, you are looking for capability to control your jobs from configuration. If yes, then following might be helpful.
You can schedule you jobs using Apache Camel routing.
public class JobExecutorRoute extends RouteBuilder
{
private String script="exec:yourjob.sh";
private String cron="quartz2://group/timer?cron=00+00+010+*+*+?" ;
public void configure() throws Exception {
from(script).autoStartup(true).to(cron);
}
}
This question already has answers here:
How to run a background task in a servlet based web application?
(5 answers)
Closed 6 years ago.
I have a Java application (running on WAS 8.5) which acts as a kind of server inventory for the client. The application has a servlet that triggers a long running process.
The process: fetches data from a third party DB, executes Java logic, writes records back to the application's own DB (these DB connections are pooled ones) .
The servlet is not load-on-startup and is manually triggered only once a month by a single Operations guy (on some particular date based on the client's choice each month). The servlet had been historically using Timer and TimerTask in this way:
public class SyncMissingServlet extends HttpServlet implements Servlet{
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
try{
SyncMissing.runSync();
}catch(Exception ex){
logger.error(new LogMessage("ERROR: "), ex);
this.sendReply(printWriter, "ERROR: " + ex.toString());
}
}
}
public class SyncMissing
{
public static void runSync() throws Exception
{
Timer t = new Timer(true);
SyncMissingTask task = new SyncMissingTask(); //SyncMissingTask is an instance of TimerTask
// Start the synchronization 5 secs from now, and run it every 30 days.
t.schedule(task, 5000, 2592000000l); //this 30 day timings never really worked out for the client,
//since the app server is restarted frequently for deployments.
}
}
There is no use of Timer.close() or TimerTask.close() in the current code.
Recently this Servlet seems to have got auto-trigerred, after a system reboot and restart of the WAS services on the system...and that's the worry.
While I couldn't explain the auto-trigger to my client, I proposed the following options:
1. drop off the use of Timer and TimerTask (the long-running process then runs on the servlet's thread itself)
2. instead of TimerTask, make it a regular Runnable and run it in a separate thread within the servlet thread.
3. make use of Java's Executor Service
4. migrate to Servlet 3.0 and turn the servlet into a Async servlet.
5. drop off the servlet altogether, and replace it with a batch job.
I understand that options 3 and 4 are really the recommended ones (or possibly option 5). But I have a feeling, that in my business scenario - Options 3 & 4 may be an overkill.
If the need is really a manual invocation of the servlet by only one user per month, are options 1 and 2 that bad?
(my client wants the quickest solution and would certainly not fund option 5)
Well, if the servlet is supposed to be run only once in a month and there is only one client triggering it, it is fine to run it in the servlet's thread itself or create a new thread inside the servlet and let that do the task. The question of load and response times arises when you have a lot of clients making simultaneous requests, at which point you might want to use an Executor service or an async servlet.
There is no need to activate a background task by invoking a servlet. Your web app has its own lifecycle. The Servlet spec provides hooks for your web app getting set-up and torn-down. Perfect place to launch and quit your background task without ever invoking a servlet by a client user.
No need to depend on a human user remembering to start the background task. Let your web app technology do the work for you.
Also, you may often hear/read "never launch threads from JSP or Servlet". This is worthy advice with regard to processing each incoming request for generating a web page. But background tasks (not directly related to a single servlet request) is a different animal; perfectly okay to have threads for background tasks as long as you handle them properly. By 'properly' I mean you explicitly end those threads appropriately, and you handle thread-safety issues. An example of a background task might be regularly polling a web service or database to refresh a cache of data.
ServletContextListener
If you want an automated task to be performed regularly within your web app, use a ServletContextListener.
That interface defines a pair of methods. One, contextInitialized, is called automatically when the web app launches, guaranteed to run before any HTTP requests are handled. The other method, contextDestroyed, runs when the web app is being torn down.
Tip: Marking your listener with a #WebListener annotation will cause your Servlet container to automatically notice it and instantiate when the web app is launched.
Beware of a nasty bug when doing development with NetBeans & Tomcat (development problem only, not a problem in deployment) where the web app does a double launch.
ScheduledExecutorService
In your custom class implementing that interface, in contextInitialized, establish a ScheduledExecutorService object to run your task repeatedly. In contextDestroyed, shutdown that executor. This is very important as the thread(s) of that executor will survive the shutdown of your web app and even the servlet container.
The ScheduledExecutorService technology supplants the Timer and TimerTask classes. These classes are especially not recommended for use in a Java Servlet environment.
You can store a reference to the executor in your listener object.
#WebListener
class MonthlyTaskRunner implements ServletContextListener {
private ScheduledExecutorService scheduledExecutorService;
void contextInitialized(ServletContextEvent see) {
// initialize your ScheduledExecutorService.
// The ScheduledExecutorService will use one or more threads for its work outside of this thread running now.
this.scheduledExecutorService = … ;
}
void contextInitialized(ServletContextEvent see) {
// Shutdown the executor along with its thread(s).
this.scheduledExecutorService.shutDown();
}
}
I and others have posted on this extensively here on Stack Overflow, such as this. So search Stack Overflow. I have posted extensive examples in the context of Vaadin web apps, but the principles apply to any servlet web app. And see the Oracle Tutorial on Executors.
Where to store a reference to your ScheduledExecutorService once instantiated? You could store in a member variable on your context listener. But a more accessible place would be as an "attribute" on the servlet context. I describe this in detail along with example code and a nifty diagram in my Answer to another Question: Start & Stop a ScheduledExecutorService in Java EE environment using servlet
YearMonth
In that executor task, get the year-month of the current date for the time zone of your business context. Compare that year-month to one recorded when the task was last performed. Record that year-month somewhere, in a file, in a database, someplace.
Schedule your ScheduledExecutorService to run more often than necessary. Rather than worry about scheduling out a month, just let it run everyday. The check to compare current YearMonth with stored year-month requires nearly no execution time. KISS.
Java includes a YearMonth class.
YearMonth ymThen = YearMonth.parse( "2016-11" ); // Retrieve that string from storage.
ZoneId z = ZoneId.of( "America/Montreal" );
YearMonth ymNow = YearMonth.now( z );
if( ymNow.isAfter( ymThen ) ) {
// … run the task
String ymOutput = ymNow.toString();
// … write that `ymOutput` string someplace in storage.
} // Else do nothing. Let the ScheduledExecutorService run again after its designated rest period.
Similar Questions
Background timer task in JSP/Servlet web application
How to run a background task in a servlet based web application?
I'm making a html5/js game that will have online capabilities for my backend I've decided to use a wildfly server. The client will communicate with the server via web sockets.
I intended for my wildfly server to also be in charge of game logic decisions such as moving npc's. My plan was to have a #startup bean that would run a server game loop to handle this logic. The server loop would then talk to the serverEndPoint via HornetQ. My serverEndPoint and server loop look like this:
ServerEndPoint
#ServerEndpoint(value= "/game/{user-id}")
public class GameEndpoint {
#Inject
GameManager gameState;
GameWorld gameWorld;
Player p;
private Logger logger = Logger.getLogger(this.getClass().getName());
#OnOpen
public void onOpen(Session session){
//do stuff
}
#OnMessage
public void onMessage(Session session, String message){
//do stuff
}
#OnClose
public void onClose(CloseReason reason){
//do stuff
}
#OnError
public void error(Throwable t){
//do stuff
}
}
GameWorld
#Startup
#Singleton
public class GameWorld {
#Inject
GameManager gameState;
private Logger logger = Logger.getLogger(this.getClass().getName());
#PostConstruct
public void init(){
gameloop();
}
private void gameloop(){
while(true){
logger.info("This is a test!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#PreDestroy
public void terminate(){
//do stuff
}
}
the issue with this is that the server loop freezes everything as it is a infinite loop(for instance if I try and access the html web page I get a 404). obviously this could be solved if the serverLoop was on its own seperate thread but after doing some research it seems threading in jboss is very difficult as its hard to know what dependencies to inject e.t.c
Can anyone shed some light on how I can solve this issue? any help on the matter would be amazing.
What you have encountered has to do with what Java EE is and what it not is: Java EE is optimized for handling many concurrent, short-lived requests, each of which (usually) handle a single transaction. The containers do that very well, particularly with stateless beans, but also with stateful beans (cluster replication etc). As such, Java EE might be well-suited to process the requests coming from your HTML5/JS clients and feed the requests to the messaging infrastructure. Java EE is not, however, designed for long running, thread-blocking background processes like yours.
FWIW: Another issue that you have not yet encountered is, even if you could get that one fixed: Next you'll encounter the transaction timeout on your #PostConstruct method.
I think you are better of with moving the game engine out of the Java EE stack. You already mentioned you plan to use HornetQ - then why not put the game engine in a simple standalone application that receives messages from HornetQ and feeds replies back into HornetQ.
Another option might be a dedicated Java game server engine, see, e.g., this question and its accepted answer on programmers.stackoverflow.com. (Update: it seems the "RedDwarf Server" project mentioned in that answer was discontinued 3 years ago).
If you absolutely want to use the Java EE environment, I suggest you use a TimerService instead. Note, however, that this also requires that your game loop calculation is quick and guaranteed to finish until the next timeout is scheduled, otherwise the container will skip the scheduled invocation (with a "still running" message or similar).
Finally, let me mention that if I were to start a new game server today, I would definitely take a look at Akka, Node.js or similar projects that support "reactive" programming.
I have a JEE6 application that runs on an Glassfish 3.1.2 cluster.
One #Singleton Bean contains some kind of (readolny) cache. A User can press a button in the GUI to update the cache with (updated) content from the database.
This works well in a none clustered environment, but now we need to switch to an cluster.
So I am facing the problem, that when a user press that update button, only the Cache Singleton from his server node is updated. My question is, what would be the easiest way to make the other Singletons (in the other nodes) updating there data too?
I am aware of question Singleton in Cluster environment, but my question is specific for Glassfish (because I hope there is some build in support), the other one is taged with "Websphere". And my question is about JEE6, the other one is older than JEE6.
GlassFish High Availability Administration Guide explicitly states:
Restrictions
When configuring session persistence and failover, note the following
restrictions:
When a session fails over, any references to open files or network connections are lost. Applications must be coded with this restriction in mind.
EJB Singletons are created for each server instance in a cluster, and not once per cluster.
Another suggestion, would be to use JMS and have the GUI button press post a message to a JMS Topic. All the Singleton beans can subscribe to that Topic and receiving the message will cause them all to update from the database, almost simultaneously. The benefit of this approach, is that it leverages more of the built in features of Glassfish, without necessarily having to bring in another framework.
In any case, moving from single instance to multiple instance is never a truly seamless change, and is going to cause some difficulty. There will probably need to be application changes to make sure that all the relevant state (other than session state), is shared correctly to all instances in the cluster.
Unfortunately there's no built-in way of achieving what you want, but the shoal framework that Glassfish bases its clustering on could help you out here. You can solve the problem either by sending notifications to cluster members to update their caches or by replacing your current cache with a distributed one.
Below is an example using shoal to send notifications:
#Startup
#Singleton
public class Test {
private String groupName = "mygroup";
private String serverName = System.getProperty("HTTP_LISTENER_PORT");
private GroupManagementService gms;
#PostConstruct
public void init() {
Runnable gmsRunnable = GMSFactory.startGMSModule(serverName, groupName,
GroupManagementService.MemberType.CORE, null);
gms = (GroupManagementService) gmsRunnable;
try {
gms.join();
gms.addActionFactory(new MessageActionFactory() {
#Override
public Action produceAction() {
return new MessageAction() {
#Override
public void consumeSignal(Signal signal)
throws ActionException {
// Update your cache here
}
};
}
}, groupName);
} catch (GMSException e) {
Logger.getAnonymousLogger().severe(e.getMessage());
}
}
#PreDestroy
public void cleanup() {
gms.shutdown(GMSConstants.shutdownType.INSTANCE_SHUTDOWN);
}
/**
* Call this from your button click.
*/
public void updateCache() {
try {
byte[] message = new byte[] {};
gms.getGroupHandle().sendMessage(groupName, message);
} catch (GMSException e) {
Logger.getAnonymousLogger().severe(e.getMessage());
}
}
}
If you wanted to use a distributed cache instead:
DistributedStateCache cache = gms.getGroupHandle().getDistributedStateCache();
Items placed in the cache will be replicated to the other cluster nodes.
Take a look at JGroups. It's a framefork for reliable multicast communication. JBoss clustering mechanisms are currently based on this tool.
You can check out an example usage of JGroups here.