qe 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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