A Simple Job Scheduler Example - WebLogic Server Clustered Timer

*Dec 17th, 2010 Update* Someone commented on another entry about this very helpful EJB3 Timer write-up for WebLogic Server that is also very relevant to this topic. http://shaoxiongyang.blogspot.com/2010/10/how-to-use-ejb-3-timer-in-weblogic-10.html

Did you know WebLogic Server can schedule future tasks similar to a cron job?  This even works in a WebLogic cluster.  Using a cluster ensures that as long as one of the managed servers in the cluster is available, your task has a high-availability characteristic and the task will execute.  This has come up for at least 3 of my local customers.  Every once in awhile I see questions about WebLogic timers from my peers, so I thought I'd share a simple example for how this works and some extra tidbits based on personal experience that might not be in the standard documentation.  Read on if you want to see how to schedule a simple println() task to execute every 30 seconds in a cluster that can survive server failures in both the WebLogic tier and the database tier (provided you use Oracle RAC).

HA

Background

Oracle (then BEA Systems) and IBM collaborated on a common API for Timers and Work Managers (think multi-threading) that would be portable across application servers.  They aptly named this API CommonJ.  This API has been supported in WebLogic Server since 9.x and apparently in WebSphere since 6.x.  When combined with WebLogic clustering support, the CommonJ Timer API is known as the Job Scheduler.  It requires some configuration as described in the docs, but essentially the way it works under the covers is by serializing the class that will execute the task and some related metadata to a database.  Using the leasing feature of WebLogic Server, exactly one cluster member will be responsible for JobScheduler (singleton service) which executes the Timer Tasks.  The server responsible for this service will check the database every 30 seconds to see if there are new tasks to execute.

Instructions for the System Out Example Timer

These instructions assume starting from scratch with nothing but a basic WebLogic Server installation and a database like Oracle XE.  I run all of this easily on my 2+ yr old laptop (I do have 3+ gig of ram).  The documentation is more detailed now, so definitely refer to that as well.

  1. Create a new domain with 1 Admin Server and at least one Managed Server that will be a part of a cluster.  Refer to the Oracle By Example page for WLS if you need help with this, but you should be able to do all of this from the Configuration Wizard.  I named my cluster "myCluster" and my managed servers "managedServer1" and "managedServer2".
  2. Set up the database - Basically run the DDL for your DB, which will create a table called WEBLOGIC_TIMERS. If you don't set up database often, here is my simple POC sequence with Oracle XE.  In production, I would recommend Oracle RAC with a Multi Data Source, but you can POC this with an XE database or a single database node if you can live with a single point of failure.  Open the XE database web console and create a new database user, of course I use weblogic/weblogic for the user name password and give them admin rights.  Start sqlplus and login as that user.  Navigate to the directory that contains the DDL you want to run and use the @ syntax to execute the DDL like this.  You can of course ignore the messages about the comments not being valid commands: scheduler.ddl
  3. Keep the sql prompt open, we'll use it again in a minute.  Notice that the script is in the oracle\920 directory, that simply means for 9.2+ of Oracle DB, it works totally fine for me on XE 10g.
  4. Configure the data source - Create a new data source for this and target it at all the servers in your domain (or at least the ones in your cluster) and specify it as the cluster's JobScheduler Data Source.  I recommend that you test your data source when you are creating it.
  5. Set up leasing - You can use consensus or database leasing, but since we already using the DB for the Job Scheduler, just do database leasing which creates a table called ACTIVE (at least in the recent releases of WLS, it used to be something like WEBLOGIC_ACTIVE in earlier releases).  This means running the appropriate WL_HOME/server/db/dbname/leasing.ddl as well as configuring the data source, which can be the same one you used before, and configuring the cluster to use that data source for leasing.  Make sure you note database based leasing requires a highly-available database.  If the connection goes away, the managed servers will fail.  For this reason you can use multi data sources with Oracle RAC to get an even more HA architecture, but Oracle XE works fine for a POC.  I got consensus leasing to work at one time in the past using WLS 9.2, but if I remember correctly I had to install Node Manager and configure "machines" for my servers for it to work.  So DB-based leasing is what I'm using in this example because it's simpler and I have not had issues with it before. leasing.ddl
  6. Write some code - There is a sample in the docs showing how to look up the job scheduler and schedule a task.  I'll take care of that for you, here is a WAR (Servlet 2.5 based) that has code to register the task via a servlet and a JAR file that contains the class that implements the TimerListener interface.  The source code is at the way bottom of this post.
  7. Deploy the WAR file, target it at the cluster, and make sure the application is started.
  8. Edit your server classpath to contain the timer implementation class which is in the JAR referenced earlier.  You might be asking yourself, why the heck does the timer listener class need to be placed on the system classpath?!!  Well if you think about how the classloaders work, the singleton service running the tasks does not have access to the classes from the JEE module that registered the timer.  It is running as a WebLogic system thread.  This class will be deserialized from the database, potentially on another server.  So I recommend not doing anything too sophisticated in the timer listener.  If you have lots of logic with multiple classes, just consider having the timer listener drop a message on a distributed JMS queue, which can have an MDB from another application that does all of your heavy lifting.  Back to putting the TimerListener implementation on the classpath, I accomplished this by added the following line to my domain's setDomainEnv.cmd script.  There is also the option to use an EJB Timer, which apparently does not have the system classpath requirement, but I haven't tried that before.
    set PRE_CLASSPATH=C:\JDeveloper\mywork\JobSchedulerApp\TimerListener\deploy\TimerListener.jar

  9. Optional - Enable verbose logging for the related sub-systems, I find this helpful when troubleshooting. 
    set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.debug.DebugSingletonServices=true -Dweblogic.JobScheduler=true

  10. Restart your Admin Server and Managed Server.  Make sure you see the JAR in the classpath settings in the log file.  args
  11. If your enabled the additional logging, you should see that leasing and job scheduler are creating log entries like the following in the managed server log file (not in standard out!). 
  12. ####<Apr 8, 2009 3:10:01 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221401078> <BEA-000000> <SingletonMonitor: Checking Failed Leases> 
    ####<Apr 8, 2009 3:10:11 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221411078> <BEA-000000> <SingletonMonitor: Now checking lease statuses.> 
    ####<Apr 8, 2009 3:10:11 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221411078> <BEA-000000> <SingletonMonitor: Checking for registered Migratable Targets and Singleton Services without a lease> 
    ####<Apr 8, 2009 3:10:11 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221411078> <BEA-000000> <SingletonMonitor: TimerMaster - Found an owner - -7090657857495109585/managedServer1> 
    ####<Apr 8, 2009 3:10:11 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221411078> <BEA-000000> <SingletonMonitor: Checking existant, but expired leases> 
    ####<Apr 8, 2009 3:10:11 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221411078> <BEA-000000> <SingletonMonitor: Checking Failed Leases> 
    ####<Apr 8, 2009 3:10:21 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221421078> <BEA-000000> <SingletonMonitor: Now checking lease statuses.> 
    ####<Apr 8, 2009 3:10:21 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221421078> <BEA-000000> <SingletonMonitor: Checking for registered Migratable Targets and Singleton Services without a lease> 
    ####<Apr 8, 2009 3:10:21 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221421078> <BEA-000000> <SingletonMonitor: TimerMaster - Found an owner - -7090657857495109585/managedServer1> 
    ####<Apr 8, 2009 3:10:21 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221421078> <BEA-000000> <SingletonMonitor: Checking existant, but expired leases> 
    ####<Apr 8, 2009 3:10:21 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221421078> <BEA-000000> <SingletonMonitor: Checking Failed Leases> 

  13. Register the timer by hitting the URL or invoking the web service of one of the managed servers.  In my case that is http://localhost:7011/TimerWeb/timerservlet.  Note that each time you invoke the URL successfully a new timer listener will be registered with the cluster, so you probably only want to do this once.
  14. Notice the messages in standard out if this is working correctly.
  15. timerExpired() called at 4/8/09 3:12 PM
    timerExpired() called at 4/8/09 3:13 PM

  16. Shut down the managed server that has the messages printing to standard out.  You should see the messages show up on another managed server in the cluster in standard out.
  17. Now shut down all of the managed servers and restart at least one.
  18. You should see the timer task start printing to standard out when one of the managed servers in the cluster is available.

Summary

So you should have a working timer example in WebLogic Server that survives failures.  The debug messages in the managed server log files can be helpful in trouble-shooting in case anything goes wrong.  A couple other things to note, you cannot cancel timer tasks via CommonJ API calls when running in the JobScheduler.  You have to use the JobRuntimeMBean for that.  I'll show an example of using this bean with WLST in another entry.  Here is the source code for the servlet and the timer listener classes.  Hopefully this will help you utilize this powerful capability built-in to WebLogic.

package view.jamesbayer;
import commonj.timers.TimerManager;
import jamesbayer.client.SystemOutTimerListener;
import java.io.IOException;
import java.io.PrintWriter;
import javax.naming.InitialContext;
import javax.servlet.*;
import javax.servlet.http.*;
public class TimerServlet extends HttpServlet {
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }
    public void service(HttpServletRequest request,
                        HttpServletResponse response) throws ServletException,
                                                             IOException {
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head><title>TimerServlet</title></head>");
        try {
            System.out.println("service() entering try block to intialize the timer from JNDI");
            InitialContext ic = new InitialContext();
            TimerManager jobScheduler =
                (TimerManager)ic.lookup("weblogic.JobScheduler");
            System.out.println("jobScheduler reference " + jobScheduler);
            commonj.timers.TimerListener timerListener =
                new SystemOutTimerListener();
            System.out.println("timerListener reference " + timerListener);
            jobScheduler.schedule(timerListener, 0, 30 * 1000);
            //execute this job every 30 seconds
            System.out.println("service() started the timer");
            out.write("Started the timer - status:");
        } catch (Throwable t) {
            System.out.println("service() error initializing timer manager with JNDI name weblogic.JobScheduler " +                               t);
        }
        out.println("</body></html>");
        out.close();
    }
}

package jamesbayer.client;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import commonj.timers.Timer;
import commonj.timers.TimerListener;
public class SystemOutTimerListener implements Serializable, TimerListener 
{
	private static final long serialVersionUID = 8313912206357147939L;
	public void timerExpired(Timer timer) 
	{
		SimpleDateFormat sdf = new SimpleDateFormat();
		System.out.println( "timerExpired() called at " + sdf.format( new Date() ) );
	}
}

Comments:

Excellent and useful article ! Thanks James for sharing this :)

Posted by Maxence Button on April 08, 2009 at 04:16 PM PDT #

great. your entry come in just in time. i was reading around for a scheduler of higher availability than the standard unix cron when i come across your Dec 2007 posting. in that posting, you mentioned that you will keep the wls cluster version for a later posting, and well, i was so fortunate that you post it finally after over a year. thanks for the in-depth sharing.

Posted by beng seng on April 08, 2009 at 04:40 PM PDT #

Max and Beng, It's been in my blog folder for a long time! I'm glad that I finally made the time for it. Thanks for the feedback because it does take some time to put this together, and knowing that others are benefiting from it is a big motivator. Cheers, James

Posted by James Bayer on April 08, 2009 at 07:40 PM PDT #

Thanks for the great article. Is there another way to start off the job other than manually hitting a URL on only one of the managed servers to invoke the servlet? Also, has anyone seen any good examples (like this one) using EJB Timers?

Posted by Andy H on May 28, 2009 at 09:29 PM PDT #

Andy, Regarding initializing a job, you have to be prudent about where this goes because if you think about it, job registration is separate from the long-running job itself. If I put it somewhere like Servlet.init() or when I activate the web application, then every time I restart the server a new job would be registered! Therefore the right approach is probably a separate web application (or ejb etc, something in the container) that is responsible for creating/managing jobs. I just used a servlet as a simple placeholder for something more sophisticated. I'm not aware of any EJB 3 Timer demos, but I am on the lookout for them. Thanks, James

Posted by James Bayer on May 28, 2009 at 11:01 PM PDT #

James, thanks for the interesting article. It covers almost exactly what I was looking for. I tried to make this setup work with an EJB timer and (sort of) succeeded: I used the above configuration, i.p. the two DB tables in the datasource the app server was using already and "MyDataSource" in config.xml (in /domain/cluster). In the EAR I set "Clustered" in weblogic-ear-jar.xml. Now, on an injected "@Resource private EJBContext ejbCtx;" in a stateless session bean I called ctx.getTimerService().createTimer() to set up the timer which triggers the business method annotated by @Timeout in the same bean every time the timer expires. All of this works well including failover when taking down one of the cluster nodes ... once it works. The problem I am experiencing is start up: When I first start the application calling any Timer API methods results in a BEA internal NullPointerException. From the log it is clear the the TimerMaster SingletonService is not yet running. Once I restart the servers (changing state from ADMIN through RESUME to ACTIVE) the TimerMaster is started and the timers work. Unfortunately, after shut down and restart the problem occurs again. Have you ever encountered this issue? From the log I don't think it is EJB specific but rather related to the way SingletonServices in general and the TimerMaster in particular is configured and started. Cheers, Mathias

Posted by Mathias Kegelmann on June 01, 2009 at 06:38 PM PDT #

Mathias, I have not encountered this issue before, but that's probably because I haven't tried the EJB Timers. So it sounds like you are using the server's ADMIN state to test your applications on the ADMIN channel or otherwise, yet that mode may be incompatible with running Singleton Services in the cluster, which makes sense to me given some thought. I don't know enough about all the moving parts here, so I suggest working with Oracle Support to see if that theory is correct or if there is another explanation. Thanks, James

Posted by James Bayer on June 01, 2009 at 08:41 PM PDT #

Thanks for the great article. Based on this I have started using commonj for scheduling tasks, but I am using local timers. I am facing one problem. The security credentials associated with the thread which scheduled the TimerListener are somehow passed to TimerListener and is being used for the work done in TimerListener. I have read the API document and it looks like is the expected behavior. Is there a way to avoid this? Thanks, Laxman

Posted by Laxman on June 25, 2009 at 01:52 AM PDT #

Laxman, My first intuition is that this is working-as-designed with respect to security. I've asked someone on the team. My 2 seconds of thought ideas is that if you want to separate the user from the timer, you could probably put a layer in-between with JMS and an MDB. So the user request would send a JMS message, the MDB would pick it up without a security context, and initialize a timer without the user information. This is just my 2 seconds of thought idea, not well thought through. Good luck, James

Posted by James Bayer on June 25, 2009 at 02:47 AM PDT #

James, Thanks for the great tutorial. We're considering using the Job Scheduler as well. Do you know if it has the same limitations as EJB Clustered Timers with regards to being intended only for "coarse-grained operations". My Google searches did not turn up any limitations with Job Scheduler, so is it safe to assume that we can use it to create several thousand timers, each timer associated to a specific entity or object? Thanks, Rody

Posted by Rody Bagtes on August 17, 2009 at 06:02 AM PDT #

Actually, it's my understanding that they (JobScheduler and EJB 3 Clustered timers) use the same underlying framework, so I'm not sure they were designed to support thousands of timers. Perhaps you could send me your use case and I can run it by one of the product managers. Thanks, James

Posted by james.bayer on August 17, 2009 at 07:21 AM PDT #

Hi James, Your blog is just superb. I am also implementing Job Scheduler for Weblogic 10.3. I am facing the below problem while deploying my application: BEA-000180 Unable to retrieve Job Cluster_MS2_1251204736672 from the data base. The retrieval failed with java.io.IOException: mydomain.timer.MyTimerListener at weblogic.scheduler.ObjectPersistenceHelper.getObject(ObjectPersistenceHelper.java:94) at weblogic.scheduler.ObjectPersistenceHelper.getObject(ObjectPersistenceHelper.java:82) at weblogic.scheduler.ObjectPersistenceHelper.getObject(ObjectPersistenceHelper.java:227) at weblogic.scheduler.DBTimerBasisImpl.getTimerState(DBTimerBasisImpl.java:238) at weblogic.scheduler.TimerExecutor.timerExpired(TimerExecutor.java:164) at weblogic.timers.internal.TimerImpl.run(TimerImpl.java:273) at weblogic.work.SelfTuningWorkManagerImpl$WorkAdapterImpl.run(SelfTuningWorkManagerImpl.java:516) at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201) at weblogic.work.ExecuteThread.run(ExecuteThread.java:173) The timer-listener class implements Serializable interface too. Thanks in advance.

Posted by Ankur Jain on August 24, 2009 at 08:02 PM PDT #

Ankur, I'm not sure just based on that stack. I would expect a Serializable or NotFound exception if the class was not on the classpath, but just in case validate that the TimerListener class is on the system classpath for all the servers in the cluster. Point 8 in the entry explains the classpath settings in some detail. If you're still stuck, then I suggest a Service Request with support as they can help you troubleshoot and find the issue. James

Posted by James Bayer on August 24, 2009 at 09:10 PM PDT #

James, Just to follow up, we eventually implemented the EJB Clustered Timer which as you know is implemented using the Job Scheduler. We're using the UDD Queue and JMS setDelayTime(). Everything is good, except for the startup. What's the best way to automatically start the EJB Clustered Timer in an EAR? We're using the ApplicationLifecycleListener's postStart(). It calls an EJB, which in turn calls EJBContext.getTimerService(). But this does not work when starting up the domain, i.e., Start Domain Cluster "Core" starts -> STARTING state Core Server 1 starts, then RUNNING Core Server 1 automatically starts App App looks up Clustered Timer Server -> Null Pointer exception (Cluster is still in STARTING state) Core Server 2 Starts, goes to RUNNING. All members of the cluster RUNNING Cluster Core set to RUNNING App state Failed As you can see above, there is a cyclic dependency between the App and the Cluster Timer Service. The App is automatically started by server instance before the Cluster is RUNNING. To solve this problem our startup and shutdown script automatically Stop the App before the domain is stopped. The App is then started after the domain starts. This way the Cluster is up before the App starts ensuring cluster services are available. Is there a better way of doing this? It seems that Weblogic overlooked how the ApplicationLifecycleListener handles startup in a cluster. Maybe a postClusterStart() is needed? Otherwise pretty cool stuff. I really like the UDD and setDeliveryTime(). Thanks, Rody

Posted by Rody Bagtes on August 29, 2009 at 12:44 PM PDT #

Rody, I'm not sure about an alternative to the scripting approach you took for the circular dependency in startup between clustered timers and the app lifecycle listener. I was thinking that perhaps you could also use the CommonJ WorkManager to schedule a piece of work with a semi-short call to Thread.sleep() that would then invoke the EJB, rescheduling the Work if the cluster was still not available, but that's a bit of a hack. http://download.oracle.com/docs/cd/E12839_01/web.1111/e13733/toc.htm I forwarded your comments to the Product Manager who owns the clustered timer to see if he has a comment and inform him about the perceived limitation to see if there are alternatives, etc. Thanks for the follow-up! Cheers, James

Posted by james.bayer on August 30, 2009 at 08:44 PM PDT #

Please help how can I configure the scheduler in weblogic 10. the link provided above is broken. I am failing at look up for weblogic.JobScheduler Thanks

Posted by Dan on September 03, 2009 at 10:17 PM PDT #

Yes, unfortunately all the edocs documentations links are broken since that site has been decommissioned and all the old BEA documentation has moved to oracle.com domains. It's pretty easy to find the right links however. Simply take a doc link like this: http://e-docs.bea.com/wls/docs103/commonj/commonj.html And change the prefix before the docs103 portion to be http://download.oracle.com/docs/cd/E12840_01/wls/ As an example: http://download.oracle.com/docs/cd/E12840_01/wls/docs103/commonj/commonj.html Good luck, James

Posted by james.bayer on September 03, 2009 at 10:49 PM PDT #

Great article! However I also experience the "Null Pointer exception when the Cluster is still in STARTING state" on 10.3 when trying to initialize EJB timers during startup. Any news on this one? Is there an Oracle ticket we could refer to? Many thanks

Posted by Alec on October 27, 2009 at 09:20 PM PDT #

Alec, I'm not aware of any tickets on this issue, although you might want to contact support as they have better search tools than I do. One thing you might do is wait for some configurable amount of time after application start-up to use the Job Scheduler, and possibly even explicitly check the status of the cluster before you call the API's. Good luck, James

Posted by james.bayer on October 28, 2009 at 03:45 AM PDT #

Hi James, Thanks a lot for sharing this great sample. Now it's very clear to me that how actually this JobSchedular works. Thanks Again...

Posted by Jay SenSharma on December 25, 2009 at 11:48 AM PST #

Hi, I saw a post earlier from Mathias Kegelmann saying that he was able to get EJB Timer working in a cluster environment... I tried "everything" and I cannot get that to work... (it does not make use of the WEBLOGIC_TIMERS table, like the JobScheduler does...) Does anyone have any examples? (I believe I'm missing something in the descriptor, so a sample of that would be great!) BTW, JobScheduler works fine...(thanks for the tutorial!). The only annoying things are the listeners having to be 'outside' of the applications, and the lack of some basic functionality [commonj] (from the code, without using JMX), like cancelling timers, and creating a timers with an specific name (!!!!). Thanks, Thomas.

Posted by Thomas on January 15, 2010 at 12:36 AM PST #

Thanks for the comments Thomas, I've passed on your feedback to the Product Management team. Also, I seem to recall that the database table was required when using the clustered EJB Timer method also. I'm not sure on that, make sure to double-check the documents and post in the OTN WLS EJB forum or open a support case if you still have issues. Good luck, James

Posted by james.bayer on January 15, 2010 at 12:43 AM PST #

Hi , I am facing one issue on ejb timer ,please share your thoughts on it......... 1)I am createing some timer entries in to EJB_Timer table though my application and keeping same into another table too. 2) After restarting my server(Glassfish) My EJB timer entires being lost. 3) Can you please tell me how I can get my timer entries back after restating server(Server Startup)? Note : I am keeping same entries in another table and need to copy that entries in EJB_timer table on server start-up. Regards, Sagar

Posted by sagar on January 18, 2010 at 05:57 PM PST #

Sagar, I'm confused, how are you using the WebLogic Job Scheduler with Glassfish? This isn't really supported to my knowledge. Most likely whatever you've done is custom development and not a certified and supported use case. Thanks, James

Posted by james.bayer on January 19, 2010 at 01:28 PM PST #

I am starting to test the timer expose on this article, and I am facing the problem on how is the best approach for automatically reschedule cluster timers when the whole cluster is restarted. I need the functionality that end users can schedule jobs with several months (thousands) in advance and manage those schedules (list, cancel, reschedule). I don't know if using this cluster timers is the best approach and if not, to use another framework like Quartz. Thanks for the article. Luis Longeri

Posted by luis.longeri on April 19, 2010 at 10:18 PM PDT #

We are using weblogic cluster (2 managed servers) having singleton service with database as migration basis (i.e. Database Leasing). For some unknown reason both managed servers are starting singleton service in production. We were not able to find the reason when this is happening. Hence we have changed the migration basis to consensus (i.e.Consensus leasing). As per weblogic document we can get the owner of the lease programmatically using weblogic.cluster.singleton.Leasing interface. By doing this we compare the current server name (using jmx) and the owner we get using Leasing interface to prevent singleton service being run on another server. The question here is how to get 'lease name' as it has to be passed as a parameter to findOwner method in weblogic.cluster.singleton.Leasing interface. Please help me ASAP.

Posted by uday on July 07, 2010 at 07:58 PM PDT #

Uday, Please open a Service Request at support.oracle.com as I don't know the answer to your question. Thanks, James

Posted by james.bayer on July 07, 2010 at 11:49 PM PDT #

James, Great Article !!! I am trying to use this scheduler in my applications. I am however getting a ClassCast exception at TimerManager jobScheduler = (TimerManager)ic.lookup("weblogic.Jobscheduler"); I have targeted this datasource on cluster and have set it for schedulling This is the error i get: service() error initializing timer manager with JNDI name weblogic.JobScheduler java.lang.ClassCastException: weblogic.jdbc.common.internal.RmiDataSource cannot be cast to commonj.timers.TimerManager I am using Weblogic10.3. Any ideas?

Posted by Sumathi on July 13, 2010 at 06:28 AM PDT #

Sumathi, A few things you could try: 1) Make sure the capitalization is correct on the string: TimerManager jobScheduler = (TimerManager)ic.lookup("weblogic.JobScheduler"); 2) You do not name your data source with the JNDI name weblogic.JobScheduler, you give it it's own JNDI name and make sure in your cluster configuration that you refer to that data source. The weblogic.JobScheduler is a special JNDI name automatically created by WLS for your cluster for the Job Scheduler feature. Hope this helps. Thanks, James

Posted by james.bayer on July 13, 2010 at 07:16 AM PDT #

Hi James, Thanks for the great example. We would like to be able to use local timers in our application - even when it is running in a cluster. The issue that we're running into is that the JNDI call to lookup a TimerManager is failing in a clustered environment even though the web.xml file contains the proper resource reference in it. The code works fine in a non-clustered environment. Do you know if local timers are supported when running in a clustered environment? Thanks, Alan

Posted by Alan on July 28, 2010 at 11:48 PM PDT #

Alan, I would expect local timers to work just fine in a clustered environment. I suggest you open a Service Request with support.oracle.com and perhaps also ask in the OTN WLS General forum. Good luck, James

Posted by james.bayer on July 30, 2010 at 07:12 AM PDT #

Hi James, My schedule method is not getting called. I have to schedule job at specified time so I'm just specifying the time at which job should be scheduled in the properties file and in through code I'm converting that time to set on the required date. So my date with time when job should be scheduled and I'm specifying delay - so my call to schedule method is as follows jobScheduler.schedule(new ArchiverTimerListener(), date, 300000); The date conversion will be done as follows -- timeStr = "14:15" time at which job should be scheduled public void setTimeStr(String timeStr) { Calendar cal = Calendar.getInstance(); // cal.add(Calendar.DATE, 1); String[] times = timeStr.split(":"); int hour = Integer.parseInt(times[0]); int minute = times.length > 1 ? Integer.parseInt(times[1]) : 0; int second = times.length > 2 ? Integer.parseInt(times[2]) : 0; cal.set(Calendar.HOUR_OF_DAY, hour); cal.set(Calendar.MINUTE, minute); cal.set(Calendar.SECOND, second); if (cal.before(Calendar.getInstance())) { cal.add(Calendar.DATE, 1); } this.date = cal.getTime(); } Here date we provide as a parameter to schedule method will be set as start_time in the Weblogic_Timers table. Now if I want to schedule a job today Aug 4 2010 at 20:30, the start_time value will be set as 2561936481173 in the Start_time column of weblogic_timer table and is I try to get current date milliseconds by using date.toTime() it will come around 1280968240524, This is I'm doing just to check what value of current date should go in database as follows Date date = new Date(); System.out.println("date "+date ); System.out.println("date.getTime()"+date.getTime()); Now here if I take to diff between 2 dates start date value which is actually inserted into database and today's date(2561936481173 - 1280968240524) which I calculated programmatically it will come around 40 years, so should I consider that my job will start after 40 years? Here I'm confused, is correct date is getting inserted into start_time and something is wrong with my code or wrong value is getting inserted. In total I'm using spring. Pls help. Thanks, Swati

Posted by Swati on August 04, 2010 at 02:04 PM PDT #

Swati, I am not sure what is happening here and I suggest you file a support case with your reproducer. That is the fastest way to resolution. I do not work in support and do not know the engineers responsible for this code. I am tied up on projects and don't even have time to try it out. If you want to troubleshoot further yourself, consider using the debug flags to see if they yield any information. Thanks, James

Posted by james.bayer on August 05, 2010 at 01:36 PM PDT #

Hi James , I am getting below error , Do you have any idea about this ? service() entering try block to intialize the timer from JNDI service() error initializing timer manager with JNDI name weblogic.JobScheduler javax.naming.NameNotFoundException: Unable to resolve 'weblogic.JobScheduler'. Resolved 'weblogic'; remaining name 'JobScheduler' Thanks John

Posted by John on December 09, 2010 at 02:00 AM PST #

Have you targeted the application at a cluster that has the job scheduler configured (datasource, leasing, etc)? I would expect this message if you either targeted a an Admin Server or stand-alone managed server, or a cluster that was not properly configured. Please ask the OTN WLS General forum or Oracle Support for assistance as I'm not able to respond in a timely manner right now. http://forums.oracle.com/forums/forum.jspa?forumID=570 Thanks, James

Posted by james.bayer on December 09, 2010 at 09:33 AM PST #

Hi James, Will this scheme of scheduling work with two Weblogic clusters( each cluster having 4 managed servers) , both the deployments are active and pointing to the same database at any given time? or there can be some issues regarding locking, data corruption etc? Thanks. KT.

Posted by Kuldeep T. on February 09, 2011 at 01:18 AM PST #

As far as I remember the Job Scheduler only supports a single cluster at a time because leasing is at a cluster level. Thanks, James

Posted by james.bayer on February 09, 2011 at 05:55 AM PST #

Thanks for the blog. Where can I find the JAR that contains WebLogic Timer classes in order to compile my own source code?

Posted by Lennarth Anaya on June 02, 2011 at 12:50 AM PDT #

Finally I realized that weblogic.jar is the one who contains timers.

Posted by Lennarth Anaya on June 02, 2011 at 12:57 AM PDT #

Hi, James. When deploying EAR file with listener to weblogic "unable to convert Object to Blob" error occurs. Both weblogic_timers and active tables are present, my Listener class extends Serializable. My listener class also contains injected Spring bean, and full error is like this: "unable to convert Object to Blob. Reason: com.frf.MySpringBean". What could be the problem? Thanks.

Posted by guest on June 08, 2011 at 12:38 AM PDT #

"unable to convert Object to Blob. Reason: com.frf.MySpringBean" Well the timer listener implementation and all classes inside would need to be serializable. Is com.frf.MySpringBean serializable? Does it work when you have a simpler timer listerner?

Posted by james.bayer on June 08, 2011 at 01:10 AM PDT #

Hi. In previous case "unable to convert Object to Blob" I made all classes that are injected into my bean serializable, and now it works fine. I have another issue - when I put JAR file with timer into classpath (in setDomainEnv), and then this class is deployed within EAR, I get "No currently living server was found that could host Timer class". Do you have any ideas what could cause that?
Thanks.

Posted by guest on June 14, 2011 at 11:48 PM PDT #

"No currently living server was found that could host Timer class" sounds like it could be an issue with leasing or the classpath. Leasing information you can get from DEBUG. It also might be that the Timer class isn't found, which means you should validate that you got it on the system classpath correctly. That seemed to be this users issue:
http://stackoverflow.com/questions/2446880/weblogic-job-scheduling

James

Posted by james.bayer on June 15, 2011 at 05:00 AM PDT #

Hi, James. Thanks for answering previous questions.
I have another one: When I deploy application with scheduler to cluster, Timer record is created in WEBLOGIC_TIMERS table, and listener (sometimes) works fine. But from time to time I get following exception:
"java.lang.AssertionError: weblogic.scheduler.TimerException: unable to timeout in database..caused by
java.sql.SQLException: unable to convert Object to Blob. Reason: weblogic.wsee.jaxws.spi.ClientInstanceInvocationHandler". What's general logic of Listener, is it constantly persisted to WEBLOGIC_TIMERS table, or only once when created?
Thanks in advance.

Posted by guest on July 05, 2011 at 01:30 AM PDT #

ferfax,

If it's a recurring timer, then it may be possible that the TimerListener gets re-serialized into the blob column during each invocation. I don't know the logic as it's inside the black box of the implementation. You should not be seeing errors however, so I recommend a Support Case if you have something reproducible. Does your listener have a reference to ClientInstanceInvocationHandler as the exception indicates? That seems likely to have issues. Good luck.

James

Posted by james.bayer on July 05, 2011 at 01:42 AM PDT #

No direct references to ClientInstanceInvocationHandler in my Listener class, still I had to change logic within to get rid of that error. Anyway its interesting how listener class was stored into BLOB column one time, and refused to do so other time.
Thanks for reply.

Posted by guest on July 05, 2011 at 06:58 PM PDT #

Hello.
I schedule my listener to be called every 30 seconds, but on WebLogic admin console in Server->Control->Jobs my scheduler info(timeout, execution time) says it fires every 2 minutes, and execution count is also updated every 2 minutes. Do you have any ideas what could be the cause?

State Period Timeout Last Local Execution Time Execution Count
Running 30000 12:30:59 PM EEST 12:30:29 PM EEST 369

Posted by guest on July 18, 2011 at 07:32 PM PDT #

Ferfax, it might be helpful to send me a screenshot. I'm not sure what console page you're talking about.

The debug java options I've found very helpful in seeing what is happening by monitoring the logs:
-Dweblogic.debug.DebugSingletonServices=true -Dweblogic.JobScheduler=true

Thanks, James

Posted by james.bayer on July 19, 2011 at 03:57 AM PDT #

Hi James,

I have deployed your sample to WLS 10.3.0.
Then I invoke http://localhost:8001/TimerWeb/timerservlet.
I see the output of 1st managed server (MS1):
<01-Sep-2011 15:26:27 o'clock CEST> <Notice> <WebLogicServer> <BEA-000360> <Server started in RUNNING mode>
timerExpired() called at 01/09/11 15:28
timerExpired() called at 01/09/11 15:29
timerExpired() called at 01/09/11 15:29
timerExpired() called at 01/09/11 15:30
timerExpired() called at 01/09/11 15:31

Then I shutdown MS1:
<01-Sep-2011 15:35:08 o'clock CEST> <Notice> <WebLogicServer> <BEA-000388> <JVM called WLS shutdown hook. The server will force shutdown now>

and after a while it becomes active on MS2:
<01-Sep-2011 15:26:33 o'clock CEST> <Notice> <WebLogicServer> <BEA-000360> <Server started in RUNNING mode>
service() entering try block to intialize the timer from JNDI
jobScheduler reference weblogic.scheduler.TimerServiceImpl@7a40fc
timerListener reference jamesbayer.client.SystemOutTimerListener@189538
service() started the timer
timerExpired() called at 01/09/11 15:36
timerExpired() called at 01/09/11 15:37
timerExpired() called at 01/09/11 15:37

Now I restart the MS1 and I can see that it is being active on MS1:
<01-Sep-2011 15:37:41 o'clock CEST> <Notice> <WebLogicServer> <BEA-000360> <Server started in RUNNING mode>
timerExpired() called at 01/09/11 15:38
timerExpired() called at 01/09/11 15:38

Is it a normal behaviour of singleton service?
For me it is a load balancing and not a singleton service.

As per document:
"A singleton service is a service running on a managed server that is available on only one member of a cluster at a time."

Posted by guest on September 01, 2011 at 02:28 AM PDT #

Yes, the timer should only be firing on 1 managed server at a time as only 1 managed server in the cluster should own the lease. I recommend using the Debug options to see more information about which server thinks it owns the lease. If more than 1 managed server thinks it owns the lease and the timer is firing on more than 1 managed server in the cluster at once, then it is not working properly and I recommend you work with Oracle Support. Thanks, James

Posted by james.bayer on September 01, 2011 at 05:13 AM PDT #

Hi James,

I am just confused here, we did not create any singleton service (At Clusters->Target-Clsuter->Singleton service.

Do we need to configure this for the given example to work?

Thanks
Jeff

Posted by guest on September 13, 2011 at 07:02 AM PDT #

Jeff,

No. The Job Scheduler does not require a singleton service as it is already a feature provided by WebLogic Server to make sure there is only one instance of the Job Scheduler active at a time per cluster. Just coding to the TimerListener interface and using the JobScheduler JNDI lookup is enough.

Thanks, James

Posted by james.bayer on September 14, 2011 at 05:21 PM PDT #

Post a Comment:
Comments are closed for this entry.
About

James Bayer Image
I was formerly a Product Manager on the WebLogic Server team based out of Oracle HQ. You can find my new blog at http://iamjambay.com.
Follow Me on Twitter
Oracle WebLogic

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today