ctt-background-jobs 0.8.0
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.
- data/.gitignore +18 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/CTT-Background-Jobs.gemspec +37 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +25 -0
- data/Rakefile +29 -0
- data/lib/background_jobs/configuration.rb +27 -0
- data/lib/background_jobs/job.rb +17 -0
- data/lib/background_jobs/job_factory.rb +9 -0
- data/lib/background_jobs/job_id_generator.rb +15 -0
- data/lib/background_jobs/job_notifier.rb +31 -0
- data/lib/background_jobs/job_queue_factory.rb +36 -0
- data/lib/background_jobs/job_registry.rb +65 -0
- data/lib/background_jobs/queue_service.rb +17 -0
- data/lib/background_jobs/strategies/direct_call/job_queue.rb +11 -0
- data/lib/background_jobs/strategies/sidekiq/job_adapter.rb +21 -0
- data/lib/background_jobs/strategies/sidekiq/job_attributes_adapter.rb +141 -0
- data/lib/background_jobs/strategies/sidekiq/job_queue.rb +42 -0
- data/lib/background_jobs/strategies/sidekiq/setup.rb +31 -0
- data/lib/version.rb +3 -0
- data/spec/fast_helper.rb +11 -0
- data/spec/integration/sidekiq_spec.rb +34 -0
- data/spec/lib/background_jobs/configuration_spec.rb +13 -0
- data/spec/lib/background_jobs/job_factory_fast_spec.rb +24 -0
- data/spec/lib/background_jobs/job_fast_spec.rb +38 -0
- data/spec/lib/background_jobs/job_id_generator_fast_spec.rb +23 -0
- data/spec/lib/background_jobs/job_notififer_spec.rb +9 -0
- data/spec/lib/background_jobs/job_queue_factory_fast_spec.rb +58 -0
- data/spec/lib/background_jobs/queue_service_fast_spec.rb +36 -0
- data/spec/lib/background_jobs/strategies/direct_call/job_queue_spec.rb +27 -0
- data/spec/lib/background_jobs/strategies/sidekiq/job_adapter_spec.rb +30 -0
- data/spec/lib/background_jobs/strategies/sidekiq/job_attributes_adapter_spec.rb +129 -0
- data/spec/lib/background_jobs/strategies/sidekiq/job_queue_spec.rb +63 -0
- data/spec/lib/background_jobs/torquebox_jobs_queue_fast_spec.rb +31 -0
- data/spec/support/job_queue.rb +7 -0
- metadata +281 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ctt-background-jobs
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-1.9.3-p194
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ctt-background-jobs"
|
8
|
+
spec.version = BackgroundJobs::VERSION
|
9
|
+
spec.authors = ["CTT Innovations"]
|
10
|
+
spec.email = ["info@cttinnovations.com"]
|
11
|
+
spec.description = 'Common CTT caching tools.'
|
12
|
+
spec.summary = 'CTT Caching.'
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'ctt-notifications', "~> 0.1"
|
22
|
+
spec.add_dependency 'require_relative', '1.0.2'
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
25
|
+
spec.add_development_dependency 'delayed_job_active_record', '0.4.2'
|
26
|
+
spec.add_development_dependency 'imitate', '0.2.0'
|
27
|
+
spec.add_development_dependency 'mocha', '0.13.3'
|
28
|
+
spec.add_development_dependency "rake"
|
29
|
+
spec.add_development_dependency 'rspec', '2.13.0'
|
30
|
+
spec.add_development_dependency 'shoulda', '3.4.0'
|
31
|
+
spec.add_development_dependency 'sidekiq'
|
32
|
+
spec.add_development_dependency 'timecop', '0.6.1'
|
33
|
+
|
34
|
+
if RUBY_ENGINE == 'jruby'
|
35
|
+
spec.add_development_dependency 'torquebox', '2.3.0'
|
36
|
+
end
|
37
|
+
end
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Petr Janda
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# CTT::BackgroundJobs
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
Add this line to your application's Gemfile:
|
6
|
+
|
7
|
+
gem 'ctt-background-jobs'
|
8
|
+
|
9
|
+
And then execute:
|
10
|
+
|
11
|
+
$ bundle
|
12
|
+
|
13
|
+
Or install it yourself as:
|
14
|
+
|
15
|
+
$ gem install ctt-background-jobs
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
## Contributing
|
20
|
+
|
21
|
+
1. Fork it
|
22
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
23
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
24
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
25
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
task :release_private do
|
4
|
+
require 'version'
|
5
|
+
|
6
|
+
version = BackgroundJobs::VERSION
|
7
|
+
|
8
|
+
puts '** Commiting the VERSION file'
|
9
|
+
system 'git add lib/version.rb'
|
10
|
+
system "git commit -m 'v#{version}'"
|
11
|
+
|
12
|
+
puts '** Tagging the git version'
|
13
|
+
system "git tag v#{version}"
|
14
|
+
|
15
|
+
puts '** Pushing tag to remote'
|
16
|
+
system "git push origin v#{version}"
|
17
|
+
|
18
|
+
|
19
|
+
puts '** Pushing to remote'
|
20
|
+
system 'git push origin master'
|
21
|
+
|
22
|
+
puts '** Building the gem'
|
23
|
+
system 'gem build ctt-background-jobs.gemspec'
|
24
|
+
|
25
|
+
puts '** Publishing the gem'
|
26
|
+
system "gem inabox ctt-background-jobs-#{version}.gem"
|
27
|
+
|
28
|
+
puts '** Relax. All done.'
|
29
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module BackgroundJobs
|
4
|
+
def self.configure
|
5
|
+
yield Configuration.instance
|
6
|
+
|
7
|
+
strategy = BackgroundJobs.config.strategy
|
8
|
+
|
9
|
+
case strategy
|
10
|
+
when 'sidekiq'
|
11
|
+
options = BackgroundJobs.config.strategy_options
|
12
|
+
|
13
|
+
require 'background_jobs/strategies/sidekiq/setup'
|
14
|
+
BackgroundJobs::Sidekiq.setup options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.config
|
19
|
+
Configuration.instance
|
20
|
+
end
|
21
|
+
|
22
|
+
class Configuration
|
23
|
+
include Singleton
|
24
|
+
|
25
|
+
attr_accessor :strategy, :strategy_options
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'digest'
|
2
|
+
|
3
|
+
module BackgroundJobs
|
4
|
+
module JobIdGenerator
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def generate_job_id
|
11
|
+
Digest::SHA256.hexdigest("#{Time.now.to_f}-#{rand(0)}")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'i18n'
|
2
|
+
require 'notification/notifier_service'
|
3
|
+
require 'notification/channel_name_service'
|
4
|
+
|
5
|
+
module BackgroundJobs
|
6
|
+
module JobNotifier
|
7
|
+
def error(job, exception)
|
8
|
+
super(job, exception)
|
9
|
+
|
10
|
+
notify_error(:message => I18n.t(:flash_background_error))
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def notify_error(data)
|
16
|
+
notify('error', data)
|
17
|
+
end
|
18
|
+
|
19
|
+
def notify_success(data)
|
20
|
+
notify('success', data)
|
21
|
+
end
|
22
|
+
|
23
|
+
def notify(event, data)
|
24
|
+
Notification::NotifierService.notify(channel_name, event, data)
|
25
|
+
end
|
26
|
+
|
27
|
+
def channel_name
|
28
|
+
@channel_name ||= Notification::ChannelNameService.private_channel_name(@id)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative 'configuration'
|
2
|
+
|
3
|
+
module BackgroundJobs
|
4
|
+
class UnknownBackgroundJobsQueueStrategy < RuntimeError
|
5
|
+
def initialize(strategy_name)
|
6
|
+
@strategy_name = strategy_name
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
"Unknown strategy '#{@strategy_name}' doesnt exist!"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class JobQueueFactory
|
15
|
+
def self.build
|
16
|
+
to_class(Configuration.instance.strategy)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def self.to_class(strategy_name)
|
22
|
+
case strategy_name
|
23
|
+
when 'sidekiq'
|
24
|
+
require 'background_jobs/strategies/sidekiq/job_queue'
|
25
|
+
Sidekiq::JobQueue.new
|
26
|
+
|
27
|
+
when 'direct_call'
|
28
|
+
require 'background_jobs/strategies/direct_call/job_queue'
|
29
|
+
DirectCall::JobQueue.new
|
30
|
+
|
31
|
+
else
|
32
|
+
raise UnknownBackgroundJobsQueueStrategy.new(strategy_name)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module BackgroundJobs
|
4
|
+
class UnknownJob < RuntimeError
|
5
|
+
def initialize(job_name)
|
6
|
+
@job_name = job_name
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
"Unknown job '#{@job_name}'!"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class JobMetadata
|
15
|
+
attr_reader :name, :type, :clazz, :options
|
16
|
+
|
17
|
+
def initialize(name, type, clazz, options = nil)
|
18
|
+
@name, @type, @clazz, @options = name, type, clazz, options
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class JobRegistry
|
23
|
+
include Singleton
|
24
|
+
|
25
|
+
attr_writer :register_callback
|
26
|
+
|
27
|
+
def register_job(job_metadata)
|
28
|
+
jobs[job_metadata.name] = job_metadata
|
29
|
+
|
30
|
+
@register_callback.call(job_metadata) if @register_callback
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_class!(job_name)
|
34
|
+
raise UnknownJob.new(job_name) unless job_metadata = get(job_name)
|
35
|
+
|
36
|
+
job_metadata.clazz
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_type(job_name)
|
40
|
+
raise UnknownJob.new(job_name) unless job_metadata = get(job_name)
|
41
|
+
|
42
|
+
job_metadata.type
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def get(job_name)
|
48
|
+
jobs[job_name]
|
49
|
+
end
|
50
|
+
|
51
|
+
def jobs
|
52
|
+
@jobs ||= {}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.register_job(job_name, job_type, job_class, options = {})
|
57
|
+
job_registry.register_job JobMetadata.new(job_name, job_type, job_class, options)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def self.job_registry
|
63
|
+
JobRegistry.instance
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'background_jobs/job_id_generator'
|
2
|
+
require 'background_jobs/job_queue_factory'
|
3
|
+
|
4
|
+
module BackgroundJobs
|
5
|
+
class QueueService
|
6
|
+
include JobIdGenerator
|
7
|
+
|
8
|
+
def self.enqueue(job_type, attributes = [], options = {})
|
9
|
+
job_id = generate_job_id
|
10
|
+
|
11
|
+
job_queue = JobQueueFactory.build
|
12
|
+
job_queue.enqueue(job_type, job_id, attributes, options)
|
13
|
+
|
14
|
+
job_id
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
require 'background_jobs/job_factory'
|
3
|
+
require 'background_jobs/strategies/sidekiq/job_attributes_adapter'
|
4
|
+
|
5
|
+
module BackgroundJobs
|
6
|
+
module Sidekiq
|
7
|
+
class JobAdapter
|
8
|
+
include ::Sidekiq::Worker
|
9
|
+
|
10
|
+
def perform(*attrs)
|
11
|
+
job_type = attrs.shift
|
12
|
+
job_id = attrs.shift
|
13
|
+
attrs = JobAttributesAdapter.new(attrs).decode
|
14
|
+
|
15
|
+
job = JobFactory.build(job_type.to_sym, attrs)
|
16
|
+
job.id = job_id.to_i
|
17
|
+
job.execute
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module BackgroundJobs
|
2
|
+
module Sidekiq
|
3
|
+
class JobAttributesAdapter
|
4
|
+
def initialize(attributes)
|
5
|
+
@attributes = Attributes.new(attributes)
|
6
|
+
end
|
7
|
+
|
8
|
+
def encode
|
9
|
+
@attributes.encode
|
10
|
+
end
|
11
|
+
|
12
|
+
def decode
|
13
|
+
@attributes.decode
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Attributes < Array
|
18
|
+
def initialize(array)
|
19
|
+
super array.map {|attr| create_attribute(attr) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def encode
|
23
|
+
map(&:encode)
|
24
|
+
end
|
25
|
+
|
26
|
+
def decode
|
27
|
+
map(&:decode)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def create_attribute(attr)
|
33
|
+
AttributeFactory.build(attr)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class AttributeFactory
|
38
|
+
def self.build(value)
|
39
|
+
return HashAttribute.new(value) if value.kind_of?(Hash)
|
40
|
+
return ArrayAttribute.new(value) if value.kind_of?(Array)
|
41
|
+
return Attribute.new(value) unless value.kind_of?(String)
|
42
|
+
StringAttribute.new(value)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Attribute
|
47
|
+
def initialize(value)
|
48
|
+
@value = value
|
49
|
+
end
|
50
|
+
|
51
|
+
def decode
|
52
|
+
@value
|
53
|
+
end
|
54
|
+
|
55
|
+
def encode
|
56
|
+
case @value.class.name
|
57
|
+
when 'Date'
|
58
|
+
"date:#{@value.to_s}"
|
59
|
+
|
60
|
+
when 'Hash'
|
61
|
+
HashAttribute.new(@value).encode
|
62
|
+
|
63
|
+
when 'Array'
|
64
|
+
ArrayAttribute.new(@value).encode
|
65
|
+
|
66
|
+
when 'Range'
|
67
|
+
"range:[#{Attribute.new(@value.first).encode},#{Attribute.new(@value.last).encode}]"
|
68
|
+
|
69
|
+
else
|
70
|
+
@value
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class HashAttribute < Hash
|
76
|
+
def initialize(value)
|
77
|
+
@value = value
|
78
|
+
end
|
79
|
+
|
80
|
+
def encode
|
81
|
+
@value.keys.each do |key|
|
82
|
+
value = @value.delete(key)
|
83
|
+
@value[key.to_s] = AttributeFactory.build(value).encode
|
84
|
+
end
|
85
|
+
|
86
|
+
@value
|
87
|
+
end
|
88
|
+
|
89
|
+
def decode
|
90
|
+
@value.keys.each do |key|
|
91
|
+
@value[key.to_sym] = AttributeFactory.build(@value.delete(key)).decode
|
92
|
+
end
|
93
|
+
|
94
|
+
@value
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class ArrayAttribute < Array
|
99
|
+
def decode
|
100
|
+
map {|i| AttributeFactory.build(i).decode }
|
101
|
+
end
|
102
|
+
|
103
|
+
def encode
|
104
|
+
map {|i| AttributeFactory.build(i).encode }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
class StringAttribute < String
|
109
|
+
def decode
|
110
|
+
if number?
|
111
|
+
return to_i
|
112
|
+
end
|
113
|
+
|
114
|
+
if date?
|
115
|
+
return Date.parse(gsub('date:', ''))
|
116
|
+
end
|
117
|
+
|
118
|
+
if range?
|
119
|
+
matches = match(/range:\[(.*),(.*)\]/)
|
120
|
+
return AttributeFactory.build(matches[1]).decode..AttributeFactory.build(matches[2]).decode
|
121
|
+
end
|
122
|
+
|
123
|
+
self
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def number?
|
129
|
+
match(/^\d*$/)
|
130
|
+
end
|
131
|
+
|
132
|
+
def date?
|
133
|
+
match(/^date:.*$/)
|
134
|
+
end
|
135
|
+
|
136
|
+
def range?
|
137
|
+
match(/^range:\[(.*),(.*)\]$/)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|