jruby-hornetq 0.2.3.alpha → 0.2.5.alpha

Sign up to get free protection for your applications and to get access to all the features.
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: