Forum: JRuby Building a JRuby Quartz gem for scheduling; running into problems passing a JRuby object's class whe

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Ikai L. (Guest)
on 2009-01-15 02:48
(Received via mailing list)
I had a lot of hope for the Quartz-Rails plugin that was created a while
ago:

http://www.jkraemer.net/2008/1/12/job-scheduling-w...

Unfortunately, it doesn't work with the newest versions of JRuby and
looks
like it isn't being maintained. I looked a bit at the Quartz
documentation
and think this can not only be updated, but done in such a way that all
the
configurations are done in YAML or Ruby rather than in XML and requiring
a
Servlet to work ­ this should be something that can be used for ANY kind
of
Ruby application.

I'm thinking that the interface from the Ruby side could look something
like
this:

JQuartz.schedule :jobname, :cron => ""0/20 * * * * ?" do
   # Some code here to be executed every 20 seconds
end

What is the best approach to this problem? Here are some of the
approaches I
see:

1. Just use the JobDetail interface in Quarts:

        JobDetail job = new JobDetail("job1", "group1",
SimpleJob.class);

In JRuby, this is:

    jobDetail =
Java::OrgQuartz::JobDetail.new(java.lang.String.new("myJob"),
java.lang.String.new("myGroup"), RubyJob.new.java_class)


Unfortunately, the third parameter requires a Java class that conforms
to
the Job interface. Using "include" I can create a Ruby class that
implements
the interface, but I either get an error that it can't accept
org.jruby.RubyClass or some crazy error like:

 Problem instantiating class 'org.jruby.gen.InterfaceImpl57204556'

Is there a way to pass a JRuby class to a Java object expecting a Java
class?

2. Write all the scheduling madness in Java and invoke a JRuby
interpreter.
So far I've tried this:

public class RubyJob implements Job
{
      public void execute(JobExecutionContext context) throws
JobExecutionException {
            System.out.println("Executing job");
      Ruby runtime = Ruby.newInstance();
            runtime.evalScriptlet("require 'job.rb'");
      }
}

Probably not the best way to do things. Is this the preferred way to
execute
Ruby from Java?

My preference is to figure out a way to make option 1 work, since I can
write most of the gem in Ruby and not face the possibility of the JRuby
interface breaking. Any ideas on a lightweight solution?

Ikai
Paweł Wielgus (Guest)
on 2009-01-15 08:37
(Received via mailing list)
Hi Akai,
i dont know if it is an option but You might try Crone4J.
It's java library used by me pretty much, and since You use JRuby You
have a choice.

Best greetings,
Pawel Wielgus.

2009/1/14, Ikai L. <removed_email_address@domain.invalid>:
> Ruby application.
>
>
> 2. Write all the scheduling madness in Java and invoke a JRuby interpreter.
> }
>
> Probably not the best way to do things. Is this the preferred way to execute
> Ruby from Java?
>
> My preference is to figure out a way to make option 1 work, since I can
> write most of the gem in Ruby and not face the possibility of the JRuby
> interface breaking. Any ideas on a lightweight solution?
>
> Ikai
>

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email
John M. (Guest)
on 2009-01-15 08:52
(Received via mailing list)
On Thu, Jan 15, 2009 at 9:48 AM, Ikai L. <removed_email_address@domain.invalid> 
wrote:
> Any ideas on a lightweight solution?
Hi,

you might also want to take a look at the gem "rufus-scheduler" :

  http://github.com/jmettraux/rufus-scheduler
  http://openwferu.rubyforge.org/scheduler.html

It works well for me on JRuby (1.1.2 to 1.1.5 at least).


Best regards,

--
John M.   -   http://jmettraux.wordpress.com

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email
Andres K. (Guest)
on 2009-01-15 11:02
(Received via mailing list)
Hi Ikai,

What do you mean by:
> Unfortunately, it doesn't work with the newest versions of JRuby
I'm currently running Jruby-1.5 with jruby-rack-0.9.2 on tomcat using a
patched version of the Quartz-Rails plugin from Kraemer. I've posted it
a few weeks ago on this list.

However using Quartz with a YAML-config file without the need of a
servlet would be very nice!

Andres
Christian M. (Guest)
on 2009-01-15 11:08
(Received via mailing list)
Hi Ikai,

I was looking a few weeks ago for the same thing (JRuby + Quartz + Job
implementation in Ruby + not limited to a JEE environment). Because I'm
busy
at the moment, I can't finish my analysis.

A few things I have learned:
- I subclass JobDetail to make it possible to pass a job instance rather
than a class name (RAILS_ROOT/lib/sharing_stateless_job_detail.rb):

include_class 'org.quartz.JobDetail'
include_class 'org.quartz.SchedulerException'

class SharingStatelessJobDetail < org.quartz.JobDetail

  attr_accessor :job

  def initialize(name, group, job)
    super()
    setName name
    setGroup group
    @job = job
  end

  def validate
    raise org.quartz.SchedulerException.new("Job's name cannot be null",
org.quartz.SchedulerException.ERR_CLIENT_ERROR) if getName == nil
    raise org.quartz.SchedulerException.new("Job's group cannot be
null",
org.quartz.SchedulerException.ERR_CLIENT_ERROR) if getGroup == nil
  end
end

- I create a new JobFactory which return my passed job instance, rather
than
create a new instance from the provided class
(RAILS_ROOT/lib/sharing_stateless_job_factory.rb):

include_class 'org.quartz.spi.JobFactory'
include_class 'org.quartz.spi.TriggerFiredBundle'
include_class 'org.quartz.JobDetail'

class SharingStatelessJobFactory
  include org.quartz.spi.JobFactory

  def newJob bundle
    jobDetail = bundle.getJobDetail
    jobDetail.job
  end
end

- My simple logging example (RAILS_ROOT/lib/logging_job.rb):

include_class 'org.quartz.Job'
include_class 'org.quartz.JobExecutionContext'

class LoggingJob
  include org.quartz.Job

  def execute context
    RAILS_DEFAULT_LOGGER.info "LoggingJob scheduled at #{Time.now}"
  end
end

- And my initializer
(RAILS_ROOT/config/initializers/quartz_scheduler.rb):

    require 'java'
    require 'lib/commons-logging-1.1.jar'
    require 'lib/commons-collections-3.2.jar'
    require 'lib/commons-pool-1.3.jar'
    require 'lib/quartz-all-1.6.4.jar'

    require 'sharing_stateless_job_factory'
    require 'sharing_stateless_job_detail'

    include_class 'org.quartz.impl.StdSchedulerFactory'
    include_class 'org.quartz.JobDetail'
    include_class 'org.quartz.CronTrigger'

    RAILS_DEFAULT_LOGGER.info 'intializing Quartz Scheduler...'

    factory = org.quartz.impl.StdSchedulerFactory.new()
    scheduler = factory.scheduler
    scheduler.jobFactory= SharingStatelessJobFactory.new
    scheduler.startDelayed 5

    RAILS_DEFAULT_LOGGER.info 'intializing LoggingJob...'
    job = SharingStatelessJobDetail.new('LoggingJob', 'schedulingGroup',
LoggingJob.new)
    trigger = org.quartz.CronTrigger.new('LoggingJobTrigger',
'schedulingGroup', '0 * * * * ?')
    scheduler.scheduleJob(job, trigger)

    RAILS_DEFAULT_LOGGER.info 'Finished initializing quartz scheduler
and
jobs'



And  a few things I have to think over:
- If it executed in a JEE server (which starts more than one rails
instances), how do you ensure, the job is only scheduled one time?
- Quartz starts a new thread for the scheduling stuff. How we can stop
the
threads, if the user press CTRL + C if it starts rails with
script/server?

I hope this helps a little bit...

Ragards (and sorry for my poor english),
Christian
Ikai L. (Guest)
on 2009-01-15 20:46
(Received via mailing list)
Christian, wow, thanks for the awesome detailed email! I'll have to dig
back
into this when I get some free cycles.

Regarding a new thread ­ when you do jruby script/server, it starts a
new
instance of Java, so hitting Control-C should kill the instance of Java,
which should, in turn, cull all the running threads. Quartz doesn't do
anything analogous to forking, so I don't think this'll be a problem.

Also ­ in a JEE server, I believe the SchedulerFactory will return the
same
scheduler. This is because even though multiple Rails instances are
started,
Rails instances can share static Java objects. This should not be an
issue
if you are on Rails 2.2, the threadsafe release of Rails, since only one
instance of Rails is started.

Thanks for the great email. I'll look into this when I get a chance.
I'll
also look at Crone4J and rufus-scheduler, per the other comments I've
received in this thread.

Ikai
Christian M. (Guest)
on 2009-01-17 14:35
(Received via mailing list)
Hi Ikai!

My understanding (verified with a debugging session) is, Quartz create a
Threadpool with WorkerThreads (the default is 10). If I run a simple job
in
my java ide (eclipse) and exit the main method, the job is still
running.

If I run the job in rails and hitting Ctrl+C, I have the following
output:

chris:~/workspaceJRuby/scheduler mullerc$ jruby script/server
=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails 2.2.2 application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
** Starting Mongrel listening at 0.0.0.0:3000
** Starting Rails with development environment...
Jan 17, 2009 1:20:59 PM org.quartz.simpl.SimpleThreadPool initialize
INFO: Job execution threads will use class loader of thread: main
Jan 17, 2009 1:20:59 PM org.quartz.core.SchedulerSignalerImpl <init>
INFO: Initialized Scheduler Signaller of type: class
org.quartz.core.SchedulerSignalerImpl
Jan 17, 2009 1:20:59 PM org.quartz.core.QuartzScheduler <init>
INFO: Quartz Scheduler v.1.6.4 created.
Jan 17, 2009 1:20:59 PM org.quartz.simpl.RAMJobStore initialize
INFO: RAMJobStore initialized.
Jan 17, 2009 1:20:59 PM org.quartz.impl.StdSchedulerFactory instantiate
INFO: Quartz scheduler 'DefaultQuartzScheduler' initialized from default
resource file in Quartz package: 'quartz.properties'
Jan 17, 2009 1:20:59 PM org.quartz.impl.StdSchedulerFactory instantiate
INFO: Quartz scheduler version: 1.6.4
Jan 17, 2009 1:21:00 PM org.quartz.core.QuartzScheduler setJobFactory
INFO: JobFactory set to: org.jruby.gen.InterfaceImpl267287782@8434b1
intializing quartz scheduler...
intializing job 'LoggingJob'...
quartz scheduler and all jobs initialized
** Rails loaded.
** Loading any Rails specific GemPlugins
** Signals ready.  TERM => stop.  USR2 => restart.  INT => stop (no
restart).
** Rails signals registered.  HUP => reload (without restart).  It might
not
work well.
** Mongrel 1.1.5 available at 0.0.0.0:3000
** Use CTRL-C to stop.
Jan 17, 2009 1:21:05 PM org.quartz.core.QuartzScheduler start
INFO: Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
LoggingJob scheduled at Sat Jan 17 13:21:05 +0100 2009
^C** INT signal received.
Exiting


I don't know, why rails isn't shutting down as expected. I must kill the
process... :o(  Some test with the ShutdownHookPlugin from quartz are
also
not successful (with rails). Now, I will find out the reason...

Tomorrow, I will package the project with warbler and test the
SchedulerFactory
and Scheduler behavoir in a JEE environment.

I will commit the code of my tests project to
http://github.com/muellerc/quartz_scheduler/tree/master in a short
time...

Christian
Christian M. (Guest)
on 2009-01-19 09:06
(Received via mailing list)
Hi Ikai,

today, I commit the first version of my quartz scheduler plugin. It has
some
issues, but you can play with this version and any notes are welcome...
You find the plugin with install instructions ans the list of known
issues
at http://github.com/muellerc/quartz_scheduler

Christian
This topic is locked and can not be replied to.