qwirk 0.0.1
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/History.md +7 -0
- data/LICENSE.txt +201 -0
- data/README.md +180 -0
- data/Rakefile +34 -0
- data/examples/README +1 -0
- data/examples/activemq.xml +84 -0
- data/examples/advanced_requestor/README.md +15 -0
- data/examples/advanced_requestor/base_request_worker.rb +18 -0
- data/examples/advanced_requestor/char_count_worker.rb +16 -0
- data/examples/advanced_requestor/config.ru +24 -0
- data/examples/advanced_requestor/exception_raiser_worker.rb +17 -0
- data/examples/advanced_requestor/length_worker.rb +14 -0
- data/examples/advanced_requestor/print_worker.rb +14 -0
- data/examples/advanced_requestor/publisher.rb +49 -0
- data/examples/advanced_requestor/qwirk.yml +16 -0
- data/examples/advanced_requestor/reverse_worker.rb +14 -0
- data/examples/advanced_requestor/triple_worker.rb +14 -0
- data/examples/batch/my_batch_worker.rb +30 -0
- data/examples/batch/my_line_worker.rb +8 -0
- data/examples/qwirk.yml +20 -0
- data/examples/requestor/README.md +13 -0
- data/examples/requestor/config.ru +13 -0
- data/examples/requestor/qwirk_persist.yml +5 -0
- data/examples/requestor/requestor.rb +68 -0
- data/examples/requestor/reverse_echo_worker.rb +15 -0
- data/examples/setup.rb +13 -0
- data/examples/shared/README.md +24 -0
- data/examples/shared/config.ru +13 -0
- data/examples/shared/publisher.rb +49 -0
- data/examples/shared/qwirk_persist.yml +5 -0
- data/examples/shared/shared_worker.rb +16 -0
- data/examples/simple/README +53 -0
- data/examples/simple/bar_worker.rb +10 -0
- data/examples/simple/baz_worker.rb +10 -0
- data/examples/simple/config.ru +14 -0
- data/examples/simple/publisher.rb +49 -0
- data/examples/simple/qwirk_persist.yml +4 -0
- data/examples/simple/tmp/kahadb/db-1.log +0 -0
- data/examples/simple/tmp/kahadb/db.data +0 -0
- data/examples/simple/tmp/kahadb/db.redo +0 -0
- data/examples/task/README +47 -0
- data/examples/task/config.ru +14 -0
- data/examples/task/foo_worker.rb +10 -0
- data/examples/task/messages.out +1000 -0
- data/examples/task/publisher.rb +25 -0
- data/examples/task/qwirk_persist.yml +5 -0
- data/examples/task/task.rb +36 -0
- data/lib/qwirk.rb +63 -0
- data/lib/qwirk/adapter.rb +45 -0
- data/lib/qwirk/base_worker.rb +96 -0
- data/lib/qwirk/batch.rb +4 -0
- data/lib/qwirk/batch/acquire_file_strategy.rb +47 -0
- data/lib/qwirk/batch/active_record.rb +3 -0
- data/lib/qwirk/batch/active_record/batch_job.rb +111 -0
- data/lib/qwirk/batch/active_record/failed_record.rb +5 -0
- data/lib/qwirk/batch/active_record/outstanding_record.rb +6 -0
- data/lib/qwirk/batch/file_status_strategy.rb +86 -0
- data/lib/qwirk/batch/file_worker.rb +228 -0
- data/lib/qwirk/batch/job_status.rb +29 -0
- data/lib/qwirk/batch/parse_file_strategy.rb +48 -0
- data/lib/qwirk/engine.rb +9 -0
- data/lib/qwirk/loggable.rb +23 -0
- data/lib/qwirk/manager.rb +140 -0
- data/lib/qwirk/marshal_strategy.rb +74 -0
- data/lib/qwirk/marshal_strategy/bson.rb +37 -0
- data/lib/qwirk/marshal_strategy/json.rb +37 -0
- data/lib/qwirk/marshal_strategy/none.rb +26 -0
- data/lib/qwirk/marshal_strategy/ruby.rb +26 -0
- data/lib/qwirk/marshal_strategy/string.rb +25 -0
- data/lib/qwirk/marshal_strategy/yaml.rb +25 -0
- data/lib/qwirk/publish_handle.rb +170 -0
- data/lib/qwirk/publisher.rb +67 -0
- data/lib/qwirk/queue_adapter.rb +3 -0
- data/lib/qwirk/queue_adapter/active_mq.rb +13 -0
- data/lib/qwirk/queue_adapter/active_mq/publisher.rb +12 -0
- data/lib/qwirk/queue_adapter/active_mq/worker_config.rb +16 -0
- data/lib/qwirk/queue_adapter/in_mem.rb +7 -0
- data/lib/qwirk/queue_adapter/in_mem/factory.rb +45 -0
- data/lib/qwirk/queue_adapter/in_mem/publisher.rb +98 -0
- data/lib/qwirk/queue_adapter/in_mem/queue.rb +88 -0
- data/lib/qwirk/queue_adapter/in_mem/reply_queue.rb +56 -0
- data/lib/qwirk/queue_adapter/in_mem/topic.rb +48 -0
- data/lib/qwirk/queue_adapter/in_mem/worker.rb +63 -0
- data/lib/qwirk/queue_adapter/in_mem/worker_config.rb +59 -0
- data/lib/qwirk/queue_adapter/jms.rb +50 -0
- data/lib/qwirk/queue_adapter/jms/connection.rb +42 -0
- data/lib/qwirk/queue_adapter/jms/consumer.rb +37 -0
- data/lib/qwirk/queue_adapter/jms/publisher.rb +126 -0
- data/lib/qwirk/queue_adapter/jms/worker.rb +89 -0
- data/lib/qwirk/queue_adapter/jms/worker_config.rb +38 -0
- data/lib/qwirk/remote_exception.rb +42 -0
- data/lib/qwirk/request_worker.rb +62 -0
- data/lib/qwirk/task.rb +177 -0
- data/lib/qwirk/task.rb.sav +194 -0
- data/lib/qwirk/version.rb +3 -0
- data/lib/qwirk/worker.rb +222 -0
- data/lib/qwirk/worker_config.rb +187 -0
- data/lib/rails/generators/qwirk/qwirk_generator.rb +82 -0
- data/lib/rails/generators/qwirk/templates/initializer.rb +6 -0
- data/lib/rails/generators/qwirk/templates/migration.rb +9 -0
- data/lib/rails/generators/qwirk/templates/schema.rb +28 -0
- data/lib/rails/railties/tasks.rake +8 -0
- data/lib/tasks/qwirk_tasks.rake +4 -0
- data/test/base_test.rb +248 -0
- data/test/database.yml +14 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +45 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +22 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +26 -0
- data/test/dummy/config/environments/production.rb +49 -0
- data/test/dummy/config/environments/test.rb +35 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +58 -0
- data/test/dummy/log/development.log +0 -0
- data/test/dummy/log/production.log +0 -0
- data/test/dummy/log/server.log +0 -0
- data/test/dummy/log/test.log +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/public/javascripts/application.js +2 -0
- data/test/dummy/public/javascripts/controls.js +965 -0
- data/test/dummy/public/javascripts/dragdrop.js +974 -0
- data/test/dummy/public/javascripts/effects.js +1123 -0
- data/test/dummy/public/javascripts/prototype.js +6001 -0
- data/test/dummy/public/javascripts/rails.js +191 -0
- data/test/dummy/script/rails +6 -0
- data/test/integration/navigation_test.rb +7 -0
- data/test/jms.yml +9 -0
- data/test/jms_fail_test.rb +149 -0
- data/test/jms_requestor_block_test.rb +278 -0
- data/test/jms_requestor_test.rb +238 -0
- data/test/jms_test.rb +287 -0
- data/test/marshal_strategy_test.rb +62 -0
- data/test/support/integration_case.rb +5 -0
- data/test/test_helper.rb +7 -0
- data/test/test_helper.rbold +22 -0
- data/test/test_helper_active_record.rb +61 -0
- data/test/unit/qwirk/batch/acquire_file_strategy_test.rb +101 -0
- data/test/unit/qwirk/batch/active_record/batch_job_test.rb +35 -0
- data/test/unit/qwirk/batch/parse_file_strategy_test.rb +49 -0
- metadata +366 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
module Qwirk
|
|
2
|
+
|
|
3
|
+
# Defines some default marshaling strategies for use in marshaling/unmarshaling objects
|
|
4
|
+
# written and read via jms. Implementing classes must define the following methods:
|
|
5
|
+
#
|
|
6
|
+
# # Return symbol
|
|
7
|
+
# # :text if session.create_text_message should be used to generate the JMS message
|
|
8
|
+
# # :bytes if session.create_bytes_message should be used to generate the JMS message
|
|
9
|
+
# def marshal_type
|
|
10
|
+
# # Return either :text or :bytes
|
|
11
|
+
# :text
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# # Defines the conversion to wire format by the publisher of the message
|
|
15
|
+
# def marshal(object)
|
|
16
|
+
# # Operate on object and convert to message format
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# # Defines the conversion from wire format by the consumer of the message
|
|
20
|
+
# def unmarshal(msg)
|
|
21
|
+
# # Operate on message to convert it from wire protocol back to object format
|
|
22
|
+
# end
|
|
23
|
+
module MarshalStrategy
|
|
24
|
+
|
|
25
|
+
@options = {}
|
|
26
|
+
|
|
27
|
+
def self.find(marshaler)
|
|
28
|
+
if marshaler.nil?
|
|
29
|
+
return Ruby
|
|
30
|
+
else
|
|
31
|
+
val = @options[marshaler.to_sym]
|
|
32
|
+
return val if val
|
|
33
|
+
end
|
|
34
|
+
raise "Invalid marshal strategy: #{marshaler}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.registered?(marshaler)
|
|
38
|
+
@options.has_key?(marshaler.to_sym)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Allow user-defined marshal strategies. It can either be passed a hash of sym => marshaler or a list of marshalers
|
|
42
|
+
# that define the to_sym method which will be used as the key.
|
|
43
|
+
def self.register(*marshalers)
|
|
44
|
+
if marshalers.size == 1 && marshalers[0].kind_of?(Hash)
|
|
45
|
+
marshalers[0].each do |key, marshaler|
|
|
46
|
+
raise "Invalid marshal strategy: #{marshaler}" unless valid?(marshaler)
|
|
47
|
+
@options[key] = marshaler
|
|
48
|
+
end
|
|
49
|
+
else
|
|
50
|
+
marshalers.each do |marshaler|
|
|
51
|
+
raise "Invalid marshal strategy: #{marshaler}" unless valid?(marshaler) && marshaler.respond_to?(:to_sym)
|
|
52
|
+
@options[marshaler.to_sym] = marshaler
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.unregister(sym)
|
|
58
|
+
@options.delete(sym)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def self.valid?(marshaler)
|
|
62
|
+
return marshaler.respond_to?(:marshal_type) &&
|
|
63
|
+
marshaler.respond_to?(:marshal) &&
|
|
64
|
+
marshaler.respond_to?(:unmarshal)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
require 'qwirk/marshal_strategy/bson'
|
|
70
|
+
require 'qwirk/marshal_strategy/json'
|
|
71
|
+
require 'qwirk/marshal_strategy/none'
|
|
72
|
+
require 'qwirk/marshal_strategy/ruby'
|
|
73
|
+
require 'qwirk/marshal_strategy/string'
|
|
74
|
+
require 'qwirk/marshal_strategy/yaml'
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Qwirk
|
|
2
|
+
module MarshalStrategy
|
|
3
|
+
module BSON
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
def marshal_type
|
|
7
|
+
:bytes
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_sym
|
|
11
|
+
:bson
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
begin
|
|
15
|
+
require 'bson'
|
|
16
|
+
def marshal(object)
|
|
17
|
+
::BSON.serialize(object).to_s
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def unmarshal(msg)
|
|
21
|
+
::BSON.deserialize(msg)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
rescue LoadError => e
|
|
25
|
+
def marshal(object)
|
|
26
|
+
raise 'Error: BSON marshaling specified but bson gem has not been installed'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def unmarshal(msg)
|
|
30
|
+
raise 'Error: BSON marshaling specified but bson gem has not been installed'
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
MarshalStrategy.register(self)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Qwirk
|
|
2
|
+
module MarshalStrategy
|
|
3
|
+
module JSON
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
def marshal_type
|
|
7
|
+
:text
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_sym
|
|
11
|
+
:json
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
begin
|
|
15
|
+
require 'json'
|
|
16
|
+
def marshal(object)
|
|
17
|
+
object.to_json
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def unmarshal(msg)
|
|
21
|
+
::JSON::Parser.new(msg).parse
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
rescue LoadError => e
|
|
25
|
+
def marshal(object)
|
|
26
|
+
raise 'Error: JSON marshaling specified but json gem has not been installed'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def unmarshal(msg)
|
|
30
|
+
raise 'Error: JSON marshaling specified but json gem has not been installed'
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
MarshalStrategy.register(self)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Qwirk
|
|
2
|
+
module MarshalStrategy
|
|
3
|
+
# Should only be used with InMem strategy
|
|
4
|
+
module None
|
|
5
|
+
extend self
|
|
6
|
+
|
|
7
|
+
def marshal_type
|
|
8
|
+
:bytes
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def to_sym
|
|
12
|
+
:none
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def marshal(object)
|
|
16
|
+
object
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def unmarshal(msg)
|
|
20
|
+
msg
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
MarshalStrategy.register(self)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Qwirk
|
|
2
|
+
module MarshalStrategy
|
|
3
|
+
module Ruby
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
def marshal_type
|
|
7
|
+
:bytes
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_sym
|
|
11
|
+
:ruby
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def marshal(object)
|
|
15
|
+
::Marshal.dump(object)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def unmarshal(msg)
|
|
19
|
+
msg = ::String.from_java_bytes(msg) unless msg.kind_of?(::String)
|
|
20
|
+
::Marshal.load(msg)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
MarshalStrategy.register(self)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Qwirk
|
|
2
|
+
module MarshalStrategy
|
|
3
|
+
module String
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
def marshal_type
|
|
7
|
+
:text
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_sym
|
|
11
|
+
:string
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def marshal(object)
|
|
15
|
+
object.to_s
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def unmarshal(msg)
|
|
19
|
+
msg
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
MarshalStrategy.register(self)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Qwirk
|
|
2
|
+
module MarshalStrategy
|
|
3
|
+
module YAML
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
def marshal_type
|
|
7
|
+
:text
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_sym
|
|
11
|
+
:yaml
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def marshal(object)
|
|
15
|
+
object.to_yaml
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def unmarshal(msg)
|
|
19
|
+
::YAML.load(msg)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
MarshalStrategy.register(self)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
require 'timeout'
|
|
2
|
+
|
|
3
|
+
module Qwirk
|
|
4
|
+
class PublishHandle
|
|
5
|
+
def initialize(publisher, adapter_info, start)
|
|
6
|
+
@producer = publisher
|
|
7
|
+
@adapter_info = adapter_info
|
|
8
|
+
@start = start
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Waits the given timeout for a response message on the queue.
|
|
12
|
+
#
|
|
13
|
+
# If called w/o a block:
|
|
14
|
+
# Returns the message
|
|
15
|
+
# Returns nil on timeout
|
|
16
|
+
# Raises RemoteException on a remote exception
|
|
17
|
+
#
|
|
18
|
+
# If called with a block, for instance:
|
|
19
|
+
# handle.read_response(timeout) do |response|
|
|
20
|
+
# response.on_message 'CharCount' do |hash|
|
|
21
|
+
# puts "CharCount returned #{hash.inspect}"
|
|
22
|
+
# end
|
|
23
|
+
# response.on_message 'Length', 'Reverse' do |val|
|
|
24
|
+
# puts "#{response.name} returned #{val}"
|
|
25
|
+
# end
|
|
26
|
+
# response.on_message 'ExceptionRaiser' do |val|
|
|
27
|
+
# puts "#{response.name} didn't raise an exception but returned #{val}"
|
|
28
|
+
# end
|
|
29
|
+
# response.on_timeout 'Reverse' do
|
|
30
|
+
# puts "Reverse has it's own timeout handler"
|
|
31
|
+
# end
|
|
32
|
+
# response.on_timeout do
|
|
33
|
+
# puts "#{response.name} did not respond in time"
|
|
34
|
+
# end
|
|
35
|
+
# response.on_remote_exception 'ExceptionRaiser' do
|
|
36
|
+
# puts "It figures that ExceptionRaiser would raise an exception"
|
|
37
|
+
# end
|
|
38
|
+
# response.on_remote_exception do |e|
|
|
39
|
+
# puts "#{response.name} raised an exception #{e.message}\n\t#{e.backtrace.join("\n\t")}"
|
|
40
|
+
# end
|
|
41
|
+
# end
|
|
42
|
+
#
|
|
43
|
+
# The specified blocks will be called for each response. For instance, LengthWorker#request
|
|
44
|
+
# might return 4 and "Length returned 4" would be displayed. If it failed to respond within the
|
|
45
|
+
# timeout, then "Length did no respond in time" would be displayed.
|
|
46
|
+
# For Workers that raise an exception, they will either be handled by their specific handler if it exists or
|
|
47
|
+
# the default exception handler. If that doesn't exist either, then the RemoteException will be raised for the
|
|
48
|
+
# whole read_response call. Timeouts will also be handled by the default timeout handler unless a specific one
|
|
49
|
+
# is specified. All messages must have a specific handler specified because the call won't return until all
|
|
50
|
+
# specified handlers either return, timeout, or return an exception.
|
|
51
|
+
#
|
|
52
|
+
def read_response(timeout, &block)
|
|
53
|
+
raise "Invalid call to read_response for #{@producer}, not setup for responding" unless @producer.response_options
|
|
54
|
+
# Creates a block for reading the responses for a given message_id (adapter_info). The block will be passed an object
|
|
55
|
+
# that responds to timeout_read(timeout) with a [original_message_id, response_message, worker_name] tri or nil if no message is read.
|
|
56
|
+
# This is used in the RPC mechanism where a publish might wait for 1 or more workers to respond.
|
|
57
|
+
@producer.adapter.with_response(@adapter_info) do |consumer|
|
|
58
|
+
if block_given?
|
|
59
|
+
return read_multiple_response(consumer, timeout, &block)
|
|
60
|
+
else
|
|
61
|
+
response = read_single_response(consumer, timeout)
|
|
62
|
+
raise response if response.kind_of?(Qwirk::RemoteException)
|
|
63
|
+
return response
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
#######
|
|
69
|
+
private
|
|
70
|
+
#######
|
|
71
|
+
|
|
72
|
+
def read_single_response(consumer, timeout)
|
|
73
|
+
leftover_timeout = @start + timeout - Time.now
|
|
74
|
+
message_id, response, @worker_name = consumer.timeout_read(leftover_timeout)
|
|
75
|
+
return response
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def read_multiple_response(consumer, timeout, &block)
|
|
79
|
+
worker_response = WorkerResponse.new(@start)
|
|
80
|
+
yield worker_response
|
|
81
|
+
|
|
82
|
+
until worker_response.done? do
|
|
83
|
+
response = read_single_response(consumer, timeout)
|
|
84
|
+
if !response
|
|
85
|
+
worker_response.make_timeout_calls
|
|
86
|
+
return
|
|
87
|
+
end
|
|
88
|
+
if response.kind_of?(Qwirk::RemoteException)
|
|
89
|
+
worker_response.make_exception_call(@worker_name, response)
|
|
90
|
+
else
|
|
91
|
+
worker_response.make_message_call(@worker_name, response)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
class WorkerResponse
|
|
97
|
+
attr_reader :name, :start
|
|
98
|
+
|
|
99
|
+
def initialize(start)
|
|
100
|
+
@start = start
|
|
101
|
+
@message_hash = {}
|
|
102
|
+
@timeout_hash = {}
|
|
103
|
+
@exception_hash = {}
|
|
104
|
+
@default_timeout_block = nil
|
|
105
|
+
@default_exception_block = nil
|
|
106
|
+
@done_array = []
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Msecs since publish
|
|
110
|
+
def msec_delta
|
|
111
|
+
(Time.now - @start) * 1000
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def on_message(*names, &block)
|
|
115
|
+
raise 'Must explicitly define all message handlers so we know that we\'re done' if names.empty?
|
|
116
|
+
names.each {|name| @message_hash[name] = block}
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def on_timeout(*names, &block)
|
|
120
|
+
if names.empty?
|
|
121
|
+
@default_timeout_block = block
|
|
122
|
+
else
|
|
123
|
+
names.each {|name| @timeout_hash[name] = block}
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def on_remote_exception(*names, &block)
|
|
128
|
+
if names.empty?
|
|
129
|
+
@default_exception_block = block
|
|
130
|
+
else
|
|
131
|
+
names.each {|name| @exception_hash[name] = block}
|
|
132
|
+
end
|
|
133
|
+
@remote_exception_block = block
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def make_message_call(name, obj)
|
|
137
|
+
# Give the client access to the name
|
|
138
|
+
@name = name
|
|
139
|
+
block = @message_hash[name]
|
|
140
|
+
block.call(obj) if block
|
|
141
|
+
@done_array << name
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def done?
|
|
145
|
+
(@message_hash.keys - @done_array).empty?
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def make_timeout_calls
|
|
149
|
+
@timeouts = @message_hash.keys - @done_array
|
|
150
|
+
@timeouts.each do |name|
|
|
151
|
+
# Give the client access to the name
|
|
152
|
+
@name = name
|
|
153
|
+
block = @timeout_hash[name] || @default_timeout_block
|
|
154
|
+
block.call if block
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def make_exception_call(name, e)
|
|
159
|
+
@name = name
|
|
160
|
+
block = @exception_hash[name] || @default_exception_block
|
|
161
|
+
if block
|
|
162
|
+
block.call(e)
|
|
163
|
+
@done_array << name
|
|
164
|
+
else
|
|
165
|
+
raise e
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Protocol independent class to handle Publishing
|
|
2
|
+
module Qwirk
|
|
3
|
+
class Publisher
|
|
4
|
+
include Rumx::Bean
|
|
5
|
+
|
|
6
|
+
#attr_reader :producer_options, :persistent, :reply_queue
|
|
7
|
+
attr_reader :response_options, :adapter, :marshaler
|
|
8
|
+
|
|
9
|
+
bean_attr_reader :tasks, :hash, 'Hash of the latest tasks', :hash_type => :bean
|
|
10
|
+
|
|
11
|
+
# Parameters:
|
|
12
|
+
# One of the following must be specified
|
|
13
|
+
# :queue_name => String: Name of the Queue to publish to
|
|
14
|
+
# :topic_name => String: Name of the Topic to publish to
|
|
15
|
+
# Optional:
|
|
16
|
+
# :time_to_live => expiration time in ms for the message (JMS)
|
|
17
|
+
# :persistent => true or false (defaults to false) (JMS)
|
|
18
|
+
# :marshal => Symbol: One of :ruby, :string, :json, :bson, :yaml or any registered types (See Qwirk::MarshalStrategy), defaults to :ruby
|
|
19
|
+
# :response => if true or a hash of response options, a temporary reply queue will be setup for handling responses
|
|
20
|
+
# :time_to_live => expiration time in ms for the response message(s) (JMS))
|
|
21
|
+
# :persistent => true or false for the response message(s), set to false if you don't want timed out messages ending up in the DLQ (defaults to true unless time_to_live is set)
|
|
22
|
+
def initialize(queue_adapter, options)
|
|
23
|
+
options = options.dup
|
|
24
|
+
@queue_name = options.delete(:queue_name)
|
|
25
|
+
@topic_name = options.delete(:topic_name)
|
|
26
|
+
raise "One of :queue_name or :topic_name must be given in #{self.class.name}" if !@queue_name && !@topic_name
|
|
27
|
+
|
|
28
|
+
@response_options = options.delete(:response)
|
|
29
|
+
# response_options should only be a hash or the values true or false
|
|
30
|
+
@response_options = {} if @response_options && !@response_options.kind_of?(Hash)
|
|
31
|
+
|
|
32
|
+
@tasks = {}
|
|
33
|
+
@adapter = queue_adapter.create_adapter_publisher(@queue_name, @topic_name, options, @response_options)
|
|
34
|
+
marshal_sym = options[:marshal] || :ruby
|
|
35
|
+
@marshaler = Qwirk::MarshalStrategy.find(marshal_sym)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Publish the given object to the address.
|
|
39
|
+
def publish(object, props={})
|
|
40
|
+
start = Time.now
|
|
41
|
+
marshaled_object = @marshaler.marshal(object)
|
|
42
|
+
adapter_info = @adapter.publish(marshaled_object, @marshaler, nil, props)
|
|
43
|
+
return PublishHandle.new(self, adapter_info, start)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Creates a producer/consumer pair for writing and reading responses for a given task. It will return a pair of
|
|
47
|
+
# [producer, consumer]. The producer will publish objects specifically for the task. The consumer is an object that responds_to
|
|
48
|
+
# receive which will return a [message_id, response object] and acknowledge_message which will acknowledge the
|
|
49
|
+
# last message read. It should also respond to stop which will interrupt any receive calls causing it to return nil.
|
|
50
|
+
def create_producer_consumer_pair(task)
|
|
51
|
+
@tasks[task.task_id] = task
|
|
52
|
+
@adapter.create_producer_consumer_pair(task.task_id, @marshaler)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def to_s
|
|
56
|
+
"#{self.class.name}:#{@queue_name || @topic_name}"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def default_fail_queue_name
|
|
60
|
+
Qwirk.fail_queue_name(@queue_name || @topic_name)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def create_fail_queue_consumer(fail_queue_name=nil)
|
|
64
|
+
fail_queue_name ||= default_fail_queue_name
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|