creeper 1.0.9 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. data/.gitignore +1 -0
  2. data/.rvmrc +48 -0
  3. data/Gemfile +17 -1
  4. data/Guardfile +32 -0
  5. data/Rakefile +9 -1
  6. data/bin/creeper +10 -58
  7. data/bin/creeperctl +74 -0
  8. data/config.ru +18 -0
  9. data/creeper.gemspec +19 -9
  10. data/lib/creeper.rb +108 -413
  11. data/lib/creeper/beanstalk_connection.rb +35 -0
  12. data/lib/creeper/cli.rb +225 -0
  13. data/lib/creeper/client.rb +93 -0
  14. data/lib/creeper/core_ext.rb +54 -0
  15. data/lib/creeper/exception_handler.rb +30 -0
  16. data/lib/creeper/extensions/action_mailer.rb +33 -0
  17. data/lib/creeper/extensions/active_record.rb +30 -0
  18. data/lib/creeper/extensions/generic_proxy.rb +26 -0
  19. data/lib/creeper/fetch.rb +94 -0
  20. data/lib/creeper/legacy.rb +46 -0
  21. data/lib/creeper/logging.rb +46 -0
  22. data/lib/creeper/manager.rb +164 -0
  23. data/lib/creeper/middleware/chain.rb +100 -0
  24. data/lib/creeper/middleware/server/active_record.rb +13 -0
  25. data/lib/creeper/middleware/server/logging.rb +31 -0
  26. data/lib/creeper/middleware/server/retry_jobs.rb +79 -0
  27. data/lib/creeper/middleware/server/timeout.rb +21 -0
  28. data/lib/creeper/paginator.rb +31 -0
  29. data/lib/creeper/processor.rb +116 -0
  30. data/lib/creeper/rails.rb +21 -0
  31. data/lib/creeper/redis_connection.rb +28 -0
  32. data/lib/creeper/testing.rb +44 -0
  33. data/lib/creeper/util.rb +45 -0
  34. data/lib/creeper/version.rb +1 -1
  35. data/lib/creeper/web.rb +248 -0
  36. data/lib/creeper/worker.rb +62 -313
  37. data/spec/dummy/.gitignore +15 -0
  38. data/spec/dummy/Gemfile +51 -0
  39. data/spec/dummy/README.rdoc +261 -0
  40. data/spec/dummy/Rakefile +7 -0
  41. data/spec/dummy/app/assets/images/rails.png +0 -0
  42. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  43. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  44. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  45. data/spec/dummy/app/controllers/work_controller.rb +71 -0
  46. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  47. data/spec/dummy/app/mailers/.gitkeep +0 -0
  48. data/spec/dummy/app/mailers/user_mailer.rb +9 -0
  49. data/spec/dummy/app/models/.gitkeep +0 -0
  50. data/spec/dummy/app/models/post.rb +8 -0
  51. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  52. data/spec/dummy/app/views/user_mailer/greetings.html.erb +3 -0
  53. data/spec/dummy/app/views/work/index.html.erb +1 -0
  54. data/spec/dummy/app/workers/fast_worker.rb +10 -0
  55. data/spec/dummy/app/workers/hard_worker.rb +11 -0
  56. data/spec/dummy/app/workers/lazy_worker.rb +12 -0
  57. data/spec/dummy/app/workers/suicidal_worker.rb +33 -0
  58. data/spec/dummy/config.ru +4 -0
  59. data/spec/dummy/config/application.rb +68 -0
  60. data/spec/dummy/config/boot.rb +6 -0
  61. data/spec/dummy/config/creeper.yml +9 -0
  62. data/spec/dummy/config/database.yml +25 -0
  63. data/spec/dummy/config/environment.rb +5 -0
  64. data/spec/dummy/config/environments/development.rb +37 -0
  65. data/spec/dummy/config/environments/production.rb +67 -0
  66. data/spec/dummy/config/environments/test.rb +37 -0
  67. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  68. data/spec/dummy/config/initializers/creeper.rb +8 -0
  69. data/spec/dummy/config/initializers/inflections.rb +15 -0
  70. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  71. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  72. data/spec/dummy/config/initializers/session_store.rb +8 -0
  73. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  74. data/spec/dummy/config/locales/en.yml +5 -0
  75. data/spec/dummy/config/routes.rb +13 -0
  76. data/spec/dummy/db/migrate/20120123214055_create_posts.rb +10 -0
  77. data/spec/dummy/db/schema.rb +23 -0
  78. data/spec/dummy/db/seeds.rb +7 -0
  79. data/spec/dummy/lib/assets/.gitkeep +0 -0
  80. data/spec/dummy/lib/tasks/.gitkeep +0 -0
  81. data/spec/dummy/log/.gitkeep +0 -0
  82. data/spec/dummy/public/404.html +26 -0
  83. data/spec/dummy/public/422.html +26 -0
  84. data/spec/dummy/public/500.html +25 -0
  85. data/spec/dummy/public/favicon.ico +0 -0
  86. data/spec/dummy/public/index.html +241 -0
  87. data/spec/dummy/public/robots.txt +5 -0
  88. data/spec/dummy/script/rails +6 -0
  89. data/spec/dummy/vendor/assets/javascripts/.gitkeep +0 -0
  90. data/spec/dummy/vendor/assets/stylesheets/.gitkeep +0 -0
  91. data/spec/dummy/vendor/plugins/.gitkeep +0 -0
  92. data/spec/lib/creeper/cli_spec.rb +208 -0
  93. data/spec/lib/creeper/client_spec.rb +110 -0
  94. data/spec/lib/creeper/exception_handler_spec.rb +110 -0
  95. data/spec/lib/creeper/processor_spec.rb +92 -0
  96. data/spec/lib/creeper/testing_spec.rb +105 -0
  97. data/spec/lib/creeper_spec.rb +54 -120
  98. data/spec/spec_helper.rb +81 -7
  99. data/spec/support/config.yml +9 -0
  100. data/spec/support/fake_env.rb +0 -0
  101. data/spec/support/workers/base_worker.rb +11 -0
  102. data/spec/support/workers/my_worker.rb +4 -0
  103. data/spec/support/workers/queued_worker.rb +5 -0
  104. data/spec/support/workers/real_worker.rb +10 -0
  105. data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
  106. data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
  107. data/web/assets/javascripts/application.js +49 -0
  108. data/web/assets/javascripts/vendor/bootstrap.js +12 -0
  109. data/web/assets/javascripts/vendor/bootstrap/bootstrap-alert.js +91 -0
  110. data/web/assets/javascripts/vendor/bootstrap/bootstrap-button.js +98 -0
  111. data/web/assets/javascripts/vendor/bootstrap/bootstrap-carousel.js +154 -0
  112. data/web/assets/javascripts/vendor/bootstrap/bootstrap-collapse.js +136 -0
  113. data/web/assets/javascripts/vendor/bootstrap/bootstrap-dropdown.js +92 -0
  114. data/web/assets/javascripts/vendor/bootstrap/bootstrap-modal.js +210 -0
  115. data/web/assets/javascripts/vendor/bootstrap/bootstrap-popover.js +95 -0
  116. data/web/assets/javascripts/vendor/bootstrap/bootstrap-scrollspy.js +125 -0
  117. data/web/assets/javascripts/vendor/bootstrap/bootstrap-tab.js +130 -0
  118. data/web/assets/javascripts/vendor/bootstrap/bootstrap-tooltip.js +270 -0
  119. data/web/assets/javascripts/vendor/bootstrap/bootstrap-transition.js +51 -0
  120. data/web/assets/javascripts/vendor/bootstrap/bootstrap-typeahead.js +271 -0
  121. data/web/assets/javascripts/vendor/jquery.js +9266 -0
  122. data/web/assets/javascripts/vendor/jquery.timeago.js +148 -0
  123. data/web/assets/stylesheets/application.css +6 -0
  124. data/web/assets/stylesheets/layout.css +26 -0
  125. data/web/assets/stylesheets/vendor/bootstrap-responsive.css +567 -0
  126. data/web/assets/stylesheets/vendor/bootstrap.css +3365 -0
  127. data/web/views/_paging.slim +15 -0
  128. data/web/views/_summary.slim +9 -0
  129. data/web/views/_workers.slim +14 -0
  130. data/web/views/index.slim +10 -0
  131. data/web/views/layout.slim +37 -0
  132. data/web/views/poll.slim +3 -0
  133. data/web/views/queue.slim +15 -0
  134. data/web/views/queues.slim +19 -0
  135. data/web/views/retries.slim +31 -0
  136. data/web/views/retry.slim +52 -0
  137. data/web/views/scheduled.slim +27 -0
  138. metadata +341 -23
  139. data/lib/creeper/celluloid_ext.rb +0 -42
  140. data/lib/creeper/creep.rb +0 -25
  141. data/lib/creeper/err_logger.rb +0 -37
  142. data/lib/creeper/launcher.rb +0 -44
  143. data/lib/creeper/out_logger.rb +0 -39
  144. data/spec/lib/creeper/session_spec.rb +0 -15
  145. data/spec/lib/creeper/worker_spec.rb +0 -21
@@ -0,0 +1,248 @@
1
+ require 'sinatra/base'
2
+ require 'slim'
3
+ require 'sprockets'
4
+ require 'creeper/paginator'
5
+
6
+ module Creeper
7
+ class SprocketsMiddleware
8
+ def initialize(app, options={})
9
+ @app = app
10
+ @root = options[:root]
11
+ path = options[:path] || 'assets'
12
+ @matcher = /^\/#{path}\/*/
13
+ @environment = ::Sprockets::Environment.new(@root)
14
+ @environment.append_path 'assets/javascripts'
15
+ @environment.append_path 'assets/javascripts/vendor'
16
+ @environment.append_path 'assets/stylesheets'
17
+ @environment.append_path 'assets/stylesheets/vendor'
18
+ @environment.append_path 'assets/images'
19
+ end
20
+
21
+ def call(env)
22
+ # Solve the problem of people requesting /creeper when they need to request /creeper/ so
23
+ # that relative links in templates resolve correctly.
24
+ return [301, { 'Location' => "#{env['SCRIPT_NAME']}/", 'Content-Type' => 'text/html' }, ['redirecting']] if env['SCRIPT_NAME'] == env['REQUEST_PATH']
25
+
26
+ return @app.call(env) unless @matcher =~ env["PATH_INFO"]
27
+ env['PATH_INFO'].sub!(@matcher,'')
28
+ @environment.call(env)
29
+ end
30
+ end
31
+
32
+ class Web < Sinatra::Base
33
+ include Creeper::Paginator
34
+
35
+ dir = File.expand_path(File.dirname(__FILE__) + "/../../web")
36
+ set :views, "#{dir}/views"
37
+ set :root, "#{dir}/public"
38
+ set :slim, :pretty => true
39
+ use SprocketsMiddleware, :root => dir
40
+
41
+ helpers do
42
+
43
+ def reset_worker_list
44
+ Creeper.redis do |conn|
45
+ workers = conn.smembers('workers')
46
+ workers.each do |name|
47
+ conn.srem('workers', name)
48
+ end
49
+ end
50
+ end
51
+
52
+ def workers
53
+ @workers ||= begin
54
+ Creeper.redis do |conn|
55
+ conn.smembers('workers').map do |w|
56
+ msg = conn.get("worker:#{w}")
57
+ msg ? [w, Creeper.load_json(msg)] : nil
58
+ end.compact.sort { |x| x[1] ? -1 : 1 }
59
+ end
60
+ end
61
+ end
62
+
63
+ def processed
64
+ Creeper.redis { |conn| conn.get('stat:processed') } || 0
65
+ end
66
+
67
+ def failed
68
+ Creeper.redis { |conn| conn.get('stat:failed') } || 0
69
+ end
70
+
71
+ def zcard(name)
72
+ Creeper.redis { |conn| conn.zcard(name) }
73
+ end
74
+
75
+ def queues
76
+ @queues ||= Creeper.redis do |conn|
77
+ conn.smembers('queues').map do |q|
78
+ [q, conn.llen("queue:#{q}") || 0]
79
+ end.sort { |x,y| x[1] <=> y[1] }
80
+ end
81
+ end
82
+
83
+ def backlog
84
+ # queues.map {|name, size| size }.inject(0) {|memo, val| memo + val }
85
+ beanstalk_stats['current-jobs-ready']
86
+ end
87
+
88
+ def buried
89
+ beanstalk_stats['current-jobs-buried']
90
+ end
91
+
92
+ def scheduled
93
+ beanstalk_stats['current-jobs-delayed']
94
+ end
95
+
96
+ def retries_with_score(score)
97
+ Creeper.redis do |conn|
98
+ results = conn.zrangebyscore('retry', score, score)
99
+ results.map { |msg| Creeper.load_json(msg) }
100
+ end
101
+ end
102
+
103
+ def beanstalk_stats
104
+ @beanstalk_stats ||= Creeper.beanstalk do |conn|
105
+ conn.stats
106
+ end
107
+ end
108
+
109
+ def beanstalk_location
110
+ Creeper.beanstalk { |conn| conn.instance_variable_get(:@addrs) }.join(', ')
111
+ end
112
+
113
+ def location
114
+ Creeper.redis { |conn| conn.client.location }
115
+ end
116
+
117
+ def root_path
118
+ "#{env['SCRIPT_NAME']}/"
119
+ end
120
+
121
+ def current_status
122
+ return 'idle' if workers.size == 0
123
+ return 'active'
124
+ end
125
+
126
+ def relative_time(time)
127
+ %{<time datetime="#{time.getutc.iso8601}">#{time}</time>}
128
+ end
129
+
130
+ def display_args(args, count=100)
131
+ args.map { |arg| a = arg.inspect; a.size > count ? "#{a[0..count]}..." : a }.join(", ")
132
+ end
133
+ end
134
+
135
+ get "/" do
136
+ slim :index
137
+ end
138
+
139
+ get "/poll" do
140
+ slim :poll, layout: false
141
+ end
142
+
143
+ get "/queues" do
144
+ @queues = queues
145
+ slim :queues
146
+ end
147
+
148
+ get "/queues/:name" do
149
+ halt 404 unless params[:name]
150
+ @count = (params[:count] || 25).to_i
151
+ @name = params[:name]
152
+ (@current_page, @total_size, @messages) = page("queue:#{@name}", params[:page], @count)
153
+ @messages = @messages.map {|msg| Creeper.load_json(msg) }
154
+ slim :queue
155
+ end
156
+
157
+ post "/reset" do
158
+ reset_worker_list
159
+ redirect root_path
160
+ end
161
+
162
+ post "/queues/:name" do
163
+ Creeper.redis do |conn|
164
+ conn.del("queue:#{params[:name]}")
165
+ conn.srem("queues", params[:name])
166
+ end
167
+ redirect "#{root_path}queues"
168
+ end
169
+
170
+ get "/retries/:score" do
171
+ halt 404 unless params[:score]
172
+ @score = params[:score].to_f
173
+ @retries = retries_with_score(@score)
174
+ redirect "#{root_path}retries" if @retries.empty?
175
+ slim :retry
176
+ end
177
+
178
+ get '/retries' do
179
+ @count = (params[:count] || 25).to_i
180
+ (@current_page, @total_size, @retries) = page("retry", params[:page], @count)
181
+ @retries = @retries.map {|msg, score| [Creeper.load_json(msg), score] }
182
+ slim :retries
183
+ end
184
+
185
+ get '/scheduled' do
186
+ @count = (params[:count] || 25).to_i
187
+ (@current_page, @total_size, @scheduled) = page("schedule", params[:page], @count)
188
+ @scheduled = @scheduled.map {|msg, score| [Creeper.load_json(msg), score] }
189
+ slim :scheduled
190
+ end
191
+
192
+ post '/scheduled' do
193
+ halt 404 unless params[:score]
194
+ halt 404 unless params['delete']
195
+ params[:score].each do |score|
196
+ s = score.to_f
197
+ process_score('schedule', s, :delete)
198
+ end
199
+ redirect "#{root_path}scheduled"
200
+ end
201
+
202
+ post '/retries' do
203
+ halt 404 unless params[:score]
204
+ params[:score].each do |score|
205
+ s = score.to_f
206
+ if params['retry']
207
+ process_score('retry', s, :retry)
208
+ elsif params['delete']
209
+ process_score('retry', s, :delete)
210
+ end
211
+ end
212
+ redirect "#{root_path}retries"
213
+ end
214
+
215
+ post "/retries/:score" do
216
+ halt 404 unless params[:score]
217
+ score = params[:score].to_f
218
+ if params['retry']
219
+ process_score('retry', score, :retry)
220
+ elsif params['delete']
221
+ process_score('retry', score, :delete)
222
+ end
223
+ redirect "#{root_path}retries"
224
+ end
225
+
226
+ def process_score(set, score, operation)
227
+ case operation
228
+ when :retry
229
+ raise "Not Implemented"
230
+ Creeper.redis do |conn|
231
+ results = conn.zrangebyscore(set, score, score)
232
+ conn.zremrangebyscore(set, score, score)
233
+ results.map do |message|
234
+ msg = Creeper.load_json(message)
235
+ msg['retry_count'] = msg['retry_count'] - 1
236
+ conn.rpush("queue:#{msg['queue']}", Creeper.dump_json(msg))
237
+ end
238
+ end
239
+ when :delete
240
+ Creeper.redis do |conn|
241
+ conn.zremrangebyscore(set, score, score)
242
+ end
243
+ end
244
+ end
245
+
246
+ end
247
+
248
+ end
@@ -1,331 +1,80 @@
1
- require 'creeper'
2
-
3
- require 'celluloid'
4
- require 'creeper/celluloid_ext'
5
- # require 'em-jack'
1
+ require 'creeper/client'
2
+ require 'creeper/core_ext'
6
3
 
7
4
  module Creeper
8
5
 
9
- at_exit { shutdown_workers }
10
-
11
- class Worker
12
-
13
- def self.work(jobs = nil, size = nil)
14
-
15
- size ||= Creeper.pool_size
16
-
17
- options = {
18
- size: size,
19
- args: [jobs]
20
- }
21
-
22
- Creeper.worker_pool = Creeper::Worker.pool(options)
23
-
24
- begin
25
- trap(:INT) { Creeper.shutdown = true }
26
- trap(:TERM) { Creeper.shutdown = true }
27
- trap(:QUIT) { Creeper.shutdown = true }
28
- Creeper.worker_pool.start
29
- end until Creeper.shutdown?
30
-
31
- exit
32
- end
33
-
34
- # def self.em_work(jobs = nil, size = 2)
35
-
36
- # options = {
37
- # size: size,
38
- # args: [jobs]
39
- # }
40
-
41
- # tubes = jobs_for(jobs)
42
-
43
- # Creeper.worker_pool = Creeper::Worker.pool(options)
44
-
45
- # sleep 1
46
-
47
- # EM.run do
48
- # trap(:INT) { Creeper.shutdown = true; EM.stop }
49
- # trap(:TERM) { Creeper.shutdown = true; EM.stop }
50
- # trap(:QUIT) { Creeper.shutdown = true; EM.stop }
51
-
52
- # jack = EMJack::Connection.new(Creeper.beanstalk_url)
53
-
54
- # reserve_loop = ->(timeout) do
55
- # r = jack.reserve(timeout)
56
- # r.callback do |job|
57
- # Creeper.worker_pool.work! job
58
- # EM.next_tick { reserve_loop.call(timeout) }
59
- # end
60
- # r.errback do
61
- # EM.next_tick { reserve_loop.call(timeout) }
62
- # end
63
- # end
64
-
65
- # watch_tubes = ->(list) do
66
- # if list.empty?
67
- # reserve_loop.call(Creeper.reserve_timeout)
68
- # else
69
- # w = jack.watch(list.shift)
70
- # w.callback do
71
- # watch_tubes.call(list)
72
- # end
73
- # end
74
- # end
75
-
76
- # watch_tubes.call(tubes)
77
-
78
- # end
79
-
80
- # end
81
-
82
- def self.jobs_for(jobs = nil)
83
- case jobs
84
- when :all, nil
85
- Creeper.all_jobs
86
- else
87
- Array(jobs)
88
- end
89
- end
90
-
91
- include Celluloid
92
-
93
- attr_accessor :number
94
- attr_reader :jobs
95
-
96
- def initialize(jobs = nil)
97
- @jobs = self.class.jobs_for(jobs)
98
-
99
- Creeper.register_worker(self)
100
- OutLogger.info "#{prefix} Working #{self.jobs.size} jobs: [ #{self.jobs.join(' ')} ]"
101
- end
102
-
103
- def dump(job, name = nil, data = nil)
104
- "#{name.inspect rescue nil} { data: #{(data.inspect rescue nil)}, job: #{(job.inspect rescue nil)} }"
105
- end
106
-
107
- def prefix
108
- "[#{number_format % number} - #{'%x' % Thread.current.object_id}]"
109
- end
110
-
111
- def number_format
112
- "%#{Creeper.pool_size.to_s.length}d"
113
- end
114
-
115
- def time_in_milliseconds
116
- ((stopped_at - started_at).to_f * 1000).to_i
117
- end
118
-
119
- def started_at
120
- Thread.current[:creeper_started_at]
121
- end
122
-
123
- def started_at=(started_at)
124
- Thread.current[:creeper_started_at] = started_at
125
- end
126
-
127
- def stopped_at
128
- Thread.current[:creeper_stopped_at]
129
- end
130
-
131
- def stopped_at=(stopped_at)
132
- Thread.current[:creeper_stopped_at] = stopped_at
133
- end
134
-
135
- ## beanstalk ##
136
-
137
- def beanstalk
138
- Creeper.beanstalk
139
- end
140
-
141
- def ignore(tube)
142
- beanstalk.ignore(tube)
143
- rescue Beanstalk::NotConnected => e
144
- disconnected(self, :ignore, tube) || raise
145
- end
146
-
147
- def list_tubes_watched(cached = false)
148
- beanstalk.list_tubes_watched
149
- rescue Beanstalk::NotConnected => e
150
- disconnected(self, :list_tubes_watched, cached) || raise
151
- end
152
-
153
- def reserve(timeout = nil)
154
- beanstalk.reserve(timeout)
155
- rescue Beanstalk::NotConnected => e
156
- disconnected(self, :reserve, timeout) || raise
157
- end
158
-
159
- def watch(tube)
160
- beanstalk.watch(tube)
161
- rescue Beanstalk::NotConnected => e
162
- disconnected(self, :watch, tube) || raise
163
- end
164
-
165
- ##
166
-
167
- ## work ##
168
-
169
- def start(short_circuit = false)
170
- return false if short_circuit
171
- exit if stopped?
172
- return true if working?
173
- prepare if not prepared?
174
-
175
- begin
176
- job = reserve Creeper.reserve_timeout
177
- rescue Beanstalk::TimedOut
178
- OutLogger.debug "#{prefix} Back to the unemployment line" if $DEBUG
179
- return false
6
+ ##
7
+ # Include this module in your worker class and you can easily create
8
+ # asynchronous jobs:
9
+ #
10
+ # class HardWorker
11
+ # include Creeper::Worker
12
+ #
13
+ # def perform(*args)
14
+ # # do some work
15
+ # end
16
+ # end
17
+ #
18
+ # Then in your Rails app, you can do this:
19
+ #
20
+ # HardWorker.perform_async(1, 2, 3)
21
+ #
22
+ # Note that perform_async is a class method, perform is an instance method.
23
+ module Worker
24
+ def self.included(base)
25
+ base.extend(ClassMethods)
26
+ base.class_attribute :creeper_options_hash
27
+ end
28
+
29
+ def logger
30
+ Creeper.logger
31
+ end
32
+
33
+ module ClassMethods
34
+
35
+ include Creeper::Legacy::WorkerMethods
36
+
37
+ def perform_async(*args)
38
+ client_push('class' => self, 'args' => args)
180
39
  end
181
40
 
182
- exit if stopped?
183
-
184
- Thread.current[:creeper_working] = true
185
-
186
- OutLogger.debug "#{prefix} Got #{job.inspect}" if $DEBUG
187
-
188
- work! job # asynchronously go to work
189
- rescue SystemExit => e
190
- job.release rescue nil
191
- Creeper.unregister_worker(self)
192
- rescue => e
193
- job.release rescue nil
194
- Creeper.unregister_worker(self, "start loop error")
195
- raise
196
- end
197
-
198
- def finalize
199
- Creeper.finalizers.each do |finalizer|
200
- begin
201
- case finalizer.arity
202
- when 1
203
- finalizer.call(self)
204
- else
205
- finalizer.call
206
- end
207
- rescue => e
208
- OutLogger.crash "#{prefix} finalizer error", e
209
- end
41
+ def perform_in(interval, *args)
42
+ int = interval.to_f
43
+ ts = (int < 1_000_000_000 ? Time.now.to_f + int : int)
44
+ client_push('class' => self, 'args' => args, 'at' => ts)
210
45
  end
211
-
212
- ensure
213
- Creeper.disconnect
214
- end
215
-
216
- def stop
217
- Thread.current[:creeper_stopped] = true
218
- end
219
-
220
- def work(job)
221
-
222
- exit if stopped?
223
-
224
- name, data = JSON.parse(job.body)
225
-
226
- Creeper.start_work(self, data, name, job)
227
-
228
- begin
229
- Creeper.before_handlers_for(name).each do |handler|
230
- process(handler, data, name, job)
231
- end
232
-
233
- Creeper.handler_for(name).tap do |handler|
234
- process(handler, data, name, job)
235
- end
236
-
237
- Creeper.after_handlers_for(name).each do |handler|
238
- process(handler, data, name, job)
239
- end
46
+ alias_method :perform_at, :perform_in
47
+
48
+ ##
49
+ # Allows customization for this type of Worker.
50
+ # Legal options:
51
+ #
52
+ # :queue - use a named queue for this Worker, default 'default'
53
+ # :retry - enable the RetryJobs middleware for this Worker, default *true*
54
+ # :timeout - timeout the perform method after N seconds, default *nil*
55
+ # :backtrace - whether to save any error backtrace in the retry payload to display in web UI,
56
+ # can be true, false or an integer number of lines to save, default *false*
57
+ def creeper_options(opts={})
58
+ self.creeper_options_hash = get_creeper_options.merge(stringify_keys(opts || {}))
240
59
  end
241
60
 
242
- job.delete
61
+ DEFAULT_OPTIONS = { 'retry' => true, 'queue' => 'default' }
243
62
 
244
- Creeper.stop_work(self, data, name, job)
245
-
246
- # start! unless stopped? or EM.reactor_running?
247
- start! unless stopped? # continue processing, even when end of links is reached
248
-
249
- rescue Beanstalk::NotConnected => e
250
- disconnected(self, :work, job) || begin
251
- job.release rescue nil
252
- Creeper.unregister_worker(self)
253
- raise
63
+ def get_creeper_options # :nodoc:
64
+ self.creeper_options_hash ||= DEFAULT_OPTIONS
254
65
  end
255
- rescue SystemExit => e
256
- job.release rescue nil
257
- Creeper.unregister_worker(self)
258
- rescue => e
259
-
260
- job.bury rescue nil
261
-
262
- Creeper.error_work(self, data, name, job)
263
66
 
264
- begin
265
- Creeper.error_handlers_for(name).each do |handler|
266
- process(handler, data, name, job)
67
+ def stringify_keys(hash) # :nodoc:
68
+ hash.keys.each do |key|
69
+ hash[key.to_s] = hash.delete(key)
267
70
  end
71
+ hash
268
72
  end
269
73
 
270
- Creeper.unregister_worker(self, "work loop error, burying #{dump(job, name, data)}")
271
-
272
- raise
273
- ensure
274
- Thread.current[:creeper_started_at] = nil
275
- Thread.current[:creeper_stopped_at] = nil
276
- Thread.current[:creeper_working] = false
277
- end
278
-
279
- def process(handler, data, name, job)
280
- case handler.arity
281
- when 3
282
- handler.call(data, name, job)
283
- when 2
284
- handler.call(data, name)
285
- when 1
286
- handler.call(data)
287
- else
288
- handler.call
289
- end
290
- end
291
-
292
- ##
293
-
294
- ## flags ##
295
-
296
- def prepared?
297
- Thread.current[:creeper_prepared] == true
298
- end
299
-
300
- def stopped?
301
- Thread.current[:creeper_stopped] == true || Creeper.shutdown?
302
- end
303
-
304
- def working?
305
- Thread.current[:creeper_working] == true
306
- end
307
-
308
- ##
309
-
310
- protected
311
-
312
- def disconnected(target, method, *args, &block)
313
- Creeper.send(:disconnected, target, method, *args, &block)
314
- end
315
-
316
- def prepare
317
- jobs.each do |job|
318
- watch(job)
319
- end
320
-
321
- list_tubes_watched.each do |server, tubes|
322
- tubes.each do |tube|
323
- ignore(tube) unless jobs.include?(tube)
324
- end
74
+ def client_push(*args) # :nodoc:
75
+ Creeper::Client.push(*args)
325
76
  end
326
77
 
327
- Thread.current[:creeper_prepared] = true
328
78
  end
329
-
330
79
  end
331
- end
80
+ end