jruby-hornetq 0.2.3.alpha → 0.2.5.alpha

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/README.md CHANGED
@@ -44,6 +44,8 @@ HornetQ
44
44
 
45
45
  For information on the HornetQ messaging and queuing system, see:
46
46
 
47
+ For more documentation on any of the classes, see: http://hornetq.sourceforge.net/docs/hornetq-2.1.0.Final/api/index.html?org/hornetq/api/core/client/package-summary.html
48
+
47
49
  Concepts & Terminology
48
50
  ----------------------
49
51
 
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ desc "Build gem"
8
8
  task :gem do |t|
9
9
  gemspec = Gem::Specification.new do |s|
10
10
  s.name = 'jruby-hornetq'
11
- s.version = '0.2.3.alpha'
11
+ s.version = '0.2.5.alpha'
12
12
  s.authors = ['Reid Morrison', 'Brad Pardee']
13
13
  s.email = ['rubywmq@gmail.com', 'bpardee@gmail.com']
14
14
  s.homepage = 'https://github.com/ClarityServices/jruby-hornetq'
@@ -14,7 +14,6 @@ constants = config['constants']
14
14
 
15
15
  # Create a HornetQ session
16
16
  HornetQ::Client::Factory.session(config['client']) do |session|
17
- session.delete_queue(constants[:queue]) rescue nil
18
17
  session.create_queue(constants[:address], constants[:queue], constants[:durable])
19
18
  producer = session.create_producer(constants[:address])
20
19
  start_time = Time.now
@@ -25,7 +25,7 @@ request_address = 'jms.queue.ExampleQueue'
25
25
 
26
26
  config = YAML.load_file(File.dirname(__FILE__) + '/hornetq.yml')['development']
27
27
 
28
- class BatchClient
28
+ class BatchClientPattern
29
29
  def initialize(session, request_address)
30
30
  @producer = session.create_producer(request_address)
31
31
  reply_queue = "#{request_address}.#{Java::java.util::UUID.randomUUID.toString}"
@@ -62,7 +62,7 @@ class BatchClient
62
62
  #print "Sending #{total_count} messages"
63
63
  start_time = Time.now
64
64
  total_count.times do |i|
65
- message = @session.create_message(HornetQ::Client::Message::TEXT_TYPE,false)
65
+ message = @session.create_message(HornetQ::Client::Message::TEXT_TYPE,true)
66
66
  message.reply_to_queue_name = @consumer.queue_name
67
67
  message.body = "Request Current Time. #{i}"
68
68
  @producer.send(message)
@@ -99,7 +99,7 @@ end
99
99
  HornetQ::Client::Factory.session(config) do |session|
100
100
  batching_size = total_count if batching_size > total_count
101
101
 
102
- client = BatchClient.new(session, request_address)
102
+ client = BatchClientPattern.new(session, request_address)
103
103
 
104
104
  # Start receive thread
105
105
  receive_thread = Thread.new {client.receive}
@@ -0,0 +1,197 @@
1
+ # Allow examples to be run in-place without requiring a gem install
2
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../../lib'
3
+
4
+ require 'rubygems'
5
+ require 'resque/job_with_status' # in rails you would probably do this in an initializer
6
+ require 'yaml'
7
+ require 'hornetq'
8
+ require 'sync'
9
+
10
+ # The Batch Client Pattern submits requests to a server following the Server Pattern
11
+ #
12
+ # A good example of when to use the Batch Client Pattern is when processing large
13
+ # batch files. Rather than just flood the queue with every record from a file
14
+ # the Batch Client Pattern can be used to only send out a batch of requests at
15
+ # a time and when sufficient responses have been received, send another batch.
16
+ #
17
+ # The following additional features can be implemented in this pattern
18
+ # * Stop the batch if say 80% of records fail in the first batch, etc.
19
+ # * Support pause and resume of batch processing
20
+ # * Support restart and recoverability
21
+ #
22
+ # See the Resque example for implementations of some of the above capabilities
23
+ #
24
+ class BatchClientPattern
25
+ def initialize(session, request_address)
26
+ @producer = session.create_producer(request_address)
27
+ reply_queue = "#{request_address}.#{Java::java.util::UUID.randomUUID.toString}"
28
+ begin
29
+ session.create_temporary_queue(reply_queue, reply_queue)
30
+ rescue NativeException => exc
31
+ p exc
32
+ end
33
+ @consumer = session.create_consumer(reply_queue)
34
+ @session = session
35
+ session.start
36
+
37
+ @counter_sync = Sync.new
38
+ @processed = 0
39
+ end
40
+
41
+ # Before re-using a batch pattern, reset all internal counters
42
+ def reset
43
+ @counter_sync.synchronize(:EX) do
44
+ @failed = 0
45
+ @sucessful = 0
46
+ end
47
+ end
48
+
49
+ # Return the current message count
50
+ def processed
51
+ @counter_sync.synchronize(:SH) { @sucessful + @processed }
52
+ end
53
+
54
+ # Increment Successful response counter by supplied count
55
+ def inc_sucessful(count=1)
56
+ @counter_sync.synchronize(:EX) { @sucessful += count }
57
+ end
58
+
59
+ # Return the current message count
60
+ def sucessful
61
+ @counter_sync.synchronize(:SH) { @sucessful }
62
+ end
63
+
64
+ # Increment Successful response counter by supplied count
65
+ def inc_failed(count=1)
66
+ @counter_sync.synchronize(:EX) { @failed += count }
67
+ end
68
+
69
+ # Return the current message count
70
+ def failed
71
+ @counter_sync.synchronize(:SH) { @failed }
72
+ end
73
+
74
+ # Send x messages
75
+ def send(total_count)
76
+ #print "Sending #{total_count} messages"
77
+ start_time = Time.now
78
+ total_count.times do |i|
79
+ message = @session.create_message(HornetQ::Client::Message::TEXT_TYPE,false)
80
+ message.reply_to_queue_name = @consumer.queue_name
81
+ message.body = "Request Current Time. #{i}"
82
+ @producer.send(message)
83
+ print "."
84
+ #puts "Sent:#{message}"
85
+ end
86
+ duration = Time.now - start_time
87
+ #printf "\nSend %5d msg, %5.2f s, %10.2f msg/s\n", total_count, duration, total_count/duration
88
+ end
89
+
90
+ # Receive Reply messages calling the supplied block for each message
91
+ # passing in the message received from the server.
92
+ # After the block returns, the message is automatically acknowledged
93
+ def receive(&block)
94
+ print "Receiving messages"
95
+ raise "Missing mandatory block" unless block
96
+ begin
97
+ while reply = @consumer.receive
98
+ block.call(reply)
99
+ reply.acknowledge
100
+ end
101
+ rescue Exception => exc
102
+ p exc
103
+ end
104
+ end
105
+
106
+ def close
107
+ @producer.close
108
+ @consumer.close
109
+ @session.delete_queue(@consumer.queue_name)
110
+ end
111
+ end
112
+
113
+ # sleeps for _length_ seconds updating the status every second
114
+ #
115
+ #
116
+ # Create a Resque Job with the ability to report status
117
+ #
118
+ class HornetQJob < Resque::JobWithStatus
119
+
120
+ # Set the name of the queue to use for this Job Worker
121
+ @queue = "hornetq_job"
122
+
123
+ # Must be an instance method for Resque::JobWithStatus
124
+ def perform
125
+ total_count = (options['total_count'] || 4000).to_i
126
+ batching_size = (options['batching_size'] || 80).to_i
127
+ address = options['address'] || 'processor'
128
+ receive_thread = nil
129
+
130
+ # Create a HornetQ session
131
+ count = 0
132
+ HornetQ::Client::Factory.session('hornetq://localhost') do |session|
133
+ batching_size = total_count if batching_size > total_count
134
+
135
+ client = BatchClient.new(session, address)
136
+
137
+ # Start receive thread
138
+ receive_thread = Thread.new do
139
+ client.receive do |message|
140
+ print '@'
141
+ client.inc_sucessful
142
+ end
143
+ end
144
+
145
+ times = (total_count/batching_size).to_i
146
+ puts "Performing #{times} loops"
147
+ times.times do |i|
148
+ at(count, total_count, "At #{count} of #{total_count}")
149
+ client.send(batching_size)
150
+ count += batching_size
151
+ # Wait for at least 80% of responses
152
+ loop do
153
+ #puts "Waiting for receive"
154
+ sleep 0.1
155
+ received_count = client.counter
156
+ #puts "\nReceived #{received_count} messages"
157
+ if received_count >= 0.8 * count
158
+ puts ""
159
+ break
160
+ end
161
+ end
162
+ end
163
+
164
+ while client.counter < total_count
165
+ sleep 0.1
166
+ print "*"
167
+ end
168
+ client.close
169
+ end
170
+ receive_thread.kill if receive_thread
171
+ completed('num' => total_count, 'description' => "Completed #{count} of #{total_count}")
172
+ end
173
+
174
+ end
175
+
176
+ # Submit a new request at the command line
177
+ if __FILE__ == $0
178
+ # Make sure you have a worker running
179
+ # jruby resque_worker.rb
180
+
181
+ options = {
182
+ 'total_count' => (ARGV[0] || 4000).to_i,
183
+ 'batching_size' => (ARGV[1] || 40).to_i,
184
+ 'address' => 'processor'
185
+ }
186
+ # running the job
187
+ puts "Creating the HornetQJob"
188
+ job_id = HornetQJob.create(options)
189
+ puts "Got back #{job_id}"
190
+
191
+ # check the status until its complete
192
+ while status = Resque::Status.get(job_id) and !status.completed? && !status.failed? &&!status.killed?
193
+ sleep 1
194
+ puts status.inspect
195
+ end
196
+ puts status.inspect
197
+ end
@@ -0,0 +1,41 @@
1
+ #
2
+ # Processor:
3
+ # Process requests submitted by Resque Worker and reply
4
+ #
5
+
6
+ # Allow examples to be run in-place without requiring a gem install
7
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
8
+
9
+ require 'rubygems'
10
+ require 'hornetq'
11
+
12
+ # Let server shutdown on its own after 5 minutes of inactivity. Set to 0 to wait forever
13
+ timeout = (ARGV[0] || 300000).to_i
14
+
15
+ q_name = 'processor'
16
+
17
+ HornetQ::Client::Factory.start('hornetq://localhost') do |session|
18
+ begin
19
+ # Create durable queue with matching address
20
+ session.create_queue(q_name, q_name, true)
21
+ rescue
22
+ # Ignore when queue already exists
23
+ end
24
+
25
+ server = session.create_server(q_name, timeout)
26
+
27
+ puts "Waiting for Requests..."
28
+ server.run do |request_message|
29
+ print "."
30
+
31
+ # Create Reply Message
32
+ reply_message = session.create_message(HornetQ::Client::Message::TEXT_TYPE, false)
33
+ reply_message.body = "Echo [#{request_message.body}]"
34
+
35
+ # The result of the block is the message to be sent back, or nil if no reply
36
+ reply_message
37
+ end
38
+
39
+ # Server will stop after timeout period after no messages received. Set to 0 to wait forever
40
+ server.close
41
+ end
@@ -0,0 +1,33 @@
1
+ Overview
2
+
3
+ This example shows how to use Resque to initiate a Job which in turn submits all
4
+ its work to processors.
5
+
6
+ ## Architecture
7
+
8
+ The architecture for this example uses:
9
+ ### Initiator
10
+
11
+ An _initiator_ which enqueues the job to be completed
12
+
13
+ ### Resque Worker
14
+
15
+ A _resque worker_ which manages the job itself. The _resque worker_ in turn submits
16
+ requests to the _task worker_.
17
+
18
+ ### Processor
19
+
20
+ A _processor_ performs the actual work and receives its requests over a
21
+ hornetq queue. It replies back to the _resque worker_ when complete
22
+
23
+
24
+ Requirements
25
+
26
+ Install the following gems
27
+ * resque
28
+ * resque-status
29
+ ** https://github.com/quirkey/resque-status
30
+
31
+ Start the Resque Job worker
32
+
33
+ Start the Task workers
@@ -0,0 +1 @@
1
+ require 'resque/status_server'
@@ -0,0 +1,22 @@
1
+ # Start up a Resque Worker to run the Job Request
2
+ require 'rubygems'
3
+ require 'resque'
4
+ require 'resque/job_with_status'
5
+ require 'sleep_job'
6
+ require 'hornetq_job'
7
+
8
+ # Number of workers to start (each on its own thread)
9
+ thread_count = (ARGV[0] || 1).to_i
10
+
11
+ # Configure Redis client connection
12
+ Resque.redis = "localhost:6379"
13
+
14
+ # How long to keep Job status for in seconds
15
+ Resque::Status.expire_in = (24 * 60 * 60) # 24hrs in seconds
16
+
17
+ # Start the worker instance(s) in which Jobs are run
18
+ resque_worker = Resque::Worker.new("hornetq_job")
19
+ resque_worker.log "Starting worker #{resque_worker}"
20
+ resque_worker.verbose = true
21
+ resque_worker.very_verbose = true
22
+ resque_worker.work(5) # Redis Poll interval in seconds
@@ -0,0 +1,45 @@
1
+ require 'rubygems'
2
+ require 'resque/job_with_status' # in rails you would probably do this in an initializer
3
+
4
+ # sleeps for _length_ seconds updating the status every second
5
+ #
6
+ #
7
+ # Create a Resque Job with the ability to report status
8
+ #
9
+ class SleepJob < Resque::JobWithStatus
10
+
11
+ # Set the name of the queue to use for this Job Worker
12
+ @queue = "sleep_job"
13
+
14
+ # Must be an instance method for Resque::JobWithStatus
15
+ def perform
16
+ total = options['length'].to_i || 10
17
+ num = 0
18
+ while num < total
19
+ at(num, total, "At #{num} of #{total}")
20
+ sleep(1)
21
+ num += 1
22
+ end
23
+ completed
24
+ end
25
+
26
+ end
27
+
28
+ # Submit a new request at the command line
29
+ if __FILE__ == $0
30
+ # Make sure you have a worker running
31
+ # jruby resque_worker.rb
32
+
33
+ count = (ARGV[0] || 10).to_i
34
+
35
+ # running the job
36
+ puts "Creating the SleepJob"
37
+ job_id = SleepJob.create :length => count
38
+ puts "Got back #{job_id}"
39
+
40
+ # check the status until its complete
41
+ while status = Resque::Status.get(job_id) and !status.completed? && !status.failed?
42
+ sleep 1
43
+ puts status.inspect
44
+ end
45
+ end
@@ -0,0 +1,14 @@
1
+ # Window 1:
2
+ # Step 1
3
+ hornetq_server hornetq.yml standalone_server
4
+ # Wait for HornetQ Server version ... started
5
+
6
+ # Window 2:
7
+ # Step 2
8
+ ./producer.rb
9
+
10
+ # Window 3:
11
+ # Step 3
12
+ ./worker.rb
13
+
14
+ #Should be able to cntl-c and restart producer and worker without issues.
@@ -0,0 +1,34 @@
1
+ standalone_server:
2
+ :uri: hornetq://localhost:15445
3
+ :data_directory: ./data
4
+ :persistence_enabled: true
5
+ :security_enabled: false
6
+
7
+ client:
8
+ :connector:
9
+ :uri: hornetq://localhost:15445
10
+ :session:
11
+ :username: guest
12
+ :password: guest
13
+ :session_pool:
14
+ :pool_size: 3
15
+ :pool_warn_timeout: 0.25
16
+ :username: guest
17
+ :password: guest
18
+
19
+ :addresses:
20
+ address1:
21
+ :serialize: ruby_marshal
22
+ :unique: true
23
+ :durable: true
24
+ :queues:
25
+ queue1_1:
26
+ queue1_2:
27
+
28
+ address2:
29
+ :serialize: json
30
+ :unique: false
31
+ :durable: false
32
+ :queues:
33
+ queue2_1:
34
+ queue2_2: