delayed_job_sqs 0.1.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 +11 -0
- data/Gemfile +10 -0
- data/LICENSE +20 -0
- data/README.md +86 -0
- data/Rakefile +15 -0
- data/delayed_job_sqs.gemspec +25 -0
- data/lib/delayed/backend/actions.rb +70 -0
- data/lib/delayed/backend/sqs.rb +120 -0
- data/lib/delayed/backend/sqs_config.rb +3 -0
- data/lib/delayed/backend/version.rb +11 -0
- data/lib/delayed/backend/worker.rb +62 -0
- data/lib/delayed/serialization/sqs.rb +6 -0
- data/lib/delayed_job_sqs.rb +20 -0
- data/spec/.gitkeep +0 -0
- metadata +109 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 LeanDog, Inc. and other contributors
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
This is an [Amazon SQS](http://aws.amazon.com/sqs/) backend for [delayed_job](http://github.com/collectiveidea/delayed_job)
|
2
|
+
|
3
|
+
# Getting Started
|
4
|
+
|
5
|
+
## Get credentials
|
6
|
+
|
7
|
+
To start using delayed_job_sqs, you need to sign up for an AWS account and setup your credentials.
|
8
|
+
|
9
|
+
1. Go to https://portal.aws.amazon.com/gp/aws/developer/registration/index.html and sign up.
|
10
|
+
2. Get your AWS Access Key Id & Secret Access Key for your account.
|
11
|
+
3. Either `require 'aws-sdk'` and call `AWS.config()` prior to `require 'delayed_job_sqs'`, or create an aws.yml that will get loaded with your app. You will need to configure Delayed::Worker below to pass in the YAML file location:
|
12
|
+
|
13
|
+
```yaml
|
14
|
+
[aws]
|
15
|
+
access_key_id: <your access key>
|
16
|
+
secret_access_key: <your secret key>
|
17
|
+
```
|
18
|
+
|
19
|
+
Or if using Rails, create config/initializers/aws-sdk.rb and put the following into the file:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
AWS.config({
|
23
|
+
access_key_id: '<your access key>',
|
24
|
+
secret_access_key: '<your secret key>',
|
25
|
+
})
|
26
|
+
```
|
27
|
+
|
28
|
+
## Installation
|
29
|
+
|
30
|
+
Add the gems to your `Gemfile:`
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
gem 'delayed_job'
|
34
|
+
gem 'delayed_job_sqs'
|
35
|
+
```
|
36
|
+
|
37
|
+
Optionally: Add an initializer (`config/initializers/delayed_job.rb`):
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
Delayed::Worker.configure do |config|
|
41
|
+
# optional params:
|
42
|
+
config.aws_config = '~/stuff/things/aws.yml' # Specify the file location of the AWS configuration YAML if you're not using Rails and you want to use a YAML file instead of calling AWS.config
|
43
|
+
config.default_queue_name = 'default' # Specify an alternative default queue name
|
44
|
+
config.delay_seconds = # Sets the default delay in seconds for messages sent to the queue.
|
45
|
+
config.message_retention_period = 345600 # The number of seconds Amazon SQS retains a message. Must be an integer from 3600 (1 hour) to 1209600 (14 days). The default for this attribute is 345600 (4 days).
|
46
|
+
config.visibility_timeout = 30 # The length of time (in seconds) that a message received from a queue will be invisible to other receiving components when they ask to receive messages. Valid values: integers from 0 to 43200 (12 hours).
|
47
|
+
config.wait_time_seconds = # How many seconds to wait for a response
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
## Usage
|
52
|
+
|
53
|
+
That's it. Use [delayed_job as normal](http://github.com/collectiveidea/delayed_job).
|
54
|
+
|
55
|
+
Example:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
class User
|
59
|
+
def background_stuff
|
60
|
+
puts "I run in the background"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
Then in one of your controllers:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
user = User.new
|
69
|
+
user.delay.background_stuff
|
70
|
+
```
|
71
|
+
|
72
|
+
## Start worker process
|
73
|
+
|
74
|
+
rake jobs:work
|
75
|
+
|
76
|
+
If you want to process a specific queue that's not in your initializer or called `default`, use the `QUEUE` or `QUEUES` environment variable:
|
77
|
+
|
78
|
+
QUEUE=tracking rake jobs:work
|
79
|
+
|
80
|
+
That will start pulling jobs off the default queue and processing them. The gem will also handle multiple named queues if you have configured `rake` or `scripts/delayed_job` accordingly however be sure to name the queue when putting objects on the queue:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
user = User.new
|
84
|
+
user.delay(queue: 'bestest_queue').background_stuff
|
85
|
+
```
|
86
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
|
6
|
+
begin
|
7
|
+
Bundler.setup(:default, :development)
|
8
|
+
rescue Bundler::BundlerError => e
|
9
|
+
$stderr.puts e.message
|
10
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
11
|
+
exit e.status_code
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'rake'
|
15
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'delayed/backend/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.require_paths = ["lib"]
|
8
|
+
s.name = "delayed_job_sqs"
|
9
|
+
s.version = Delayed::Backend::Sqs.version
|
10
|
+
s.authors = ["Eric Hankinson"]
|
11
|
+
s.email = ["eric.hankinson@gmail.com"]
|
12
|
+
s.description = "Amazon SQS backend for delayed_job"
|
13
|
+
s.summary = "Amazon SQS backend for delayed_job"
|
14
|
+
s.homepage = "https://github.com/kumichou/delayed_job_sqs"
|
15
|
+
s.license = "MIT"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split($/)
|
18
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
19
|
+
|
20
|
+
s.add_dependency("aws-sdk", "1.11.1")
|
21
|
+
s.add_dependency("delayed_job", ">= 3.0.0")
|
22
|
+
|
23
|
+
s.add_development_dependency "rspec"
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Delayed
|
2
|
+
module Backend
|
3
|
+
module Sqs
|
4
|
+
module Actions
|
5
|
+
def field(name, options = {})
|
6
|
+
default = options[:default] || nil
|
7
|
+
define_method name do
|
8
|
+
@attributes ||= {}
|
9
|
+
@attributes[name.to_sym] || default
|
10
|
+
end
|
11
|
+
|
12
|
+
define_method "#{name}=" do |value|
|
13
|
+
@attributes ||= {}
|
14
|
+
@attributes[name.to_sym] = value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def before_fork
|
19
|
+
end
|
20
|
+
|
21
|
+
def after_fork
|
22
|
+
end
|
23
|
+
|
24
|
+
def db_time_now
|
25
|
+
Time.now.utc
|
26
|
+
end
|
27
|
+
|
28
|
+
def find_available(worker_name, limit = 5, max_run_time = Worker.max_run_time)
|
29
|
+
Delayed::Worker.queues.each_with_index do |queue, index|
|
30
|
+
message = sqs.queues.named(queue_name(index)).receive_message
|
31
|
+
return [Delayed::Backend::Sqs::Job.new(message)] if message
|
32
|
+
end
|
33
|
+
[]
|
34
|
+
end
|
35
|
+
|
36
|
+
def delete_all
|
37
|
+
deleted = 0
|
38
|
+
|
39
|
+
Delayed::Worker.queues.each_with_index do |queue, index|
|
40
|
+
loop do
|
41
|
+
msgs = sqs.queues.named(queue_name(index)).receive_message({ :limit => 10})
|
42
|
+
break if msgs.blank?
|
43
|
+
msgs.each do |msg|
|
44
|
+
msg.delete
|
45
|
+
deleted += 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
puts "Messages removed: #{deleted}"
|
51
|
+
end
|
52
|
+
|
53
|
+
# No need to check locks
|
54
|
+
def clear_locks!(*args)
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def sqs
|
61
|
+
::Delayed::Worker.sqs
|
62
|
+
end
|
63
|
+
|
64
|
+
def queue_name(index)
|
65
|
+
Delayed::Worker.queues[index]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
|
2
|
+
module Delayed
|
3
|
+
module Backend
|
4
|
+
module Sqs
|
5
|
+
class Job
|
6
|
+
include ::DelayedJobSqs::Document
|
7
|
+
include Delayed::Backend::Base
|
8
|
+
extend Delayed::Backend::Sqs::Actions
|
9
|
+
|
10
|
+
field :priority, :type => Integer, :default => 0
|
11
|
+
field :attempts, :type => Integer, :default => 0
|
12
|
+
field :handler, :type => String
|
13
|
+
field :run_at, :type => Time
|
14
|
+
field :locked_at, :type => Time
|
15
|
+
field :locked_by, :type => String
|
16
|
+
field :failed_at, :type => Time
|
17
|
+
field :last_error, :type => String
|
18
|
+
field :queue, :type => String
|
19
|
+
|
20
|
+
def initialize(data = {})
|
21
|
+
puts "[init] Delayed::Backend::Sqs"
|
22
|
+
@msg = nil
|
23
|
+
|
24
|
+
if data.is_a?(AWS::SQS::ReceivedMessage)
|
25
|
+
@msg = data
|
26
|
+
data = JSON.load(data.body)
|
27
|
+
end
|
28
|
+
|
29
|
+
data.symbolize_keys!
|
30
|
+
payload_obj = data.delete(:payload_object) || data.delete(:handler)
|
31
|
+
|
32
|
+
@queue_name = data[:queue] || Delayed::Worker.default_queue_name
|
33
|
+
@delay = data[:delay] || Delayed::Worker.delay
|
34
|
+
@timeout = data[:timeout] || Delayed::Worker.timeout
|
35
|
+
@expires_in = data[:expires_in] || Delayed::Worker.expires_in
|
36
|
+
@attributes = data
|
37
|
+
self.payload_object = payload_obj
|
38
|
+
end
|
39
|
+
|
40
|
+
def payload_object
|
41
|
+
@payload_object ||= YAML.load(self.handler)
|
42
|
+
rescue TypeError, LoadError, NameError, ArgumentError => e
|
43
|
+
raise DeserializationError,
|
44
|
+
"Job failed to load: #{e.message}. Handler: #{handler.inspect}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def payload_object=(object)
|
48
|
+
if object.is_a? String
|
49
|
+
@payload_object = YAML.load(object)
|
50
|
+
self.handler = object
|
51
|
+
else
|
52
|
+
@payload_object = object
|
53
|
+
self.handler = object.to_yaml
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def save
|
58
|
+
puts "[SAVE] #{@attributes.inspect}"
|
59
|
+
|
60
|
+
if @attributes[:handler].blank?
|
61
|
+
raise "Handler missing!"
|
62
|
+
end
|
63
|
+
payload = JSON.dump(@attributes)
|
64
|
+
|
65
|
+
@msg.delete if @msg
|
66
|
+
|
67
|
+
sqs.queues.named(queue_name).send_message(payload, :delay_seconds => @delay)
|
68
|
+
true
|
69
|
+
end
|
70
|
+
|
71
|
+
def save!
|
72
|
+
save
|
73
|
+
end
|
74
|
+
|
75
|
+
def destroy
|
76
|
+
if @msg
|
77
|
+
puts "job destroyed! #{@msg.id}"
|
78
|
+
@msg.delete
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def fail!
|
83
|
+
destroy
|
84
|
+
# v2: move to separate queue
|
85
|
+
end
|
86
|
+
|
87
|
+
def update_attributes(attributes)
|
88
|
+
attributes.symbolize_keys!
|
89
|
+
@attributes.merge attributes
|
90
|
+
save
|
91
|
+
end
|
92
|
+
|
93
|
+
# No need to check locks
|
94
|
+
def lock_exclusively!(*args)
|
95
|
+
true
|
96
|
+
end
|
97
|
+
|
98
|
+
# No need to check locks
|
99
|
+
def unlock(*args)
|
100
|
+
true
|
101
|
+
end
|
102
|
+
|
103
|
+
def reload(*args)
|
104
|
+
# reset
|
105
|
+
super
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def queue_name
|
111
|
+
@queue_name
|
112
|
+
end
|
113
|
+
|
114
|
+
def sqs
|
115
|
+
::Delayed::Worker.sqs
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require_relative 'sqs_config'
|
2
|
+
|
3
|
+
module Delayed
|
4
|
+
class Worker
|
5
|
+
|
6
|
+
class << self
|
7
|
+
attr_accessor :config, :sqs, :delay, :timeout, :expires_in, :aws_config
|
8
|
+
|
9
|
+
def configure
|
10
|
+
yield(config)
|
11
|
+
|
12
|
+
self.default_queue_name = if !config.default_queue_name.nil? && config.default_queue_name.length != 0
|
13
|
+
config.default_queue_name
|
14
|
+
else
|
15
|
+
'default'
|
16
|
+
end
|
17
|
+
self.delay = config.delay_seconds || 0
|
18
|
+
self.timeout = config.visibility_timeout || 5.minutes
|
19
|
+
self.expires_in = config.message_retention_period || 4.days
|
20
|
+
end
|
21
|
+
|
22
|
+
def config
|
23
|
+
@config ||= SqsConfig.new
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module Backend
|
29
|
+
module Sqs
|
30
|
+
if Object.const_defined?(:Rails) and Rails.const_defined?(:Railtie)
|
31
|
+
class Railtie < Rails::Railtie
|
32
|
+
|
33
|
+
# configure our gem after Rails completely boots so that we have
|
34
|
+
# access to any config/initializers that were run
|
35
|
+
config.after_initialize do
|
36
|
+
AWS::Rails.setup
|
37
|
+
|
38
|
+
Delayed::Worker.sqs = AWS::SQS.new
|
39
|
+
Delayed::Worker.configure {}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
else
|
43
|
+
path = Pathname.new(Delayed::Worker.config.aws_config)
|
44
|
+
|
45
|
+
if File.exists?(path)
|
46
|
+
cfg = YAML::load(File.read(path))
|
47
|
+
|
48
|
+
unless cfg.keys[0]
|
49
|
+
raise "AWS Yaml configuration file is missing a section"
|
50
|
+
end
|
51
|
+
|
52
|
+
AWS.config(cfg.keys[0])
|
53
|
+
end
|
54
|
+
|
55
|
+
Delayed::Worker.sqs = AWS::SQS.new
|
56
|
+
Delayed::Worker.configure {}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'aws-sdk'
|
3
|
+
require 'delayed_job'
|
4
|
+
require 'active_support'
|
5
|
+
|
6
|
+
module ActiveSupport
|
7
|
+
Inflector.inflections do |inflect|
|
8
|
+
inflect.irregular('sqs', 'sqs')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
require_relative 'delayed/serialization/sqs'
|
13
|
+
require_relative 'delayed/backend/actions'
|
14
|
+
require_relative 'delayed/backend/sqs_config'
|
15
|
+
require_relative 'delayed/backend/worker'
|
16
|
+
require_relative 'delayed/backend/version'
|
17
|
+
require_relative 'delayed/backend/sqs'
|
18
|
+
|
19
|
+
Delayed::Worker.backend = :sqs
|
20
|
+
|
data/spec/.gitkeep
ADDED
File without changes
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: delayed_job_sqs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Eric Hankinson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-07-22 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: aws-sdk
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - '='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.11.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - '='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.11.1
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: delayed_job
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 3.0.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 3.0.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: Amazon SQS backend for delayed_job
|
63
|
+
email:
|
64
|
+
- eric.hankinson@gmail.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- Gemfile
|
71
|
+
- LICENSE
|
72
|
+
- README.md
|
73
|
+
- Rakefile
|
74
|
+
- delayed_job_sqs.gemspec
|
75
|
+
- lib/delayed/backend/actions.rb
|
76
|
+
- lib/delayed/backend/sqs.rb
|
77
|
+
- lib/delayed/backend/sqs_config.rb
|
78
|
+
- lib/delayed/backend/version.rb
|
79
|
+
- lib/delayed/backend/worker.rb
|
80
|
+
- lib/delayed/serialization/sqs.rb
|
81
|
+
- lib/delayed_job_sqs.rb
|
82
|
+
- spec/.gitkeep
|
83
|
+
homepage: https://github.com/kumichou/delayed_job_sqs
|
84
|
+
licenses:
|
85
|
+
- MIT
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ! '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
requirements: []
|
103
|
+
rubyforge_project:
|
104
|
+
rubygems_version: 1.8.25
|
105
|
+
signing_key:
|
106
|
+
specification_version: 3
|
107
|
+
summary: Amazon SQS backend for delayed_job
|
108
|
+
test_files:
|
109
|
+
- spec/.gitkeep
|