stable-badge

Ubiquo Jobs

The ubiquo_jobs plugin provides a simple way to create jobs and workers that will execute them.

It aims to resolve the problem of executing code asynchronously. It can be used for all those tasks that don’t need to be run while answering a request (or shouldn’t, because are too heavy).

It tries to be simple to use, but also is filled with a lot of useful features, among which:

This guide will walk you through ubiquo_jobs internals and contains a tutorial to show you how to create new job types, planify jobs for execution and launch workers.

1 Creating job types

For every different kind of work that you want to be done you need to create a new job type. This essentially means that you have to:

  • Create a subclass of UbiquoJobs::Jobs::Base
  • Override and implement the do_job_work and place there the work that will be performed when the worker starts the job.

The following is a very simple job example, that implements this basic schema that every Job must have

# An example job class # It simply calculates a Array.size, overriding do_job_work # Passes the required arguments using the options hash # Ex: # ExampleJob.run_async(:options => {:set => [1,2]}) # will execute # [1,2].size # and store the result. To display the results use job.output_log class ExampleJob < UbiquoJobs::Jobs::Base def do_job_work set_property :result_output, self.options[:set].size return 0 end end

1.1 Parameters

If your job needs to be parameterized, use the options hash when creating to set all the needed parameters:

MassMailer.run_async(:options => { :recipients => ['one@one.one', 'two@two.two'] :subject => 'This is an example' :type => :one_time_mail })

You can use virtual attributes to get parameters, but keep in mind that every thing that is not stored inside options will likely be lost at runtime (when a worker executes your job), since for custom parameters only the options hash has the persistence guaranteed.

1.2 Return code

In ExampleJob the last line is a return 0 statement. The Job Manager needs to know if the job has been executed correctly, and that, unless exceptions are raised, is something that every job must tell to the manager by returning an error code.

This might change in the future to assume that everything went fine unless an exception is raised.

2 ActiveJob

If you know for sure that you will be using the ActiveJob implementation, you can freely use ActiveModel/ActiveRecord goodies in your job classes, including validations or callbacks.

2.1 Validations

Validations will usually be done only on creation

attr_accessor :parts, :file validates_presence_of :parts, :file, :on => :create

2.2 Callbacks

You can use the usual lifecycle callbacks too

attr_accessor :parts, :file after_validation_on_create :store_options def store_options self.options = {:parts => parts * 20, :file => 'file://' + file} end

Take in mind that you will usually just touch jobs on creation time, and then the handling is done automatically. For this reason, if your job needs some kind of parameter parsing, like in the above example, do it on creation to leave the job ready for execution.

3 Shell Jobs

If the job type you want to create will primarily execute a shell command, you will probably want to use the ShellJob helpers to do this a no-brainer. The main difference if you are using ShellJob is that, instead of implementing the do_task_work function, you need to override set_command. This is because what happens in execution time (command execution, and output/error handling) is automatically managed, so you just have to state the concrete command that will be run.

# An example shell job class # Overrides set_command method using the 'path' virtual attribute # Ex: # ExampleShellJob.run_async(:path => '.') # will execute # ls . class ExampleShellJob < UbiquoJobs::Jobs::Base include UbiquoJobs::Helpers::ShellJob attr_accessor :path def set_command self.command = 'ls ' + path end end

As you can see, we can use a virtual attribute here, since set_command is called in creation time.

4 Workers

Now that we know how to create new job types, it’s time to know how to execute them, The process that executes planified jobs is called a worker. Hence, all what is needed here is to start a worker.

script/ubiquo_worker worker_id

Every worker must have a unique and known id. This is because when a job is started, the Job Manager needs to identify which worker is doing it. In the case that a worker is killed while executing a job, starting a new worker with the same id will alert the Manager that the previous one did not finish the job, and will make this one again available to be executed.

That’s all – The worker will find available jobs (with the planification threshold overcame) and execute them immediately.

To stop all the running workers use:

script/ubiquo_worker --stop

5 Changelog

Lighthouse tickets