modern_times 0.1.2 → 0.2.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 (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