modern_times 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/README.rdoc +24 -12
  2. data/Rakefile +2 -2
  3. data/VERSION +1 -1
  4. data/examples/README +4 -0
  5. data/examples/jms.yml +9 -0
  6. data/examples/requestor/README +4 -2
  7. data/examples/requestor/manager.rb +3 -2
  8. data/examples/requestor/request.rb +5 -4
  9. data/examples/requestor/reverse_echo_worker.rb +3 -2
  10. data/examples/simple/README +7 -4
  11. data/examples/simple/bar_worker.rb +4 -1
  12. data/examples/simple/baz_worker.rb +4 -3
  13. data/examples/simple/manager.rb +3 -2
  14. data/examples/simple/publish.rb +6 -5
  15. data/lib/modern_times.rb +20 -2
  16. data/lib/modern_times/base/supervisor.rb +14 -21
  17. data/lib/modern_times/base/supervisor_mbean.rb +4 -6
  18. data/lib/modern_times/base/worker.rb +17 -26
  19. data/lib/modern_times/jms.rb +23 -0
  20. data/lib/modern_times/{hornetq/client.rb → jms/connection.rb} +19 -12
  21. data/lib/modern_times/jms/publisher.rb +91 -0
  22. data/lib/modern_times/jms/supervisor.rb +19 -0
  23. data/lib/modern_times/jms/supervisor_mbean.rb +11 -0
  24. data/lib/modern_times/jms/worker.rb +166 -0
  25. data/lib/modern_times/jms_requestor.rb +10 -0
  26. data/lib/modern_times/jms_requestor/request_handle.rb +33 -0
  27. data/lib/modern_times/jms_requestor/requestor.rb +45 -0
  28. data/lib/modern_times/jms_requestor/supervisor.rb +45 -0
  29. data/lib/modern_times/jms_requestor/supervisor_mbean.rb +21 -0
  30. data/lib/modern_times/jms_requestor/worker.rb +78 -0
  31. data/lib/modern_times/manager.rb +14 -9
  32. data/lib/modern_times/manager_mbean.rb +14 -7
  33. data/lib/modern_times/marshal_strategy.rb +47 -0
  34. data/lib/modern_times/marshal_strategy/bson.rb +31 -0
  35. data/lib/modern_times/marshal_strategy/json.rb +30 -0
  36. data/lib/modern_times/marshal_strategy/ruby.rb +20 -0
  37. data/lib/modern_times/marshal_strategy/string.rb +19 -0
  38. data/lib/modern_times/railsable.rb +17 -74
  39. data/test/base_test.rb +248 -0
  40. data/test/jms.yml +8 -0
  41. data/test/jms_requestor_test.rb +263 -0
  42. data/test/jms_test.rb +296 -0
  43. data/test/marshal_strategy_test.rb +39 -0
  44. metadata +49 -46
  45. data/examples/requestor/hornetq.yml +0 -14
  46. data/examples/simple/hornetq.yml +0 -14
  47. data/lib/modern_times/hornetq.rb +0 -11
  48. data/lib/modern_times/hornetq/marshal_strategy.rb +0 -3
  49. data/lib/modern_times/hornetq/marshal_strategy/json.rb +0 -17
  50. data/lib/modern_times/hornetq/marshal_strategy/ruby.rb +0 -17
  51. data/lib/modern_times/hornetq/marshal_strategy/string.rb +0 -17
  52. data/lib/modern_times/hornetq/publisher.rb +0 -65
  53. data/lib/modern_times/hornetq/supervisor.rb +0 -22
  54. data/lib/modern_times/hornetq/supervisor_mbean.rb +0 -12
  55. data/lib/modern_times/hornetq/worker.rb +0 -127
  56. data/lib/modern_times/hornetq_requestor.rb +0 -9
  57. data/lib/modern_times/hornetq_requestor/request_handle.rb +0 -49
  58. data/lib/modern_times/hornetq_requestor/requestor.rb +0 -48
  59. data/lib/modern_times/hornetq_requestor/worker.rb +0 -29
  60. data/lib/modern_times/thread.rb +0 -16
  61. data/test/base/worker_test.rb +0 -38
  62. data/test/messaging/worker_manager_test.rb +0 -58
  63. data/test/messaging/worker_test.rb +0 -58
  64. data/test/worker_manager_test.rb +0 -48
@@ -1,14 +0,0 @@
1
- server:
2
- :uri: hornetq://localhost
3
- :data_directory: ./data
4
- :persistence_enabled: true
5
- :security_enabled: true
6
- :cluster_user: myuser
7
- :cluster_password: mypassword
8
-
9
- client:
10
- :connection:
11
- :uri: hornetq://localhost
12
- :session:
13
- :username: myuser
14
- :password: mypassword
@@ -1,14 +0,0 @@
1
- server:
2
- :uri: hornetq://localhost
3
- :data_directory: ./data
4
- :persistence_enabled: true
5
- :security_enabled: true
6
- :cluster_user: myuser
7
- :cluster_password: mypassword
8
-
9
- client:
10
- :connection:
11
- :uri: hornetq://localhost
12
- :session:
13
- :username: myuser
14
- :password: mypassword
@@ -1,11 +0,0 @@
1
- require 'modern_times/hornetq/client'
2
- require 'modern_times/hornetq/marshal_strategy'
3
- require 'modern_times/hornetq/publisher'
4
- require 'modern_times/hornetq/supervisor_mbean'
5
- require 'modern_times/hornetq/supervisor'
6
- require 'modern_times/hornetq/worker'
7
-
8
- module ModernTimes
9
- module HornetQ
10
- end
11
- end
@@ -1,3 +0,0 @@
1
- require 'modern_times/hornetq/marshal_strategy/json'
2
- require 'modern_times/hornetq/marshal_strategy/ruby'
3
- require 'modern_times/hornetq/marshal_strategy/string'
@@ -1,17 +0,0 @@
1
- module ModernTimes
2
- module HornetQ
3
- module MarshalStrategy
4
- module JSON
5
- def marshal(session, object, durable)
6
- message = session.create_message(::HornetQ::Client::Message::TEXT_TYPE, durable)
7
- message.body = object.to_json
8
- message
9
- end
10
-
11
- def unmarshal(msg)
12
- JSON::Parser.new(msg.body).parse
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,17 +0,0 @@
1
- module ModernTimes
2
- module HornetQ
3
- module MarshalStrategy
4
- module Ruby
5
- def marshal(session, object, durable)
6
- message = session.create_message(::HornetQ::Client::Message::BYTES_TYPE, durable)
7
- message.body = ::Marshal.dump(object)
8
- message
9
- end
10
-
11
- def unmarshal(msg)
12
- ::Marshal.load(msg.body)
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,17 +0,0 @@
1
- module ModernTimes
2
- module HornetQ
3
- module MarshalStrategy
4
- module String
5
- def marshal(session, object, durable)
6
- message = session.create_message(::HornetQ::Client::Message::TEXT_TYPE, durable)
7
- message.body = object.to_s
8
- message
9
- end
10
-
11
- def unmarshal(msg)
12
- msg.body
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,65 +0,0 @@
1
- require 'hornetq'
2
-
3
- # Protocol independent class to handle Publishing
4
- module ModernTimes
5
- module HornetQ
6
- class Publisher
7
- attr_reader :address
8
-
9
- # TODO: Possible performance enhancements on producer
10
- # setDisableMessageID()
11
- # setDisableMessageTimeStamp()
12
- # See http://hornetq.sourceforge.net/docs/hornetq-2.1.2.Final/user-manual/en/html/perf-tuning.html
13
- # Create producer pool as per above section 46.6?
14
- def initialize(address, options={})
15
- @address = address
16
- @durable = !!options[:durable]
17
- if options[:marshal].nil?
18
- marshal_module = MarshalStrategy::Ruby
19
- elsif options[:marshal].kind_of? Symbol
20
- marshal_module = case options[:marshal]
21
- when :ruby then MarshalStrategy::Ruby
22
- when :string then MarshalStrategy::String
23
- when :json then MarshalStrategy::JSON
24
- else raise "Invalid marshal strategy: #{options[:marshal]}"
25
- end
26
- elsif options[:marshal].kind_of? Module
27
- marshal_module = options[:marshal]
28
- else
29
- raise "Invalid marshal strategy: #{options[:marshal]}"
30
- end
31
- self.extend marshal_module
32
- end
33
-
34
- # Publish the given object to the address.
35
- def publish(object, user_id=nil, props={})
36
- Client.session_pool.producer(@address) do |session, producer|
37
- message = marshal(session, object, @durable)
38
- message.user_id = user_id if user_id
39
- props.each do |key, value|
40
- message.putStringProperty(key, value)
41
- end
42
- producer.send_with_retry(message)
43
- end
44
- end
45
-
46
- # For non-configured Rails projects, The above publish method will be overridden to
47
- # call this publish method instead which calls all the HornetQ workers that
48
- # operate on the given address.
49
- def dummy_publish(object)
50
- @@worker_instances.each do |worker|
51
- if worker.kind_of?(Worker) && worker.address_name == @address
52
- ModernTimes.logger.debug "Dummy publishing #{object} to #{worker}"
53
- worker.perform(object)
54
- end
55
- end
56
- end
57
-
58
- def self.setup_dummy_publishing(workers)
59
- @@worker_instances = workers.map {|worker| worker.new}
60
- alias_method :real_publish, :publish
61
- alias_method :publish, :dummy_publish
62
- end
63
- end
64
- end
65
- end
@@ -1,22 +0,0 @@
1
- module ModernTimes
2
- module HornetQ
3
- class Supervisor < ModernTimes::Base::Supervisor
4
- # Make HornetQ::SupervisorMBean our mbean
5
- mbean SupervisorMBean
6
-
7
- attr_reader :message_count
8
-
9
- def initialize(manager, worker_name, supervisor_options, worker_options)
10
- super
11
- @message_count = 0
12
- @message_count_mutex = Mutex.new
13
- end
14
-
15
- def incr_message_count
16
- @message_count_mutex.synchronize do
17
- @message_count += 1
18
- end
19
- end
20
- end
21
- end
22
- end
@@ -1,12 +0,0 @@
1
- module ModernTimes
2
- module HornetQ
3
- class SupervisorMBean < ModernTimes::Base::SupervisorMBean
4
- r_attribute :message_count, :int, 'Total message count', :message_count
5
-
6
- def message_count
7
- supervisor.message_count
8
- end
9
-
10
- end
11
- end
12
- end
@@ -1,127 +0,0 @@
1
- module ModernTimes
2
- module HornetQ
3
-
4
- # Base Worker Class for any class that will be processing messages from queues
5
- class Worker < ModernTimes::Base::Worker
6
- # Default to ruby marshaling, but extenders can override as necessary
7
- include MarshalStrategy::Ruby
8
-
9
- # Make HornetQ::Supervisor our supervisor
10
- supervisor Supervisor
11
-
12
- attr_reader :session, :message_count
13
-
14
- def initialize(opts={})
15
- super
16
- @status = 'initialized'
17
- @message_count = 0
18
- end
19
-
20
- def setup
21
- session = Client.create_consumer_session
22
- session.create_queue_ignore_exists(address_name, queue_name, false)
23
- session.close
24
- end
25
-
26
- def status
27
- @status || "Processing message #{message_count}"
28
- end
29
-
30
- def on_message(message)
31
- object = unmarshal(message)
32
- ModernTimes.logger.debug "#{self}: Received Object: #{object}" if ModernTimes.logger.debug?
33
- perform(object)
34
- ModernTimes.logger.debug "#{self}: Finished processing message" if ModernTimes.logger.debug?
35
- ModernTimes.logger.flush if ModernTimes.logger.respond_to?(:flush)
36
- rescue Exception => e
37
- ModernTimes.logger.error "#{self}: Messaging Exception: #{e.inspect}\n#{e.backtrace.inspect}"
38
- rescue java.lang.Exception => e
39
- ModernTimes.logger.error "#{self}: Java Messaging Exception: #{e.inspect}\n#{e.backtrace.inspect}"
40
- end
41
-
42
- def perform(object)
43
- raise "#{self}: Need to override perform method in #{self.class.name} in order to act on #{object}"
44
- end
45
-
46
- def self.address_name
47
- @address_name ||= default_name
48
- end
49
-
50
- def self.queue_name
51
- @queue_name ||= default_name
52
- end
53
-
54
- def address_name
55
- self.class.address_name
56
- end
57
-
58
- def queue_name
59
- self.class.queue_name
60
- end
61
-
62
- def to_s
63
- "#{address_name}:#{queue_name}:#{index}"
64
- end
65
-
66
- # Start the event loop for handling messages off the queue
67
- def start
68
- session_init
69
- ModernTimes.logger.debug "#{self}: Starting receive loop"
70
- @status = nil
71
- while msg = @consumer.receive
72
- @message_count += 1
73
- supervisor.incr_message_count
74
- on_message(msg)
75
- msg.acknowledge
76
- end
77
- @status = 'Exited'
78
- ModernTimes.logger.info "Exiting #{self}"
79
- rescue Java::org.hornetq.api.core.HornetQException => e
80
- if e.cause.code == Java::org.hornetq.api.core.HornetQException::OBJECT_CLOSED
81
- # Normal exit
82
- @status = 'Exited'
83
- ModernTimes.logger.info "#{self}: Exiting due to close"
84
- else
85
- @status = "Exited with HornetQ exception #{e.message}"
86
- ModernTImes.logger.error "#{self} HornetQException: #{e.message}\n#{e.backtrace.join("\n")}"
87
- end
88
- rescue Exception => e
89
- @status = "Exited with exception #{e.message}"
90
- ModernTimes.logger.error "#{self}: Exception, thread terminating: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
91
- rescue java.lang.Exception => e
92
- @status = "Exited with java exception #{e.message}"
93
- ModernTimes.logger.error "#{self}: Java exception, thread terminating: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
94
- end
95
-
96
- def stop
97
- @session.close if @session
98
- end
99
-
100
- #########
101
- protected
102
- #########
103
-
104
- # Create session information and allow extenders to initialize anything necessary prior to the event loop
105
- def session_init
106
- @session = Client.create_consumer_session
107
- @consumer = @session.create_consumer(queue_name)
108
- @session.start
109
- end
110
-
111
- # Create a queue, assigned to the specified address
112
- # Every time a message arrives, the perform instance method
113
- # will be called. The parameter to the method is the Ruby
114
- # object supplied when the message was sent
115
- def self.address(address_name, opts={})
116
- @address_name = address_name.to_s
117
- #Messaging::Client.on_message(address, queue_name) do |object|
118
- # self.send(method.to_sym, object)
119
- #end
120
- end
121
-
122
- def self.queue(queue_name, opts={})
123
- @queue_name = queue_name.to_s
124
- end
125
- end
126
- end
127
- end
@@ -1,9 +0,0 @@
1
- require 'modern_times/hornetq_requestor/request_handle'
2
- require 'modern_times/hornetq_requestor/requestor'
3
- require 'modern_times/hornetq_requestor/worker'
4
-
5
- module ModernTimes
6
- module HornetQRequestor
7
- MESSAGE_ID = 'ModernTimesMessageId'
8
- end
9
- end
@@ -1,49 +0,0 @@
1
- require 'timeout'
2
-
3
- module ModernTimes
4
- module HornetQRequestor
5
- class RequestHandle
6
- def initialize(requestor, message_id, start, timeout)
7
- @requestor = requestor
8
- @reply_queue = requestor.reply_queue
9
- @message_id = message_id
10
- @start = start
11
- @timeout = timeout
12
- end
13
-
14
- def read_response
15
- message = nil
16
- leftover_timeout = ((@start + @timeout - Time.now) * 1000).to_i
17
- ModernTimes::HornetQ::Client.session_pool.session do |s|
18
- consumer = nil
19
- begin
20
- consumer = s.create_consumer(@reply_queue, "#{MESSAGE_ID}='#{@message_id}'")
21
- if leftover_timeout > 0
22
- message = consumer.receive(leftover_timeout)
23
- else
24
- message = consumer.receive(1)
25
- end
26
- puts "funked at #{Time.now.to_f}" unless message
27
- consumer.receive_immediate unless message
28
- ensure
29
- consumer.close if consumer
30
- end
31
- end
32
- raise Timeout::Error, "Timeout waiting for message #{@message_id} on queue #{@reply_queue}" unless message
33
- return @requestor.unmarshal(message)
34
- end
35
- end
36
- end
37
- end
38
-
39
- #handle = Intercept::Client.async_cair(bank_account_array, tracking_number, timeout)
40
- #... do other stuff ...
41
- #begin
42
- # # Following call will block until the queue receives the reply or what's left of the timeout expires
43
- # intercept_statuses = handle.read_response
44
- # ... process intercept statuses ...
45
- #rescue Timeout::Error => e
46
- # Rails.logger.warn "We didn't receive a reply back on the queue in time"
47
- #rescue Intercept::Error => e
48
- # Rails.logger.warn "Error during intercept call: #{e.message}"
49
- #end
@@ -1,48 +0,0 @@
1
- module ModernTimes
2
- module HornetQRequestor
3
- class Requestor < ModernTimes::HornetQ::Publisher
4
- attr_reader :reply_queue
5
-
6
- def initialize(address, options={})
7
- super
8
- @reply_queue = "#{address}.#{Java::java.util::UUID.randomUUID.toString}"
9
- @reply_queue_simple = Java::org.hornetq.api.core.SimpleString.new(@reply_queue)
10
- ModernTimes::HornetQ::Client.session_pool.session do |session|
11
- session.create_temporary_queue(@reply_queue, @reply_queue)
12
- end
13
- end
14
-
15
- def request(object, timeout)
16
- start = Time.now
17
- message_id = Java::org.hornetq.utils.UUIDGenerator.instance.generateUUID.toString
18
- publish(object,
19
- nil,
20
- MESSAGE_ID => message_id,
21
- Java::OrgHornetqCoreClientImpl::ClientMessageImpl::REPLYTO_HEADER_NAME => @reply_queue_simple)
22
- #HornetQMessage.CORRELATIONID_HEADER_NAME
23
- #REPLY_QUEUE => @reply_queue,
24
- #MESSAGE_ID => message_id)
25
- return RequestHandle.new(self, message_id, start, timeout)
26
- end
27
-
28
- # For non-configured Rails projects, The above request method will be overridden to
29
- # call this request method instead which calls all the HornetQ workers that
30
- # operate on the given address.
31
- def dummy_request(object)
32
- @@worker_instances.each do |worker|
33
- if worker.kind_of?(Worker) && worker.address_name == address
34
- ModernTimes.logger.debug "Dummy requesting #{object} to #{worker}"
35
- return new OpenStruct(:read_response => worker.request(object))
36
- end
37
- end
38
- raise "No worker to handle #{address} request of #{object}"
39
- end
40
-
41
- def self.setup_dummy_requesting(workers)
42
- @@worker_instances = workers.map {|worker| worker.new}
43
- alias_method :real_request, :request
44
- alias_method :request, :dummy_request
45
- end
46
- end
47
- end
48
- end