qe 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ require "bundler"
2
+ Bundler.setup(:default)
3
+ Bundler.require(:default)
4
+
5
+ run BeanstalkdView::Server
@@ -0,0 +1,16 @@
1
+ require "./workers"
2
+
3
+ ActiveRecord::Schema.define(:version => 0) do
4
+ create_table :delayed_jobs, :force => true do |table|
5
+ table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue
6
+ table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually.
7
+ table.text :handler # YAML-encoded string of the object that will do work
8
+ table.text :last_error # reason for last failure (See Note below)
9
+ table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
10
+ table.datetime :locked_at # Set when a client is working on this object
11
+ table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
12
+ table.string :locked_by # Who is working on this object (if locked)
13
+ table.string :queue # The name of the queue this job is in
14
+ table.timestamps
15
+ end
16
+ end
@@ -0,0 +1 @@
1
+ loglevel notice
@@ -0,0 +1,6 @@
1
+ require "bundler"
2
+ Bundler.setup(:default)
3
+ Bundler.require(:default)
4
+
5
+ require "resque/server"
6
+ run Resque::Server
@@ -0,0 +1,11 @@
1
+ require "./workers"
2
+
3
+ loop do
4
+ puts "=> Enqueuing jobs [#{Time.now}]"
5
+
6
+ MailerWorker.enqueue(:name => "John Doe", :email => "john@example.org")
7
+ ClockWorker.enqueue
8
+
9
+ sleep 3
10
+ end
11
+
@@ -0,0 +1,10 @@
1
+ require "bundler"
2
+ Bundler.setup(:default)
3
+ Bundler.require(:default)
4
+
5
+ Sidekiq.configure_client do |config|
6
+ config.redis = { :size => 1 }
7
+ end
8
+
9
+ require "sidekiq/web"
10
+ run Sidekiq::Web
@@ -0,0 +1,43 @@
1
+ require "bundler"
2
+ Bundler.setup(:default)
3
+ Bundler.require
4
+
5
+ $:.unshift File.expand_path("../../lib", __FILE__)
6
+ require "qe"
7
+
8
+ $stdout.sync = true
9
+
10
+ Qe.adapter = Qe::Sidekiq
11
+ # Qe.adapter = Qe::Beanstalk
12
+ # Qe.adapter = Qe::Resque
13
+ # Qe.adapter = Qe::DelayedJob
14
+ # Qe.adapter = Qe::Qu
15
+ # Qe.adapter = Qe::Testing
16
+
17
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => "jobs.sqlite3")
18
+
19
+ class ClockWorker
20
+ include Qe::Worker
21
+
22
+ def perform
23
+ puts "=> Time: #{Time.now}"
24
+ end
25
+ end
26
+
27
+ class MailerWorker
28
+ include Qe::Worker
29
+ queue :mail
30
+
31
+ def before
32
+ puts "=> Running before"
33
+ end
34
+
35
+ def perform
36
+ puts "=> Performing"
37
+ puts "=> Options: #{options.inspect}"
38
+ end
39
+
40
+ def after
41
+ puts "=> Running after"
42
+ end
43
+ end
@@ -0,0 +1,79 @@
1
+ require "qe/immediate"
2
+ require "qe/version"
3
+ require "qe/worker"
4
+
5
+ # In this wild world where a new asynchronous job processing
6
+ # library is released every once in a while, Qe tries to keep a unified
7
+ # interface that works with most famous libraries:
8
+ #
9
+ # # Sidekiq
10
+ # # Resque
11
+ # # DelayedJob
12
+ # # Qu
13
+ # # Beanstalk/Backburner
14
+ #
15
+ # See an example:
16
+ #
17
+ # You can choose an adapter:
18
+ #
19
+ # Qe.adapter = Qe::Sidekiq
20
+ # Qe.adapter = Qe::Resque
21
+ # Qe.adapter = Qe::Qu
22
+ # Qe.adapter = Qe::DelayedJob
23
+ # Qe.adapter = Qe::Beanstalk
24
+ #
25
+ # Create our worker that will send e-mails through +ActionMailer+.
26
+ #
27
+ # class MailerWorker
28
+ # include Qe::Worker
29
+ #
30
+ # def perform
31
+ # Mailer.public_send(options[:mail], options).deliver
32
+ # end
33
+ # end
34
+ #
35
+ # Define our +Mailer+ class.
36
+ #
37
+ # class Mailer < ActionMailer::Base
38
+ # def welcome(options)
39
+ # @options = options
40
+ # mail :to => options[:email]
41
+ # end
42
+ # end
43
+ #
44
+ # Enqueue a job to be processed asynchronously.
45
+ #
46
+ # MailerWorker.enqueue({
47
+ # :mail => :welcome,
48
+ # :email => "john@example.org",
49
+ # :name => "John Doe"
50
+ # })
51
+ #
52
+ # == Testing support
53
+ #
54
+ # Qe comes with testing support. Just require the <tt>qe/testing.rb</tt> file
55
+ # and a fake queuing adapter will be used. All enqueued jobs will be stored
56
+ # at <tt>Qe.jobs</tt>. Note that this method is only available on testing mode.
57
+ #
58
+ # require "qe/testing"
59
+ # Qe.adapter = Qe::Testing
60
+ #
61
+ # If you're using RSpec, you can require the <tt>qe/testing/rspec.rb</tt> file
62
+ # instead. This will reset <tt>Qe.jobs</tt> before every spec and will add a
63
+ # +enqueue+ matcher.
64
+ #
65
+ # require "qe/testing/rspec"
66
+ #
67
+ # describe "Enqueuing a job" do
68
+ # it "enqueues job" do
69
+ # expect {
70
+ # # do something
71
+ # }.to enqueue(MailerWorker).with(:email => "john@example.org")
72
+ # end
73
+ # end
74
+ #
75
+ module Qe
76
+ class << self
77
+ attr_accessor :adapter
78
+ end
79
+ end
@@ -0,0 +1,21 @@
1
+ require "qe"
2
+ require "backburner"
3
+
4
+ module Qe
5
+ class Beanstalk
6
+ class Worker
7
+ include Backburner::Queue
8
+
9
+ def self.perform(*args)
10
+ Qe::Worker.perform(*args)
11
+ end
12
+ end
13
+
14
+ def self.enqueue(worker, options = {})
15
+ Worker.queue worker.queue
16
+ Backburner.enqueue Worker, worker.name, options
17
+ end
18
+ end
19
+
20
+ self.adapter = Beanstalk
21
+ end
@@ -0,0 +1,18 @@
1
+ require "qe"
2
+ require "delayed_job"
3
+
4
+ module Qe
5
+ class DelayedJob
6
+ class Worker < Struct.new(:worker_name, :options)
7
+ def perform
8
+ Qe::Worker.perform(worker_name, options)
9
+ end
10
+ end
11
+
12
+ def self.enqueue(worker, options = {})
13
+ Delayed::Job.enqueue Worker.new(worker.name, options), :queue => worker.queue
14
+ end
15
+ end
16
+
17
+ self.adapter = DelayedJob
18
+ end
@@ -0,0 +1,7 @@
1
+ module Qe
2
+ class Immediate
3
+ def self.enqueue(worker, options = {})
4
+ Qe::Worker.perform(worker.name, options)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,21 @@
1
+ require "qe"
2
+ require "qu"
3
+
4
+ module Qe
5
+ class Qu
6
+ class Worker
7
+ include ::Sidekiq::Worker
8
+
9
+ def self.perform(*args)
10
+ Qe::Worker.perform(*args)
11
+ end
12
+ end
13
+
14
+ def self.enqueue(worker, options = {})
15
+ Worker.instance_variable_set("@queue", worker.queue)
16
+ ::Qu.enqueue Worker, worker.name, options
17
+ end
18
+ end
19
+
20
+ self.adapter = Qu
21
+ end
@@ -0,0 +1,19 @@
1
+ require "qe"
2
+ require "resque"
3
+
4
+ module Qe
5
+ class Resque
6
+ class Worker
7
+ def self.perform(*args)
8
+ Qe::Worker.perform(*args)
9
+ end
10
+ end
11
+
12
+ def self.enqueue(worker, options = {})
13
+ Worker.instance_variable_set "@queue", worker.queue
14
+ ::Resque.enqueue Worker, worker.name, options
15
+ end
16
+ end
17
+
18
+ self.adapter = Resque
19
+ end
@@ -0,0 +1,21 @@
1
+ require "qe"
2
+ require "sidekiq"
3
+
4
+ module Qe
5
+ class Sidekiq
6
+ class Worker
7
+ include ::Sidekiq::Worker
8
+
9
+ def perform(*args)
10
+ Qe::Worker.perform(*args)
11
+ end
12
+ end
13
+
14
+ def self.enqueue(worker, options = {})
15
+ Worker.sidekiq_options :queue => worker.queue
16
+ Worker.perform_async(worker.name, options)
17
+ end
18
+ end
19
+
20
+ self.adapter = Sidekiq
21
+ end
@@ -0,0 +1,11 @@
1
+ module Qe
2
+ def self.jobs
3
+ @jobs ||= []
4
+ end
5
+
6
+ class Testing
7
+ def self.enqueue(worker, options = {})
8
+ Qe.jobs << {:worker => worker, :options => options}
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,59 @@
1
+ require "qe/testing"
2
+
3
+ module Qe
4
+ module EnqueueMatcher
5
+ class Matcher
6
+ attr_reader :worker, :options
7
+
8
+ def initialize(worker)
9
+ @worker = worker
10
+ end
11
+
12
+ def with(options)
13
+ @options = options
14
+ self
15
+ end
16
+
17
+ def matches?(block)
18
+ block.call
19
+
20
+ Qe.jobs.find do |job|
21
+ condition = job[:worker] == worker
22
+ condition = condition && job[:options] == options if options
23
+ condition
24
+ end != nil
25
+ end
26
+
27
+ def description
28
+ "enqueue job for #{worker.inspect} worker"
29
+ end
30
+
31
+ def failure_message_for_should
32
+ build_message "expect #{worker.inspect} to be enqueued"
33
+ end
34
+
35
+ def failure_message_for_should_not
36
+ build_message "expect #{worker.inspect} not to be enqueued"
37
+ end
38
+
39
+ def build_message(base)
40
+ base << (options.empty? ? "" : " with #{options.inspect}")
41
+ end
42
+ end
43
+
44
+ #
45
+ # expect {}.to enqueue(MailerWorker).with(options)
46
+ #
47
+ def enqueue(worker)
48
+ Matcher.new(worker)
49
+ end
50
+ end
51
+ end
52
+
53
+ RSpec.configure do |config|
54
+ config.include Qe::EnqueueMatcher
55
+ config.before(:each) do
56
+ Qe.adapter = Qe::Testing
57
+ Qe.jobs.clear
58
+ end
59
+ end
@@ -0,0 +1,3 @@
1
+ module Qe
2
+ VERSION = "0.1.3"
3
+ end
@@ -0,0 +1,71 @@
1
+ module Qe
2
+ module Worker
3
+ def self.included(base)
4
+ base.class_eval do
5
+ include InstanceMethods
6
+ extend ClassMethods
7
+ end
8
+ end
9
+
10
+ module InstanceMethods
11
+ def initialize(options)
12
+ @options = options
13
+ end
14
+
15
+ # Return options that were provided when
16
+ # adding job to the queue.
17
+ def options
18
+ @options
19
+ end
20
+
21
+ # Set before hook.
22
+ def before
23
+ end
24
+
25
+ # Set after hook.
26
+ def after
27
+ end
28
+
29
+ # Set the error hook.
30
+ def error(error)
31
+ raise error
32
+ end
33
+ end
34
+
35
+ module ClassMethods
36
+ # Enqueue job on given worker class.
37
+ def enqueue(options = {})
38
+ Qe.adapter.enqueue(self, options)
39
+ end
40
+
41
+ # Set the queue name when receiving on argument.
42
+ # Return queue name otherwise.
43
+ def queue(*args)
44
+ @queue = args.first unless args.empty?
45
+ (@queue || :default).to_s
46
+ end
47
+ end
48
+
49
+ # Find a worker by its name.
50
+ # If worker constant is not found, raises a +NameError+
51
+ # exception.
52
+ def self.find(name)
53
+ name.split("::").reduce(Object) do |const, name|
54
+ const.const_get(name)
55
+ end
56
+ end
57
+
58
+ # Perform the specified worker if given options.
59
+ def self.perform(worker_name, options)
60
+ find(worker_name).new(options).tap do |job|
61
+ begin
62
+ job.before
63
+ job.perform
64
+ job.after
65
+ rescue Exception => error
66
+ job.error(error)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end