q 0.0.0 → 0.0.1

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,76 @@
1
+ module Q::Methods::DelayedJob
2
+ include Q::Methods::Base
3
+ class NotSetupError < StandardError
4
+ def initialize
5
+ msg = "Delayed job not setup, please run:\n"
6
+ msg << " $ bundle exec rails generate delayed_job:active_record\n"
7
+ msg << " $ bundle exec rake db:migrate\n"
8
+ super msg
9
+ end
10
+ end
11
+
12
+ class QueueConfig
13
+ def self.call
14
+ ::Delayed::Job
15
+ end
16
+ end
17
+
18
+
19
+ class QueueTask
20
+ def self.call(*rake_args)
21
+ Rake::Task["jobs:work"].invoke(rake_args)
22
+ end
23
+ end
24
+
25
+ # class NewsletterJob < Struct.new(:text, :emails)
26
+ # def perform
27
+ # emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
28
+ # end
29
+ # end
30
+ class QueueBuild
31
+ def self.call(options={}, &job)
32
+ base = options[:base]
33
+ queue_name = options[:queue_name]
34
+ queue_klass_name = options[:queue_klass_name]
35
+
36
+ raise NotSetupError unless ActiveRecord::Base.connection.table_exists? 'delayed_jobs'
37
+ raise Q::DuplicateQueueClassError.new(base, queue_klass_name) if Q.const_defined_on?(base, queue_klass_name)
38
+
39
+ queue_klass = Class.new do
40
+ def self.perform(*args)
41
+ @job.call(*args)
42
+ end
43
+
44
+ def self.job=(job)
45
+ @job = job
46
+ end
47
+
48
+ def self.queue=(queue)
49
+ @queue = queue
50
+ end
51
+ end
52
+
53
+ queue_klass.job = job
54
+ queue_klass.queue = queue_name
55
+
56
+ queue_klass = base.const_set(queue_klass_name, queue_klass)
57
+ return true
58
+ end
59
+ end
60
+
61
+ # Delayed::Job.enqueue NewsletterJob.new('lorem ipsum...', Customers.find(:all).collect(&:email))
62
+ class QueueMethod
63
+ def self.call(options = {})
64
+ base = options[:base]
65
+ queue_name = options[:queue_name]
66
+ queue_klass_name = options[:queue_klass_name]
67
+ queue_klass = base.const_get(queue_klass_name)
68
+
69
+ raise Q::DuplicateQueueMethodError.new(base, queue_name) if base.queue.respond_to?(queue_name)
70
+
71
+ base.queue.define_singleton_method(queue_name) do |*args|
72
+ ::Delayed::Job.enqueue(queue_klass, *args)
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,73 @@
1
+ module Q::Methods::Resque
2
+ include Q::Methods::Base
3
+
4
+ class QueueConfig
5
+ def self.call
6
+ ::Resque
7
+ end
8
+ end
9
+
10
+ class QueueTask
11
+ def self.call(*rake_args)
12
+ Resque.logger.level ||= Integer(ENV['VVERBOSE'] || 1)
13
+ ENV['QUEUE'] ||= "*"
14
+ ENV['VERBOSE'] ||= "1"
15
+ ENV['TERM_CHILD'] ||= '1'
16
+ ENV['VVERBOSE'] = nil
17
+ define_setup!
18
+ Rake::Task["resque:work"].invoke(rake_args)
19
+ end
20
+
21
+ def self.define_setup!
22
+ return true unless Rake::Task.task_defined?("resque:setup")
23
+ Rake::Task.define_task("resque:setup" => :environment) do
24
+ Resque.before_fork = Proc.new { ActiveRecord::Base.establish_connection } if defined?(ActiveRecord)
25
+ end
26
+ end
27
+ end
28
+
29
+ class QueueBuild
30
+ def self.call(options={}, &job)
31
+ base = options[:base]
32
+ queue_name = options[:queue_name]
33
+ queue_klass_name = options[:queue_klass_name]
34
+
35
+ raise Q::DuplicateQueueClassError.new(base, queue_klass_name) if Q.const_defined_on?(base, queue_klass_name)
36
+
37
+ queue_klass = Class.new do
38
+ def self.perform(*args)
39
+ @job.call(*args)
40
+ end
41
+
42
+ def self.job=(job)
43
+ @job = job
44
+ end
45
+
46
+ def self.queue=(queue)
47
+ @queue = queue
48
+ end
49
+ end
50
+
51
+ queue_klass.job = job
52
+ queue_klass.queue = queue_name
53
+
54
+ queue_klass = base.const_set(queue_klass_name, queue_klass)
55
+ return true
56
+ end
57
+ end
58
+
59
+ class QueueMethod
60
+ def self.call(options = {})
61
+ base = options[:base]
62
+ queue_name = options[:queue_name]
63
+ queue_klass_name = options[:queue_klass_name]
64
+ queue_klass = base.const_get(queue_klass_name)
65
+
66
+ raise Q::DuplicateQueueMethodError.new(base, queue_name) if base.queue.respond_to?(queue_name)
67
+
68
+ base.queue.define_singleton_method(queue_name) do |*args|
69
+ ::Resque.enqueue(queue_klass, *args)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,123 @@
1
+ module Q::Methods::Sidekiq
2
+ include Q::Methods::Base
3
+
4
+ class QueueConfig
5
+ def self.call
6
+ setup_inline!
7
+ ::Sidekiq
8
+ end
9
+
10
+ def self.setup_inline!
11
+ return if @regular_client
12
+ @regular_client = ::Sidekiq::Client
13
+
14
+ ::Sidekiq.define_singleton_method(:inline) do
15
+ ::Sidekiq::Client == @inline_client
16
+ end
17
+
18
+ ::Sidekiq.define_singleton_method(:inline=) do |val|
19
+ @regular_client ||= ::Sidekiq::Client
20
+
21
+ if val
22
+ require 'sidekiq/testing/inline'
23
+ @inline_client ||= ::Sidekiq::Client
24
+ Sidekiq.const_set("Client", @inline_client)
25
+ else
26
+ Sidekiq.const_set("Client", @regular_client)
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ class QueueTask
33
+
34
+ # -c, --concurrency INT processor threads to use
35
+ # -d, --daemon Daemonize process
36
+ # -e, --environment ENV Application environment
37
+ # -g, --tag TAG Process tag for procline
38
+ # -i, --index INT unique process index on this machine
39
+ # -p, --profile Profile all code run by Sidekiq
40
+ # -q, --queue QUEUE[,WEIGHT]... Queues to process with optional weights
41
+ # -r, --require [PATH|DIR] Location of Rails application with workers or file to require
42
+ # -t, --timeout NUM Shutdown timeout
43
+ # -v, --verbose Print more verbose output
44
+ # -C, --config PATH path to YAML config file
45
+ # -L, --logfile PATH path to writable logfile
46
+ # -P, --pidfile PATH path to pidfile
47
+ # -V, --version Print version and exit
48
+ # -h, --help Show help
49
+ def self.call(*args)
50
+ setup!
51
+ cmd = "bundle exec sidekiq "
52
+ cmd << ENV["QUEUE"] if ENV["QUEUE"]
53
+ cmd << args.join(" ") if args.any?
54
+ puts cmd.inspect
55
+ exec cmd
56
+ end
57
+
58
+ def self.setup!
59
+ return unless database_url = ENV['DATABASE_URL']
60
+ Sidekiq.configure_server do |config|
61
+ ENV['DATABASE_URL'] = "#{database_url}?pool=25"
62
+ ActiveRecord::Base.establish_connection
63
+ end
64
+ end
65
+ end
66
+
67
+ # example
68
+ # class SinatraWorker
69
+ # include Sidekiq::Worker
70
+ #
71
+ # def perform(msg="lulz you forgot a msg!")
72
+ # $redis.lpush("sinkiq-example-messages", msg)
73
+ # end
74
+ # end
75
+ class QueueBuild
76
+ def self.call(options={}, &job)
77
+ base = options[:base]
78
+ queue_name = options[:queue_name]
79
+ queue_klass_name = options[:queue_klass_name]
80
+
81
+ raise Q::DuplicateQueueClassError.new(base, queue_klass_name) if Q.const_defined_on?(base, queue_klass_name)
82
+
83
+ queue_klass = Class.new do
84
+ include ::Sidekiq::Worker
85
+
86
+ def perform(*args)
87
+ @job.call(*args)
88
+ end
89
+
90
+ def self.job=(job)
91
+ @job = job
92
+ end
93
+
94
+ def self.queue=(queue)
95
+ @queue = queue
96
+ end
97
+ end
98
+
99
+ queue_klass.job = job
100
+ queue_klass.queue = queue_name
101
+
102
+ queue_klass = base.const_set(queue_klass_name, queue_klass)
103
+ return true
104
+ end
105
+ end
106
+
107
+ # Example
108
+ # SinatraWorker.perform_async params[:msg]
109
+ class QueueMethod
110
+ def self.call(options = {})
111
+ base = options[:base]
112
+ queue_name = options[:queue_name]
113
+ queue_klass_name = options[:queue_klass_name]
114
+ queue_klass = base.const_get(queue_klass_name)
115
+
116
+ raise Q::DuplicateQueueMethodError.new(base, queue_name) if base.queue.respond_to?(queue_name)
117
+
118
+ base.queue.define_singleton_method(queue_name) do |*args|
119
+ queue_klass.perform_async(*args)
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,66 @@
1
+ module Q::Methods::ThreadedInMemoryQueue
2
+ def self.included(base)
3
+ require 'threaded_in_memory_queue'
4
+ at_exit do
5
+ ThreadedInMemoryQueue.stop unless ::ThreadedInMemoryQueue.stopped?
6
+ end
7
+ super base
8
+ end
9
+
10
+ include Q::Methods::Base
11
+
12
+ class QueueConfig
13
+ def self.call
14
+ ::ThreadedInMemoryQueue
15
+ end
16
+ end
17
+
18
+ class QueueTask
19
+ def self.call(*rake_args)
20
+ raise "Threaded In Memory Queue runs in web process, no need to start"
21
+ end
22
+ end
23
+
24
+ class QueueBuild
25
+ def self.call(options={}, &job)
26
+ base = options[:base]
27
+ queue_name = options[:queue_name]
28
+ queue_klass_name = options[:queue_klass_name]
29
+
30
+ raise Q::DuplicateQueueClassError.new(base, queue_klass_name) if Q.const_defined_on?(base, queue_klass_name)
31
+
32
+ queue_klass = Class.new do
33
+ def self.call(*args)
34
+ @job.call(*args)
35
+ end
36
+
37
+ def self.job=(job)
38
+ @job = job
39
+ end
40
+ end
41
+
42
+ queue_klass.job = job
43
+ base.const_set(queue_klass_name, queue_klass)
44
+ return true
45
+ end
46
+ end
47
+
48
+ class QueueMethod
49
+ def self.call(options = {})
50
+ base = options[:base]
51
+ queue_name = options[:queue_name]
52
+ queue_klass_name = options[:queue_klass_name]
53
+ queue_klass = base.const_get(queue_klass_name)
54
+
55
+ raise Q::DuplicateQueueMethodError.new(base, queue_name) if base.queue.respond_to?(queue_name)
56
+ base.queue.define_singleton_method(queue_name) do |*args|
57
+ ::ThreadedInMemoryQueue.start unless ::ThreadedInMemoryQueue.started?
58
+ ::ThreadedInMemoryQueue.enqueue(queue_klass, *args)
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ # alias
65
+ Q::Methods::Threaded = Q::Methods::ThreadedInMemoryQueue
66
+ Q.queue_lookup[:threaded] = Proc.new {Q::Methods::Threaded}
@@ -0,0 +1,14 @@
1
+ module Q
2
+ module QueueTask
3
+ def self.call(*args)
4
+ Q.queue::QueueTask.call(args)
5
+ end
6
+ end
7
+ end
8
+
9
+ if defined?(Rake)
10
+ task = Rake::Task.define_task("q:work" => :environment) do |t, args|
11
+ Q::QueueTask.call(args)
12
+ end
13
+ task.add_description "Processes background work using the Q library"
14
+ end
@@ -1,3 +1,3 @@
1
1
  module Q
2
- VERSION = "0.0.0"
2
+ VERSION = "0.0.1"
3
3
  end
data/q.gemspec CHANGED
@@ -1,24 +1,30 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "q/version"
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'q/version'
4
5
 
5
- Gem::Specification.new do |s|
6
- s.name = "q"
7
- s.version = Q::VERSION
8
- s.authors = ["Christopher M. Hobbs"]
9
- s.email = ["chris@altbit.org"]
10
- s.homepage = "http://github.com/hooobs/q"
11
- s.summary = %q{q is for Journal}
12
- s.description = %q{q is a command line activity logger/time tracker.}
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "q"
8
+ gem.version = Q::VERSION
9
+ gem.authors = ["Richard Schneeman"]
10
+ gem.email = ["richard.schneeman+rubygems@gmail.com"]
11
+ gem.description = %q{ A universal interface for Ruby queueing backends. }
12
+ gem.summary = %q{ Use Q to switch betwen queue backends as you please. Simplifies creating and calling background jobs }
13
+ gem.homepage = "https://github.com/schneems/q"
14
+ gem.license = "MIT"
13
15
 
14
- s.add_dependency("i18n")
15
- s.add_dependency("trollop")
16
- s.add_dependency("chronic")
17
- s.add_dependency("dm-core")
18
- s.add_dependency("dm-migrations")
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ["lib"]
19
20
 
20
- s.files = `git ls-files`.split("\n")
21
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
23
- s.require_paths = ["lib"]
21
+ gem.add_dependency "proc_to_lambda"
22
+ gem.add_dependency "threaded_in_memory_queue"
23
+
24
+ gem.add_development_dependency "rake"
25
+ gem.add_development_dependency "mocha"
26
+ gem.add_development_dependency "resque"
27
+ gem.add_development_dependency "sidekiq"
28
+ gem.add_development_dependency "delayed_job_active_record"
29
+ gem.add_development_dependency "sqlite3"
24
30
  end
@@ -0,0 +1,103 @@
1
+ require 'test_helper'
2
+
3
+ module FakeQueueKlass
4
+ include Q::Methods::Base
5
+
6
+ class QueueMethod; end
7
+ class QueueBuild; end
8
+ class QueueTask; end
9
+ class QueueConfig; end
10
+ end
11
+
12
+ class FakeUserKlass
13
+ include FakeQueueKlass
14
+ end
15
+
16
+ module FakeIncludesKlass
17
+ def self.bar(val)
18
+ end
19
+
20
+ def self.included(klass)
21
+ self.bar
22
+ super
23
+ end
24
+
25
+ include FakeQueueKlass
26
+ end
27
+
28
+ class QMethodsBaseTest < Test::Unit::TestCase
29
+
30
+ def test_includes_propper_things
31
+ assert_includes FakeQueueKlass, Q::Methods::Base
32
+ assert_respond_to FakeUserKlass, :queue
33
+ assert_respond_to FakeUserKlass.new, :queue
34
+ end
35
+
36
+ def test_queue_klass
37
+ assert_equal FakeQueueKlass, FakeUserKlass.class_variable_get("@@_q_klass")
38
+ end
39
+
40
+ def test_includes_gets_called
41
+ FakeIncludesKlass.expects(:bar).once
42
+ Class.new do
43
+ include FakeIncludesKlass
44
+ end
45
+ assert_includes FakeIncludesKlass, Q::Methods::Base
46
+ end
47
+
48
+ def test_raises_error_missing_klasses
49
+ # assert no raise
50
+ foo = Module.new do
51
+ include Q::Methods::Base
52
+ end
53
+ foo.const_set(:QueueMethod, "")
54
+ foo.const_set(:QueueBuild, "")
55
+ foo.const_set(:QueueTask, "")
56
+ foo.const_set(:QueueConfig, "")
57
+ Class.new { include foo }
58
+
59
+ error = assert_raise(Q::MissingClassError) do
60
+ foo = Module.new do
61
+ include Q::Methods::Base
62
+ end
63
+ foo.const_set(:QueueBuild, "")
64
+ foo.const_set(:QueueTask, "")
65
+ foo.const_set(:QueueConfig, "")
66
+ Class.new { include foo }
67
+ end
68
+ assert_match "QueueMethod", error.message
69
+
70
+ error = assert_raise(Q::MissingClassError) do
71
+ foo = Module.new do
72
+ include Q::Methods::Base
73
+ end
74
+ foo.const_set(:QueueMethod, "")
75
+ foo.const_set(:QueueTask, "")
76
+ foo.const_set(:QueueConfig, "")
77
+ Class.new { include foo }
78
+ end
79
+ assert_match "QueueBuild", error.message
80
+
81
+ error = assert_raise(Q::MissingClassError) do
82
+ foo = Module.new do
83
+ include Q::Methods::Base
84
+ end
85
+ foo.const_set(:QueueMethod, "")
86
+ foo.const_set(:QueueBuild, "")
87
+ foo.const_set(:QueueConfig, "")
88
+ Class.new { include foo }
89
+ end
90
+ assert_match "QueueTask", error.message
91
+
92
+ error = assert_raise(Q::MissingClassError) do
93
+ foo = Module.new do
94
+ include Q::Methods::Base
95
+ end
96
+ foo.const_set(:QueueMethod, "")
97
+ foo.const_set(:QueueBuild, "")
98
+ foo.const_set(:QueueTask, "")
99
+ Class.new { include foo }
100
+ end
101
+ assert_match "QueueConfig", error.message
102
+ end
103
+ end