perfectqueue 0.7.32 → 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.
Files changed (52) hide show
  1. data/.gitignore +6 -0
  2. data/ChangeLog +0 -62
  3. data/Gemfile +3 -0
  4. data/README.md +239 -0
  5. data/Rakefile +19 -0
  6. data/lib/perfectqueue.rb +68 -4
  7. data/lib/perfectqueue/application.rb +30 -0
  8. data/lib/perfectqueue/application/base.rb +27 -0
  9. data/lib/perfectqueue/application/dispatch.rb +73 -0
  10. data/lib/perfectqueue/application/router.rb +69 -0
  11. data/lib/perfectqueue/backend.rb +44 -47
  12. data/lib/perfectqueue/backend/rdb_compat.rb +298 -0
  13. data/lib/perfectqueue/blocking_flag.rb +84 -0
  14. data/lib/perfectqueue/client.rb +117 -0
  15. data/lib/perfectqueue/command/perfectqueue.rb +108 -323
  16. data/lib/perfectqueue/daemons_logger.rb +80 -0
  17. data/lib/perfectqueue/engine.rb +85 -123
  18. data/lib/perfectqueue/error.rb +53 -0
  19. data/lib/perfectqueue/model.rb +37 -0
  20. data/lib/perfectqueue/multiprocess.rb +31 -0
  21. data/lib/perfectqueue/multiprocess/child_process.rb +108 -0
  22. data/lib/perfectqueue/multiprocess/child_process_monitor.rb +109 -0
  23. data/lib/perfectqueue/multiprocess/fork_processor.rb +164 -0
  24. data/lib/perfectqueue/multiprocess/thread_processor.rb +123 -0
  25. data/lib/perfectqueue/queue.rb +58 -0
  26. data/lib/perfectqueue/runner.rb +39 -0
  27. data/lib/perfectqueue/signal_queue.rb +112 -0
  28. data/lib/perfectqueue/task.rb +103 -0
  29. data/lib/perfectqueue/task_metadata.rb +98 -0
  30. data/lib/perfectqueue/task_monitor.rb +189 -0
  31. data/lib/perfectqueue/task_status.rb +27 -0
  32. data/lib/perfectqueue/version.rb +1 -3
  33. data/lib/perfectqueue/worker.rb +114 -196
  34. data/perfectqueue.gemspec +24 -0
  35. data/spec/queue_spec.rb +234 -0
  36. data/spec/spec_helper.rb +44 -0
  37. data/spec/worker_spec.rb +81 -0
  38. metadata +93 -40
  39. checksums.yaml +0 -7
  40. data/README.rdoc +0 -224
  41. data/lib/perfectqueue/backend/null.rb +0 -33
  42. data/lib/perfectqueue/backend/rdb.rb +0 -181
  43. data/lib/perfectqueue/backend/simpledb.rb +0 -139
  44. data/test/backend_test.rb +0 -259
  45. data/test/cat.sh +0 -2
  46. data/test/echo.sh +0 -4
  47. data/test/exec_test.rb +0 -61
  48. data/test/fail.sh +0 -2
  49. data/test/huge.sh +0 -2
  50. data/test/stress.rb +0 -99
  51. data/test/success.sh +0 -2
  52. data/test/test_helper.rb +0 -19
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ .bundle
2
+ Gemfile.lock
3
+ vendor/*
4
+ coverage/*
5
+ pkg/*
6
+ spec/test.db
data/ChangeLog CHANGED
@@ -1,65 +1,3 @@
1
- == 2016-07-22 version 0.7.32
2
-
3
- DON'T USE THIS VERSION UNLESS YOU KNOW WHAT THIS IS!
4
- This version is for migration v07 to v0.8.48.
5
-
6
- * Use PerfectQueue v0.8.48's timeout model (#41)
7
-
8
-
9
- == 2014-10-08 version 0.7.31
10
-
11
- * Upgraded sequal v3.48.0
12
-
13
-
14
- == 2014-04-24 version 0.7.30
15
-
16
- * RDBBackend: fixed NoMethodError for @url
17
-
18
-
19
- == 2014-04-24 version 0.7.29
20
-
21
- * RDBBackend: add MySQL's SSL support
22
-
23
-
24
- == 2014-02-18 version 0.7.28
25
-
26
- * RDBBackend: wrap blob data in Sequel::SQL::Blob
27
-
28
-
29
- == 2013-06-16 version 0.7.27
30
-
31
- * RDBBackend: #issue should not ignore erros excepting duplicate entry error
32
-
33
-
34
- == 2013-06-14 version 0.7.26
35
-
36
- * RDBBackend: #issue should not ignore erros excepting duplicate entry error
37
-
38
-
39
- == 2012-09-19 version 0.7.25
40
-
41
- * removed depenedency on aws-sdk which is optional
42
-
43
-
44
- == 2012-08-10 version 0.7.24
45
-
46
- * Kill running task if an unexpected error occured during extending timeout
47
-
48
-
49
- == 2012-08-03 version 0.7.23
50
-
51
- * Use free slot ratio instead of free slot amount to decide task priorities
52
-
53
-
54
- == 2012-07-19 version 0.7.22
55
-
56
- * Fixed RDBBackend SQL
57
-
58
-
59
- == 2012-07-19 version 0.7.21
60
-
61
- * Added max_running column for fair resource restriction
62
-
63
1
 
64
2
  == 2012-01-24 version 0.7.20
65
3
 
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,239 @@
1
+ # PerfectQueue
2
+
3
+ PerfectQueue is a highly available distributed queue built on top of RDBMS.
4
+ It provides at-least-once semantics; Even if a worker node fails during processing a task, the task is retried by another worker.
5
+ PerfectQueue provides similar API to Amazon SQS. But unlike Amazon SQS, PerfectQueue never delivers finished tasks.
6
+
7
+ Since PerfectQueue also prevents storing a same task twice by using unique task identifier, client applications can retry to submit tasks until it succeeds.
8
+
9
+ All you have to consider is implementing idempotent worker programs. PerfectQueue manages the other problems.
10
+
11
+ ## API overview
12
+
13
+ ```
14
+ # open a queue
15
+ PerfectQueue.open(config, &block) #=> #<Queue>
16
+
17
+ # submit a task
18
+ Queue#submit(task_id, type, data, options={})
19
+
20
+ # poll a task
21
+ # (you don't have to use this method directly. see following sections)
22
+ Queue#poll #=> #<AcquiredTask>
23
+
24
+ # get data associated with a task
25
+ AcquiredTask#data #=> #<Hash>
26
+
27
+ # finish a task
28
+ AcquiredTask#finish!
29
+
30
+ # retry a task
31
+ AcquiredTask#retry!
32
+
33
+ # create a task reference
34
+ Queue#[](key) #=> #<Task>
35
+
36
+ # chack the existance of the task
37
+ Task#exists?
38
+
39
+ # request to cancel a task
40
+ # (actual behavior depends on the worker program)
41
+ Task#cancel_request!
42
+
43
+ # force finish a task
44
+ # be aware that worker programs can't detect it
45
+ Task#force_finish!
46
+ ```
47
+
48
+ ### Error classes
49
+
50
+ ```
51
+ TaskError
52
+
53
+ ##
54
+ # Workers may get these errors:
55
+ #
56
+
57
+ CancelRequestedError < TaskError
58
+
59
+ AlreadyFinishedError < TaskError
60
+
61
+ PreemptedError < TaskError
62
+
63
+ ProcessStopError < RuntimeError
64
+
65
+ ImmediateProcessStopError < ProcessStopError
66
+
67
+ GracefulProcessStopError < ProcessStopError
68
+
69
+ ##
70
+ # Client or other situation:
71
+ #
72
+
73
+ ConfigError < RuntimeError
74
+
75
+ NotFoundError < TaskError
76
+
77
+ AlreadyExistsError < TaskError
78
+
79
+ NotSupportedError < TaskError
80
+ ```
81
+
82
+
83
+ ### Example
84
+
85
+ ```ruby
86
+ # submit tasks
87
+ PerfectQueue.open(config) {|queue|
88
+ data = {'key'=>"value"}
89
+ queue.submit("task-id", "type1", data)
90
+ }
91
+ ```
92
+
93
+
94
+ ## Writing a worker application
95
+
96
+ ### 1. Implement PerfectQueue::Application::Base
97
+
98
+ ```ruby
99
+ class TestHandler < PerfectQueue::Application::Base
100
+ # implement run method
101
+ def run
102
+ # do something ...
103
+ puts "acquired task: #{task.inspect}"
104
+
105
+ # call task.finish!, task.retry! or task.release!
106
+ task.finish!
107
+ end
108
+ end
109
+ ```
110
+
111
+ ### 2. Implement PerfectQueue::Application::Dispatch
112
+
113
+ ```ruby
114
+ class Dispatch < PerfectQueue::Application::Dispatch
115
+ # describe routing
116
+ route "type1" => TestHandler
117
+ route /^regexp-.*$/ => :TestHandler # String or Regexp => Class or Symbol
118
+ end
119
+ ```
120
+
121
+ ### 3. Run the worker
122
+
123
+ In a launcher script or rake file:
124
+
125
+ ```ruby
126
+ system('perfectqueue run -I. -rapp/workers/dispatch Dispatch')
127
+ ```
128
+
129
+ or:
130
+
131
+ ```ruby
132
+ require 'perfectqueue'
133
+ require 'app/workers/dispatch'
134
+
135
+ PerfectQueue::Worker.run(Dispatch) {
136
+ # this method is called when the worker process is restarted
137
+ raw = File.read('config/perfectqueue.yml')
138
+ yml = YAJL.load(raw)
139
+ yml[ENV['RAILS_ENV'] || 'development']
140
+ }
141
+ ```
142
+
143
+ ### Signal handlers
144
+
145
+ - **TERM**,**INT:** graceful shutdown
146
+ - **QUIT:** immediate shutdown
147
+ - **USR1:** graceful restart
148
+ - **HUP:** immediate restart
149
+ - **WINCH:** immediate binary replace
150
+ - **CONT:** graceful binary replace
151
+ - **USR2:** reopen log files
152
+
153
+ ## Configuration
154
+
155
+ - **type:** backend type (required; see following sections)
156
+ - **log:** log file path (default: use stderr)
157
+ - **processors:** number of child processes (default: 1)
158
+ - **processor_type:** type of processor ('process' or 'thread') (default: 'process')
159
+ - **poll_interval:** interval to poll tasks in seconds (default: 1.0 sec)
160
+ - **retention_time:** duration to retain finished tasks (default: 300 sec)
161
+ - **task_heartbeat_interval:** interval to send heartbeat requests (default: 2 sec)
162
+ - **alive_time:** duration to continue a heartbeat request (default: 300 sec)
163
+ - **retry_wait:** duration to retry a retried task (default: 300 sec)
164
+ - **child_kill_interval:** interval to send signals to a child process (default: 2.0 sec)
165
+ - **child_graceful_kill_limit:** threshold time to switch SIGTERM to SIGKILL (default: never)
166
+ - **child_heartbeat_interval:** interval to send heartbeat packets to a child process (default: 2 sec)
167
+ - **child_heartbeat_limit:** threshold time to detect freeze of a child process (default: 10.0 sec)
168
+
169
+ ## Backend types
170
+
171
+ ### rdb\_compat
172
+
173
+ additional configuration:
174
+
175
+ - **url:** URL to the RDBMS (example: 'mysql://user:password@host:port/database')
176
+ - **table:** name of the table to use
177
+
178
+ ### rdb
179
+
180
+ Not implemented yet.
181
+
182
+
183
+ ## Command line management tool
184
+
185
+ ```
186
+ Usage: perfectqueue [options] <command>
187
+
188
+ commands:
189
+ list Show list of tasks
190
+ submit <key> <type> <data> Submit a new task
191
+ cancel_request <key> Cancel request
192
+ force_finish <key> Force finish a task
193
+ run <class> Run a worker process
194
+ init Initialize a backend database
195
+
196
+ options:
197
+ -e, --environment ENV Framework environment (default: development)
198
+ -c, --config PATH.yml Path to a configuration file (default: config/perfectqueue.yml)
199
+
200
+ options for submit:
201
+ -u, --user USER Set user
202
+ -t, --time UNIXTIME Set time to run the task
203
+
204
+ options for run:
205
+ -I, --include PATH Add $LOAD_PATH directory
206
+ -r, --require PATH Require files before starting
207
+ ```
208
+
209
+
210
+ ### initializing a database
211
+
212
+ # assume that the config/perfectqueue.yml exists
213
+ $ perfectqueue init
214
+
215
+ ### submitting a task
216
+
217
+ $ perfectqueue submit k1 user_task '{"uid":1}' -u user_1
218
+
219
+ ### listing tasks
220
+
221
+ $ perfectqueue list
222
+ key type user status created_at timeout data
223
+ k1 user_task user_1 waiting 2012-05-18 13:05:31 -0700 2012-05-18 14:27:36 -0700 {"uid"=>1, "type"=>"user_task"}
224
+ k2 user_task user_2 waiting 2012-05-18 13:35:33 -0700 2012-05-18 14:35:33 -0700 {"uid"=>2, "type"=>"user_task"}
225
+ k3 system_task waiting 2012-05-18 14:04:02 -0700 2012-05-22 15:04:02 -0700 {"task_id"=>32, "type"=>"system_task"}
226
+ 3 entries.
227
+
228
+ ### cancel a tasks
229
+
230
+ $ perfectqueue cancel_request k1
231
+
232
+ ### force finish a tasks
233
+
234
+ $ perfectqueue cancel_request k2
235
+
236
+ ### running a worker
237
+
238
+ $ perfectqueue run -I. -Ilib -rconfig/boot.rb -rapps/workers/task_dispatch.rb TaskDispatch
239
+
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core'
5
+ require 'rspec/core/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec) do |t|
8
+ t.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"]
9
+ t.pattern = 'spec/**/*_spec.rb'
10
+ t.verbose = true
11
+ end
12
+
13
+ task :coverage do |t|
14
+ ENV['SIMPLE_COV'] = '1'
15
+ Rake::Task["spec"].invoke
16
+ end
17
+
18
+ task :default => :build
19
+
data/lib/perfectqueue.rb CHANGED
@@ -1,4 +1,68 @@
1
- require 'perfectqueue/engine'
2
- require 'perfectqueue/worker'
3
- require 'perfectqueue/backend'
4
- require 'perfectqueue/version'
1
+ #
2
+ # PerfectQueue
3
+ #
4
+ # Copyright (C) 2012 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ module PerfectQueue
20
+ require 'json'
21
+ require 'thread' # Mutex, CoditionVariable
22
+
23
+ {
24
+ :Application => 'perfectqueue/application',
25
+ :Backend => 'perfectqueue/backend',
26
+ :BackendHelper => 'perfectqueue/backend',
27
+ :BlockingFlag => 'perfectqueue/blocking_flag',
28
+ :Client => 'perfectqueue/client',
29
+ :DaemonsLogger => 'perfectqueue/daemons_logger',
30
+ :Engine => 'perfectqueue/engine',
31
+ :Model => 'perfectqueue/model',
32
+ :Queue => 'perfectqueue/queue',
33
+ :Runner => 'perfectqueue/runner',
34
+ :Task => 'perfectqueue/task',
35
+ :TaskWithMetadata => 'perfectqueue/task',
36
+ :AcquiredTask => 'perfectqueue/task',
37
+ :TaskMetadata => 'perfectqueue/task_metadata',
38
+ :TaskMonitor => 'perfectqueue/task_monitor',
39
+ :TaskMetadataAccessors => 'perfectqueue/task_metadata',
40
+ :TaskStatus => 'perfectqueue/task_status',
41
+ :Worker => 'perfectqueue/worker',
42
+ :SignalQueue => 'perfectqueue/signal_queue',
43
+ }.each_pair {|k,v|
44
+ autoload k, File.expand_path(v, File.dirname(__FILE__))
45
+ }
46
+ [
47
+ 'perfectqueue/multiprocess',
48
+ 'perfectqueue/error',
49
+ ].each {|v|
50
+ require File.expand_path(v, File.dirname(__FILE__))
51
+ }
52
+
53
+ def self.open(config, &block)
54
+ c = Client.new(config)
55
+ begin
56
+ q = Queue.new(c)
57
+ if block
58
+ block.call(q)
59
+ else
60
+ c = nil
61
+ return q
62
+ end
63
+ ensure
64
+ c.close if c
65
+ end
66
+ end
67
+ end
68
+
@@ -0,0 +1,30 @@
1
+ #
2
+ # PerfectQueue
3
+ #
4
+ # Copyright (C) 2012 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ module PerfectQueue
20
+ module Application
21
+ {
22
+ :Dispatch => 'application/dispatch',
23
+ :Router => 'application/router',
24
+ :Base => 'application/base',
25
+ }.each_pair {|k,v|
26
+ autoload k, File.expand_path(v, File.dirname(__FILE__))
27
+ }
28
+ end
29
+ end
30
+
@@ -0,0 +1,27 @@
1
+ #
2
+ # PerfectQueue
3
+ #
4
+ # Copyright (C) 2012 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ module PerfectQueue
20
+ module Application
21
+
22
+ class Base < Runner
23
+ end
24
+
25
+ end
26
+ end
27
+