langrove-plugin-resque 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,78 @@
1
+ `Plugin::Resque`
2
+ =================
3
+
4
+ Intergates Resque support into LanGrove.</ br>
5
+
6
+
7
+ `gem install langrove-plugin-resque`
8
+
9
+ Implements
10
+ ----------
11
+
12
+ * `Adaptor::ResqueWorker`
13
+ * `Handler::ResqueJob`
14
+ * `Plugin::ResqueQue`
15
+
16
+
17
+ Supports
18
+ ---------
19
+
20
+ * `LanGrove::Adaptor`
21
+ * `LanGrove::Behaviour::Deferrable`
22
+
23
+
24
+ Examples
25
+ --------
26
+
27
+ ### Configure to post jobs onto a queue.
28
+
29
+ <pre>
30
+
31
+ ...
32
+
33
+ :plugins:
34
+ :a_job_queue:
35
+ :class: ResqueQue
36
+ :job: JobName
37
+ :queue: job_name
38
+
39
+ ...
40
+
41
+ :server:
42
+ :behavior:
43
+ :deferrable:
44
+ :plugin: :a_job_queue
45
+ :at:
46
+ :handler_after_receive: :defer_capsule
47
+ #
48
+ # will post the caspsule as payload
49
+ # onto the specified resque queue
50
+ # after the Handler.receive( data )
51
+ # method returns.
52
+ #
53
+
54
+ ...
55
+
56
+ </pre>
57
+
58
+ ### Configure to perform jobs on a queue.
59
+
60
+ <pre>
61
+
62
+ ...
63
+
64
+ :adaptor:
65
+ :class: ResqueAdaptor
66
+ :queue: job_name
67
+
68
+ ...
69
+
70
+ :handler:
71
+ :class: JobName
72
+ #
73
+ # Should extend Handler::ResqueJob
74
+ #
75
+
76
+ ...
77
+
78
+ </pre>
@@ -0,0 +1,95 @@
1
+ module Resque
2
+
3
+ class Worker
4
+
5
+ #
6
+ # Alias the shutdown! as called on the INT and TERM
7
+ # traps that Resque assigned,
8
+ #
9
+ # So that the surrounding Daemon can also receive the
10
+ # instruction to stop.
11
+ #
12
+ #
13
+ alias_method :resque_shutdown!, :shutdown!
14
+
15
+ def shutdown!
16
+
17
+ #
18
+ # Call the original Worker shutdown!
19
+ # And further raise the instruction to stop.
20
+ #
21
+
22
+ resque_shutdown!
23
+
24
+ raise LanGrove::DaemonStopException.new
25
+
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+
32
+ module Adaptor
33
+
34
+ class ResqueAdaptor < LanGrove::Adaptor::Base
35
+
36
+ def initialize( root, config, deamon_name )
37
+
38
+ super
39
+
40
+ @type = :resque_adaptor
41
+
42
+ raise config_exception(
43
+
44
+ "#{self.class} requires :queue:"
45
+
46
+ ) if (
47
+
48
+ config.nil? or
49
+
50
+ not config.has_key?( :queue ) or
51
+ not @queue = config[ :queue ] or
52
+ @queue == ''
53
+
54
+ )
55
+
56
+ end
57
+
58
+ def connector( params, &block )
59
+
60
+ #
61
+ # This yields Resque::Job(s),
62
+ # one at a time,
63
+ # into the caller.
64
+ #
65
+
66
+ wait_for_job( @queue, &block )
67
+
68
+ end
69
+
70
+ private
71
+
72
+ def wait_for_job( queue, &block )
73
+
74
+ worker = Resque::Worker.new( queue )
75
+
76
+ worker.work do |job_spec|
77
+
78
+ new_job = job_spec.payload_class.new
79
+
80
+ new_job.payload = job_spec.payload
81
+
82
+ #
83
+ # Job is yielded up the assignment pipeline to
84
+ # get access to all the local infrastructure.
85
+ #
86
+
87
+ yield new_job
88
+
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+
95
+ end
@@ -0,0 +1,102 @@
1
+ module Handler
2
+
3
+ class ResqueJob < LanGrove::Handler::Base
4
+
5
+ attr_accessor :payload
6
+
7
+ def start_handler
8
+
9
+ #
10
+ # Trigger the handler_start event
11
+ #
12
+ @root.trigger( self, :handler, :start )
13
+
14
+ #
15
+ # The job payload header may define an :action
16
+ # to perform,
17
+ #
18
+ unless payload['args'][0]['action'].nil?
19
+
20
+ unless self.respond_to?( payload['args'][0]['action'].to_sym )
21
+
22
+ #
23
+ # local handler does not define that action
24
+ # bring the house down
25
+ #
26
+ raise LanGrove::DaemonConfigException(
27
+
28
+ "#{self.class}.#{payload[0]['action']}() not defined. Required by payload header: #{payload[0].inspect} "
29
+
30
+ )
31
+
32
+ end
33
+
34
+ #
35
+ # Should the header :action return false,
36
+ #
37
+ unless self.send( payload['args'][0]['action'].to_sym )
38
+
39
+ #
40
+ # Then the job will be skipped.
41
+ #
42
+ @logger.debug "#{self.class} job SKIPPED"
43
+
44
+ return
45
+
46
+ end
47
+
48
+ end
49
+
50
+
51
+ #
52
+ # Call implementor overridable start
53
+ #
54
+ start
55
+
56
+ do_work
57
+
58
+
59
+ #
60
+ # Job was sent up the same assignment pipeline as
61
+ # socket handler,
62
+ #
63
+ # It has therefore been assigned into the server's
64
+ # @client collection
65
+ #
66
+ # It needs to be removed
67
+ #
68
+ I.notify( @logger, "need to disconnect from server here", [:vital] )
69
+ #
70
+ #
71
+ #
72
+
73
+ stop
74
+
75
+ end
76
+
77
+
78
+ def stop_handler
79
+
80
+ @root.trigger( self, :handler, :stop )
81
+
82
+ stop
83
+
84
+ end
85
+
86
+
87
+ def self.perform( *args )
88
+
89
+ #
90
+ # Does not do the job, serves only to collect
91
+ # the payload and yield into the local runtime
92
+ # via the ResqueAdaptor,
93
+ #
94
+ # Requeue jobs are marked as failed unless this
95
+ # is present.
96
+ #
97
+
98
+ end
99
+
100
+ end
101
+
102
+ end
@@ -0,0 +1,4 @@
1
+ require 'langrove' unless defined?( LanGrove )
2
+ require 'adaptor/resque_adaptor'
3
+ require 'plugin/resque_que'
4
+ require 'handler/resque_job'
@@ -0,0 +1,130 @@
1
+
2
+ #
3
+ # brew install redis
4
+ # - For the queue db
5
+ #
6
+ # bundler installed resque
7
+ # (per the Gemfile)
8
+ #
9
+ # resque-web
10
+ # - Starts a queue stats interface at http://localhost:5678/
11
+ #
12
+
13
+ module Plugin
14
+
15
+ class ResqueQue < LanGrove::Plugin::Deferrer
16
+
17
+ def validate_config
18
+
19
+ super
20
+
21
+ config_exception(
22
+
23
+ "#{self.class} requires :queue: defined"
24
+
25
+ ) if @config[:queue].nil? or @config[:queue] == ''
26
+
27
+ queue = @config[:queue]
28
+
29
+
30
+ #
31
+ # Dynamically define job class
32
+ #
33
+ # - Resque wants a class with @queue
34
+ # defined
35
+ # - Make one to give
36
+ #
37
+
38
+ @job_class = Object.const_set( @job,
39
+
40
+ Class.new do
41
+
42
+ self.instance_variable_set(
43
+
44
+ :@queue, queue
45
+
46
+ )
47
+
48
+ end
49
+
50
+ )
51
+
52
+ end
53
+
54
+
55
+ def defer_key( handler )
56
+
57
+ #
58
+ # Enqueue job with the handler.key
59
+ #
60
+
61
+ return enqueue(
62
+
63
+ queue_header( :get_capsule, handler ),
64
+
65
+ handler.key
66
+
67
+ )
68
+
69
+ end
70
+
71
+ def defer_capsule( handler )
72
+
73
+ #
74
+ # Enqueue job with the handler.capsule
75
+ #
76
+
77
+ return enqueue(
78
+
79
+ queue_header( :load_capsule, handler ),
80
+
81
+ handler.capsule
82
+
83
+ )
84
+
85
+ end
86
+
87
+ private
88
+
89
+ def enqueue( header, payload )
90
+
91
+ begin
92
+
93
+ Resque.enqueue(
94
+
95
+ @job_class,
96
+
97
+ header,
98
+
99
+ payload
100
+
101
+ )
102
+
103
+ @logger.debug(
104
+
105
+ "#{self.class}.enqueue():#{type} job:#{@job_class} parameter:#{payload.inspect}"
106
+
107
+ )
108
+
109
+ return true
110
+
111
+ rescue Exception => e
112
+
113
+ error =
114
+
115
+ "#{self.class} failed to enqueue: #{header},#{payload} as #{type}, Exception #{e}"
116
+
117
+ @logger.error( error )
118
+
119
+ #
120
+ # The daemon needs to fall over.
121
+ #
122
+ raise e
123
+
124
+ end
125
+
126
+ end
127
+
128
+ end
129
+
130
+ end
@@ -0,0 +1,152 @@
1
+ require 'langrove-plugin-resque'
2
+
3
+ describe Adaptor::ResqueAdaptor do
4
+
5
+ before :all do
6
+
7
+ class FakeJob < Handler::ResqueJob
8
+
9
+ end
10
+
11
+ ROOT = LanGrove::FakeRoot.new
12
+
13
+ end
14
+
15
+
16
+ before :each do
17
+
18
+ @queue_name = :queue_name
19
+
20
+ @config = {
21
+
22
+ :queue => @queue_name
23
+
24
+ }
25
+
26
+ @connect_spec = {
27
+
28
+ :handler => {
29
+
30
+ :class => Handler::ResqueJob,
31
+
32
+ :config => {}
33
+
34
+ }
35
+
36
+ }
37
+
38
+ end
39
+
40
+ subject {
41
+
42
+ Adaptor::ResqueAdaptor.new(
43
+
44
+ ROOT, @config , nil
45
+
46
+ )
47
+
48
+ }
49
+
50
+ it 'raises on missing queue name' do
51
+
52
+ expect {
53
+
54
+ Adaptor::ResqueAdaptor.new(
55
+
56
+ ROOT, { :queue => '' }, nil
57
+
58
+ )
59
+
60
+ }.to raise_error(
61
+
62
+ LanGrove::DaemonConfigException,
63
+
64
+ "Adaptor::ResqueAdaptor requires :queue:"
65
+
66
+ )
67
+
68
+ end
69
+
70
+ context 'uses requeue to' do
71
+
72
+ before :each do
73
+
74
+ @parameters = {
75
+
76
+ :handler => {
77
+
78
+ :class => 'FakeJob'
79
+
80
+ }
81
+
82
+ }
83
+
84
+ #
85
+ # Mock the resque infrastructure
86
+ #
87
+
88
+ @worker = mock( 'Resque::Worker' )
89
+
90
+ @job = mock( 'Job' )
91
+
92
+ @payload = {}
93
+
94
+ Resque::Worker.should_receive(
95
+
96
+ :new
97
+
98
+ ).and_return(
99
+
100
+ @worker
101
+
102
+ )
103
+
104
+ @worker.should_receive(
105
+
106
+ :work
107
+
108
+ ).and_yield(
109
+
110
+ @job
111
+
112
+ )
113
+
114
+ @job.should_receive(
115
+
116
+ :payload_class
117
+
118
+ ).and_return(
119
+
120
+ FakeJob
121
+
122
+ )
123
+
124
+ @job.should_receive(
125
+
126
+ :payload
127
+
128
+ ).and_return(
129
+
130
+ @payload
131
+
132
+ )
133
+
134
+ end
135
+
136
+ it 'yields jobs' do
137
+
138
+ job = nil
139
+
140
+ subject.connector( @parameters ) do |new_job|
141
+
142
+ job = new_job
143
+
144
+ end
145
+
146
+ job.should be_a( FakeJob )
147
+
148
+ end
149
+
150
+ end
151
+
152
+ end
@@ -0,0 +1,32 @@
1
+ require 'langrove-plugin-resque'
2
+
3
+ describe Handler::ResqueJob do
4
+
5
+ before :each do
6
+
7
+ @queue_name = :queue_name
8
+
9
+ @job_parameter = {
10
+
11
+ :the => 'originally',
12
+ :enqueued => 'payload'
13
+
14
+ }
15
+
16
+ end
17
+
18
+ subject {
19
+
20
+ worker = Handler::ResqueJob.new
21
+
22
+ worker.instance_variable_set(
23
+
24
+ :@root, ROOT
25
+
26
+ )
27
+
28
+ worker
29
+
30
+ }
31
+
32
+ end
@@ -0,0 +1,118 @@
1
+ require 'langrove-plugin-resque'
2
+
3
+ describe 'Plugin::ResqueQue' do
4
+
5
+ before :each do
6
+
7
+ ROOT = LanGrove::FakeRoot.new
8
+
9
+ RESQUE_DEFERRER = {
10
+
11
+ :class => 'ResqueQue',
12
+ :job => 'ResqueWorker',
13
+ :queue => :resque_queue
14
+
15
+ }
16
+
17
+ @capsule = { :stamp => 'STAMP', :data => '' }
18
+
19
+ end
20
+
21
+ subject {
22
+
23
+ LanGrove::ClassLoader.create( {
24
+
25
+ :module => 'Plugin',
26
+ :class => 'ResqueQue'
27
+
28
+ } ).new( ROOT, RESQUE_DEFERRER, nil )
29
+
30
+ }
31
+
32
+ it 'can enqueue the capsule key' do
33
+
34
+ subject.validate_config
35
+
36
+ handler = mock( 'handler' )
37
+
38
+ handler.should_receive(
39
+
40
+ :key
41
+
42
+ ).and_return(
43
+
44
+ 'THE_KEY'
45
+
46
+ )
47
+
48
+ handler.should_receive(
49
+
50
+ :capsule
51
+
52
+ ).and_return(
53
+
54
+ @capsule
55
+
56
+ )
57
+
58
+ Resque.should_receive(
59
+
60
+ :enqueue
61
+
62
+ ).with(
63
+
64
+ Object.const_get(
65
+
66
+ RESQUE_DEFERRER[:job]
67
+
68
+ ),
69
+
70
+ anything(),
71
+
72
+ "THE_KEY"
73
+
74
+ )
75
+
76
+ subject.defer_key( handler )
77
+
78
+ end
79
+
80
+ it 'can enqueue the capsule data' do
81
+
82
+ subject.validate_config
83
+
84
+ handler = mock( 'handler' )
85
+
86
+ handler.should_receive(
87
+
88
+ :capsule
89
+
90
+ ).twice.and_return(
91
+
92
+ @capsule
93
+
94
+ )
95
+
96
+ Resque.should_receive(
97
+
98
+ :enqueue
99
+
100
+ ).with(
101
+
102
+ Object.const_get(
103
+
104
+ RESQUE_DEFERRER[:job]
105
+
106
+ ),
107
+
108
+ anything(),
109
+
110
+ @capsule
111
+
112
+ )
113
+
114
+ subject.defer_capsule( handler )
115
+
116
+ end
117
+
118
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: langrove-plugin-resque
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.9
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Richard
9
+ - ''
10
+ - ''
11
+ - ''
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+ date: 2012-07-09 00:00:00.000000000 Z
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: langrove
19
+ requirement: !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ! '>='
23
+ - !ruby/object:Gem::Version
24
+ version: '0'
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: resque
35
+ requirement: !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ type: :runtime
42
+ prerelease: false
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ description: ''
50
+ email: ops@clue.co.za
51
+ executables: []
52
+ extensions: []
53
+ extra_rdoc_files: []
54
+ files:
55
+ - lib/adaptor/resque_adaptor.rb
56
+ - lib/handler/resque_job.rb
57
+ - lib/plugin/resque_que.rb
58
+ - spec/adaptor/resque_adaptor_spec.rb
59
+ - spec/handler/resque_job_spec.rb
60
+ - spec/plugin/resque_que_spec.rb
61
+ - lib/langrove-plugin-resque.rb
62
+ - README.md
63
+ homepage: ''
64
+ licenses: []
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 1.8.24
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Intergates Resque support into LanGrove
87
+ test_files: []