fmq 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,4 +1,14 @@
1
- == 0.3.0 2008-08-06
1
+ == 0.3.1 2008-08-27
2
+
3
+ * 2 minor changes:
4
+ * refactored the queue manager and remove legacy code (moved constraints stuff to the base queue)
5
+ * refactored the setup_queue method in the configuration file (sorry you have to change your configs)
6
+ * 3 tiny changes:
7
+ * default-server can now be used from within the development repository (no rund trip nessesary)
8
+ * added and replaced some tests for the new interface of the queue manager and the base queue
9
+ * one can now yield and return messages
10
+
11
+ == 0.3.0 2008-08-26
2
12
 
3
13
  * 2 minor changes:
4
14
  * replaced the mongrel handler by rack so that it can be used by many servers and in different configurations
data/README.txt CHANGED
@@ -34,7 +34,7 @@ stores it’s internal data in an FIFO in system memory.
34
34
  == FEATURES/PROBLEMS:
35
35
 
36
36
  * FIFO message store
37
- * easy setup and maintenance of system
37
+ * easy setup and maintenance of system (rack)
38
38
  * using http for communication
39
39
  * changeable queue implementation
40
40
  * ruby client lib
@@ -1,4 +1,8 @@
1
- require "fmq"
1
+ begin
2
+ require File.dirname(__FILE__) + '/../lib/fmq'
3
+ rescue LoadError
4
+ require "fmq"
5
+ end
2
6
 
3
7
  # load all local queues (from project directory)
4
8
  Dir.glob("queues/*.rb").each { |f| require f }
@@ -24,39 +28,33 @@ queue_manager.setup do |qm|
24
28
  # define there url and constraints here
25
29
  # =====================================================
26
30
 
27
- qm.setup_queue do |q|
28
- # the path to the queue e.g. /app1/myframe/test1
29
- # means http://localhost:5884/app1/myframe/test1
30
- # this parameter is not optional
31
- q.path = "/fmq_test/test1"
31
+ # the path to the queue e.g. /app1/myframe/test1
32
+ # means http://localhost:5884/app1/myframe/test1
33
+ # this parameter is not optional
34
+ qm.setup_queue "/fmq_test/test1" do |q|
32
35
  # this defines the maximum count of messages that
33
36
  # can be in the queue, if the queue is full every
34
37
  # new message will be rejected with a http error
35
38
  # this parameter is optional if you don't specify
36
39
  # a max value the queue size depends on your system
37
- q.max_messages = 1000000
40
+ q.max_messages = 1_000_000
38
41
  # this optional to and specifys the max content size
39
42
  # for all data of a queue
40
43
  # valid extensions are kb, mb, gb
41
- q.max_size = "10kb"
44
+ q.max_size = 10.kb
42
45
  end
43
46
 
44
47
  # if you want you can specify the class of the queue
45
48
  # this is interessting if you write your own queues
46
- qm.setup_queue FreeMessageQueue::LoadBalancedQueue do |q|
47
- q.path = "/fmq_test/test2"
48
- end
49
+ qm.setup_queue "/fmq_test/test2", FreeMessageQueue::LoadBalancedQueue
49
50
 
50
51
  # if you have special queues include put them into the queues
51
52
  # folder and and use them (this MyTestQueue is places in queues/mytest.rb)
52
- qm.setup_queue MyTestQueue do |q|
53
- q.path = "/fmq_test/test3"
54
- end
53
+ qm.setup_queue "/fmq_test/test3", MyTestQueue
55
54
 
56
55
  # this is a forwarding queue wich forwards one message
57
56
  # to some other queues
58
- qm.setup_queue FreeMessageQueue::ForwardQueue do |q|
59
- q.path = "/fmq_test/forward_to_1_and_2"
57
+ qm.setup_queue "/fmq_test/forward_to_1_and_2", FreeMessageQueue::ForwardQueue do |q|
60
58
  # you can add as may queues as you want
61
59
  # but seperate them with a space char
62
60
  q.forward_to = ["/fmq_test/test1", "/fmq_test/test2"]
@@ -4,8 +4,8 @@ class MyTestQueue < FreeMessageQueue::BaseQueue
4
4
  end
5
5
 
6
6
  def poll
7
- msg = FreeMessageQueue::Message.new "Hello World", "text/plain"
8
- msg.option["Time"] = Time.now
9
- msg
7
+ FreeMessageQueue::Message.new "Hello World", "text/plain" do |m|
8
+ m.option["Time"] = Time.now
9
+ end
10
10
  end
11
11
  end
data/lib/fmq/admin.rb CHANGED
@@ -25,72 +25,85 @@ end
25
25
 
26
26
  module FreeMessageQueue
27
27
  # This class is dedicated to the AJAX based admin interface.
28
- class AdminInterface
29
- # rack response for bad requests
30
- WRONG_METHOD = [400, {"CONTENT-TYPE" => "text/plain", "ERROR" => "Wrong http Method"}, ""]
31
-
32
- # rack response for good requests
33
- OK = [200, {"CONTENT-TYPE" => "text/plain"}, ["ok"]]
34
-
35
- # create the admin interface for the passed QueueManager
36
- def initialize(queue_manager)
37
- @manager = queue_manager
38
- @log = FreeMessageQueue.logger
39
- end
40
-
41
- # handle all requests
42
- def call(env)
43
- begin
44
- request = Rack::Request.new(env)
45
- @log.debug "[AdminInterface] ENV: #{env.inspect}"
46
-
47
- if request.get? then
48
- @log.info "[AdminInterface] list queues"
28
+ class AdminInterface
29
+ # rack response for bad requests
30
+ WRONG_METHOD = [400, {"CONTENT-TYPE" => "text/plain", "ERROR" => "Wrong http Method"}, ""]
31
+
32
+ # rack response for good requests
33
+ OK = [200, {"CONTENT-TYPE" => "text/plain"}, ["ok"]]
34
+
35
+ # create the admin interface for the passed QueueManager
36
+ def initialize(queue_manager)
37
+ @manager = queue_manager
38
+ @log = FreeMessageQueue.logger
39
+ end
40
+
41
+ # handle all requests
42
+ def call(env)
43
+ begin
44
+ request = Rack::Request.new(env)
45
+ @log.debug "[AdminInterface] ENV: #{env.inspect}"
46
+
47
+ if request.get? then
48
+ @log.info "[AdminInterface] list queues"
49
49
  # ======= LIST QUEUES
50
50
  queues_code = []
51
51
  @manager.queues.each do |queue_name|
52
52
  queues_code << queue_to_json(queue_name)
53
- end
54
-
55
- return [200, {"CONTENT-TYPE" => "application/json"}, ["[%s]" % queues_code.join(","), ]]
56
- elsif request.post? then
57
- if request["_method"] == "delete" then
58
- # ======= DELETE QUEUE
53
+ end
54
+
55
+ return [200, {"CONTENT-TYPE" => "application/json"}, ["[%s]" % queues_code.join(","), ]]
56
+ elsif request.post? then
57
+ if request["_method"] == "delete" then
58
+ # ======= DELETE QUEUE
59
59
  @log.info "[AdminInterface] delete queue"
60
- @manager.delete_queue(request["path"])
61
- return OK
62
- elsif request["_method"] == "create"
63
- # ======= CREATE QUEUE
60
+ @manager.delete_queue(request["path"])
61
+ return OK
62
+ elsif request["_method"] == "create"
63
+ # ======= CREATE QUEUE
64
64
  @log.info "[AdminInterface] create queue"
65
- @manager.create_queue(request["path"],
66
- request["max_messages"].gsub("null", "-1").to_i,
67
- request["max_size"].gsub("null", "-1").to_i)
68
- return OK
69
- else
70
- return WRONG_METHOD
71
- end
72
- else
73
- return WRONG_METHOD
74
- end
75
- rescue QueueManagerException => ex
76
- return [400, {"CONTENT-TYPE" => "text/plain", "ERROR" => ex.message}, [ex.message]]
77
- end
65
+ @manager.setup_queue request["path"] do |q|
66
+ q.max_messages = request["max_messages"].to_i
67
+ q.max_size = str_bytes request["max_size"]
68
+ end
69
+ return OK
70
+ else
71
+ return WRONG_METHOD
72
+ end
73
+ else
74
+ return WRONG_METHOD
75
+ end
76
+ rescue QueueManagerException => ex
77
+ return [400, {"CONTENT-TYPE" => "text/plain", "ERROR" => ex.message}, [ex.message]]
78
+ end
78
79
  end
79
80
 
80
81
  private
81
82
 
82
83
  # converts the data of one queue to json format
83
84
  def queue_to_json(queue_name)
84
- constraints = @manager.queue_constraints[queue_name]
85
+ queue = @manager.queue(queue_name)
85
86
 
86
87
  "[\"%s\", %d, %d, %d, %d]" % [
87
88
  queue_name,
88
- @manager.queue[queue_name].bytes,
89
- constraints[:max_size],
90
- @manager.queue[queue_name].size,
91
- constraints[:max_messages],
89
+ queue.bytes,
90
+ queue.max_size,
91
+ queue.size,
92
+ queue.max_messages,
92
93
  ]
93
94
  end
95
+
96
+ # Retuns count of bytes to a expression with kb, mb or gb
97
+ # e.g 10kb will return 10240
98
+ def str_bytes(str)
99
+ case str
100
+ when /([0-9]+)kb/i: $1.to_i.kb
101
+ when /([0-9]+)mb/i: $1.to_i.mb
102
+ when /([0-9]+)gb/i: $1.to_i.gb
103
+ else
104
+ BaseQueue::INFINITE
105
+ end
106
+ end
94
107
  end
95
- end
96
-
108
+ end
109
+
@@ -18,6 +18,21 @@
18
18
  #
19
19
  require "ostruct"
20
20
 
21
+ # add kb, mb and gb methods for easy use in the config file
22
+ class Fixnum
23
+ def kb
24
+ self * 1024
25
+ end
26
+
27
+ def mb
28
+ self.kb * 1024
29
+ end
30
+
31
+ def gb
32
+ self.mb * 1024
33
+ end
34
+ end
35
+
21
36
  module FreeMessageQueue
22
37
  # All queue manager exceptions are raised using this class
23
38
  class QueueManagerException < Exception
@@ -40,23 +55,8 @@ module FreeMessageQueue
40
55
  # corresponding constraints. Every queue that is created by this
41
56
  # queue manager will get a reference (<em>manager</em>) for later use.
42
57
  class QueueManager
43
- # Returns the queue that is passed otherwise nil
44
- attr_reader :queue
45
-
46
58
  # <b>true</b> to let the queue manager create a queue automaticly
47
59
  attr_writer :auto_create_queues
48
-
49
- # Returns the queue constrains as a hash. The hash has the following structure:
50
- # {
51
- # :max_size => "100mb",
52
- # :max_messages => 1000
53
- # }
54
- attr_reader :queue_constraints
55
-
56
- # This value is used to decribe that a constraint has no limit e.g.
57
- # :max_messages => INFINITE
58
- # means that there is no limitation for messages
59
- INFINITE = -1
60
60
 
61
61
  # this is the default queue class if no other is specified this
62
62
  # class will be created when setting up a queue
@@ -65,8 +65,7 @@ module FreeMessageQueue
65
65
  # setup the queue manager using the configuration from the configuration
66
66
  # file (which is basically a hash)
67
67
  def initialize()
68
- @queue = {}
69
- @queue_constraints = {}
68
+ @queues = {}
70
69
  @log = FreeMessageQueue.logger
71
70
  @auto_create_queues = true
72
71
  end
@@ -76,44 +75,26 @@ module FreeMessageQueue
76
75
  def auto_create_queues?
77
76
  @auto_create_queues == true
78
77
  end
79
-
80
- # Create a queue (<em>name</em> => <em>path</em>). The path must contain a leading "/" and a 3 character name
81
- # at minimum. Exceptions will be raised if the queue allready exists.
82
- def create_queue(name, max_messages = INFINITE, max_size = INFINITE, default_class = DEFAULT_QUEUE_CLASS)
83
- # path must begin with /
84
- raise QueueManagerException.new("[QueueManager] Leading / in path '#{name}' missing", caller) if name[0..0] != "/"
85
-
86
- # path must have a minimus lenght of 3 character
87
- raise QueueManagerException.new("[QueueManager] The queue path '#{name}' is to short 3 character is minimum", caller) if name.size - 1 < 3
88
-
89
- # don't create a queue twice
90
- raise QueueManagerException.new("[QueueManager] The queue '#{name}' allready exists", caller) if queue_exists? name
91
-
92
- @log.info("[QueueManager] Create queue '#{name}' {type: #{default_class}, max_messages: #{max_messages}, max_size: #{max_size}}")
93
-
94
- @queue[name] = default_class.new(self)
95
- @queue_constraints[name] = {
96
- :max_messages => max_messages,
97
- :max_size => max_size
98
- }
99
-
100
- @queue[name]
101
- end
102
78
 
103
79
  # create a queue using a block. The block can be used to set configuration
104
80
  # options for the queue
105
- def setup_queue(queue_class = DEFAULT_QUEUE_CLASS, &configure_queue)
106
- queue_settings = OpenStruct.new
107
- configure_queue.call(queue_settings)
108
- create_queue_from_config(queue_class, queue_settings.marshal_dump)
81
+ def setup_queue(path, queue_class = DEFAULT_QUEUE_CLASS)
82
+ check_queue_name(path)
83
+ queue_object = queue_class.new(self)
84
+ if block_given? then
85
+ yield queue_object
86
+ end
87
+ @queues[path] = queue_object
88
+ @log.info("[QueueManager] Create queue '#{path}' {type: #{queue_class}, max_messages: #{queue_object.max_messages}, max_size: #{queue_object.max_size}}")
89
+ return queue_object
109
90
  end
110
91
 
111
92
  # Delete the queue by name (path)
112
93
  def delete_queue(name)
113
- if @queue[name]
114
- @log.info("[QueueManager] Delete queue '#{name}' with #{@queue[name].size} messages")
115
- @queue[name].clear
116
- @queue.delete name
94
+ if queue_exists? name
95
+ @log.info("[QueueManager] Delete queue '#{name}' with #{queue(name).size} messages")
96
+ queue(name).clear
97
+ @queues.delete name
117
98
  true
118
99
  else
119
100
  raise QueueManagerException.new("[QueueManager] There is no queue '#{name}'", caller)
@@ -122,10 +103,10 @@ module FreeMessageQueue
122
103
 
123
104
  # This returns one message from the passed queue
124
105
  def poll(name)
125
- if @queue[name]
126
- @log.debug("[QueueManager] Poll from queue '#{name}' with #{@queue[name].size} messages")
127
- if @queue[name].respond_to? :poll
128
- queue_item = @queue[name].poll
106
+ if queue_exists? name
107
+ @log.debug("[QueueManager] Poll from queue '#{name}' with #{queue(name).size} messages")
108
+ if queue(name).respond_to? :poll
109
+ queue_item = queue(name).poll
129
110
  else
130
111
  raise QueueManagerException.new("[QueueManager] You can't poll from queue '#{name}'", caller)
131
112
  end
@@ -141,7 +122,8 @@ module FreeMessageQueue
141
122
  # will be generated if there isn't a queue with the passed name (path). Otherwise
142
123
  # it will raise a QueueManagerException if the passed queue doesn't exists.
143
124
  def put(name, message)
144
- unless @queue[name]
125
+ # check for auto createing queues if they are not available
126
+ unless queue_exists? name
145
127
  # only auto create queues if it is configured
146
128
  if auto_create_queues?
147
129
  create_queue(name)
@@ -149,22 +131,10 @@ module FreeMessageQueue
149
131
  raise QueueManagerException.new("[QueueManager] There is no queue '#{name}'", caller)
150
132
  end
151
133
  end
152
-
153
- # check max size constraints
154
- if @queue_constraints[name][:max_size] != INFINITE &&
155
- @queue_constraints[name][:max_size] < queue[name].bytes + message.bytes
156
- raise QueueManagerException.new("[QueueManager] The queue '#{name}' is full, max amount of space (#{@queue_constraints[name][:max_size]}) is exceeded", caller)
157
- end
158
-
159
- # check max messages constraints
160
- if @queue_constraints[name][:max_messages] != INFINITE &&
161
- @queue_constraints[name][:max_messages] < queue[name].size + 1
162
- raise QueueManagerException.new("[QueueManager] The queue '#{name}' is full, max amount of messages (#{@queue_constraints[name][:max_messages]}) is exceeded", caller)
163
- end
164
134
 
165
- @log.debug("[QueueManager] put message to queue '#{name}' with #{@queue[name].size} messages")
166
- if @queue[name].respond_to? :put
167
- @queue[name].put(message)
135
+ @log.debug("[QueueManager] put message to queue '#{name}' with #{queue(name).size} messages")
136
+ if queue(name).respond_to? :put
137
+ queue(name).put(message)
168
138
  else
169
139
  raise QueueManagerException.new("[QueueManager] You can't put to queue '#{name}'", caller)
170
140
  end
@@ -174,22 +144,12 @@ module FreeMessageQueue
174
144
 
175
145
  # Returns the names (paths) of all queues managed by this queue manager
176
146
  def queues
177
- @queue.keys
178
- end
179
-
180
- # Returns the size (number of messages)
181
- def queue_size(name)
182
- @queue[name].size
183
- end
184
-
185
- # Returns the byte size of the queue
186
- def queue_bytes(name)
187
- @queue[name].bytes
147
+ @queues.keys
188
148
  end
189
149
 
190
150
  # Is the name (path) of the queue in use allready
191
151
  def queue_exists?(name)
192
- !queue[name].nil?
152
+ !queue(name).nil?
193
153
  end
194
154
 
195
155
  # setup a this queue manager block need to be passed
@@ -197,63 +157,23 @@ module FreeMessageQueue
197
157
  config.call(self)
198
158
  end
199
159
 
200
- private
201
-
202
- # create a queue from a configuration hash.
203
- # The <em>queue_config</em> contains the following parameter:
204
- # * path: the path to the queue (with leading "/" and 3 characters at minimum) e.g. "/test_queue"
205
- # * [optional] max_size: the maximum size e.g. "10mb", "100kb", "2gb" or (black or -1) for infinite
206
- # * [optional] max_messages: the maximim messages that can be in the queue e.g. 1500 or (black or -1) for infinite
207
- # All other parameter will be send to the queue directly using a naming convention. So if you have the extra parameter
208
- # expire_date = "1h"
209
- # the QueueManager will set the expire date using this assignment
210
- # queue.expire_date = "1h"
211
- # therefore your queue must implement this method
212
- # def expire_date=(time)
213
- # @expires_after = parse_seconds(time)
214
- # end
215
- def create_queue_from_config(queue_class, queue_config)
216
- # path need to be specified
217
- raise QueueManagerException.new("[QueueManager] There is now path specified for queue", caller) if queue_config[:path].nil?
218
- path = queue_config[:path]
219
- queue_config.delete :path
220
-
221
- @log.debug("[QueueManager] setup queue from config '#{path}'")
222
-
223
- # set max size parameter -- this parameter is optional
224
- max_size = str_bytes(queue_config[:max_size])
225
- max_size = INFINITE if max_size.nil? || max_size <= 0
226
- queue_config.delete :max_size
227
-
228
- # set max messages parameter -- this parameter is optional
229
- max_messages = queue_config[:max_messages].to_i
230
- max_messages = INFINITE if max_messages.nil? || max_messages <= 0
231
- queue_config.delete :max_messages
232
-
233
- queue = create_queue(path, max_messages, max_size, queue_class)
234
-
235
- if queue_config.size > 0
236
- @log.debug("[QueueManager] Configure addional parameters for queue '#{path}'; parameter: #{queue_config.inspect}")
237
- for method_name in queue_config.keys
238
- queue.send(method_name.to_s + "=", queue_config[method_name])
239
- end
240
- end
160
+ def queue(name)
161
+ return @queues[name]
241
162
  end
242
-
243
- # Retuns count of bytes to a expression with kb, mb or gb
244
- # e.g 10kb will return 10240
245
- def str_bytes(str)
246
- case str
247
- when /([0-9]+)kb/i
248
- bs = $1.to_i * 1024
249
- when /([0-9]+)mb/i
250
- bs = $1.to_i * 1024 * 1024
251
- when /([0-9]+)gb/i
252
- bs = $1.to_i * 1024 * 1024 * 1024
253
- else
254
- bs = INFINITE
255
- end
256
- bs
163
+
164
+ private
165
+
166
+ # Create a queue (<em>name</em> => <em>path</em>). The path must contain a leading "/" and a 3 character name
167
+ # at minimum. Exceptions will be raised if the queue allready exists.
168
+ def check_queue_name(name)
169
+ # path must begin with /
170
+ raise QueueManagerException.new("[QueueManager] Leading / in path '#{name}' missing", caller) if name[0..0] != "/"
171
+
172
+ # path must have a minimus lenght of 3 character
173
+ raise QueueManagerException.new("[QueueManager] The queue path '#{name}' is to short 3 character is minimum", caller) if name.size - 1 < 3
174
+
175
+ # don't create a queue twice
176
+ raise QueueManagerException.new("[QueueManager] The queue '#{name}' allready exists", caller) if queue_exists? name
257
177
  end
258
178
  end
259
179
  end
@@ -20,8 +20,8 @@ First of all, this template is where you start.
20
20
  end
21
21
 
22
22
  def poll
23
- msg = FreeMessageQueue::Message.new "Hello World", "text/plain"
24
- msg.option["Time"] = Time.now
25
- msg
23
+ FreeMessageQueue::Message.new "Hello World", "text/plain" do |m|
24
+ m.option["Time"] = Time.now
25
+ end
26
26
  end
27
27
  end
@@ -31,26 +31,53 @@ module FreeMessageQueue
31
31
  @created_at = created_at
32
32
  @content_type = content_type
33
33
  @option = {}
34
+ if block_given? then
35
+ yield self
36
+ end
34
37
  end
35
38
 
36
- # Aize of item in bytes
39
+ # Size of item in bytes
37
40
  def bytes
38
41
  @payload.size
39
42
  end
40
43
  end
41
44
 
45
+ # All queue exceptions are raised using this class
46
+ class QueueException < Exception
47
+ attr_accessor :message, :backtrace
48
+
49
+ # Create exception with message and backtrace (if needed)
50
+ def initialize(message, callstack = [])
51
+ @message = message
52
+ @backtrace = callstack
53
+ end
54
+
55
+ # Returns the message of the exception
56
+ def to_s
57
+ @message
58
+ end
59
+ end
60
+
42
61
  # every queue has to have this interface
43
62
  class BaseQueue
44
63
  # QueueManager refrence
45
64
  attr_accessor :manager
65
+
66
+ # This value is used to decribe that a constraint has no limit e.g.
67
+ # max_messages = INFINITE
68
+ # means that there is no limitation for messages (by count)
69
+ INFINITE = -1
46
70
 
47
71
  attr_reader :bytes, # the amount of space that is used by all messages in the queue
48
- :size # the size / depp of the queue = count of messages
72
+ :size, # the size / depp of the queue = count of messages
73
+ :max_messages, # the max count of messages that can be in the queue
74
+ :max_size # the max size (bytes) of messages that can be in the queue
49
75
 
50
76
  def initialize(manager)
51
77
  @manager = manager
52
78
  @bytes = 0
53
79
  @size = 0
80
+ @max_size = @max_messages = INFINITE
54
81
  end
55
82
 
56
83
  # returns true if there is no message in the queue
@@ -58,18 +85,55 @@ module FreeMessageQueue
58
85
  size == 0
59
86
  end
60
87
 
88
+ # check that one can only set valid constraints
89
+ def max_messages=(val)
90
+ @max_messages = (val <= 0) ? BaseQueue::INFINITE : val
91
+ end
92
+
93
+ # check that one can only set valid constraints
94
+ def max_size=(val)
95
+ @max_size = (val <= 0) ? BaseQueue::INFINITE : val
96
+ end
97
+
61
98
  protected
62
99
 
63
- # update queue size and memory usage (add one messge)
64
- def add_message(bytes)
100
+ # update queue size and memory usage (add one message)
101
+ def add_message(message)
102
+ check_constraints_with_new(message)
103
+
65
104
  @size += 1
66
- @bytes += bytes
105
+ @bytes += message.bytes
106
+ return message
67
107
  end
68
108
 
69
- # update queue size and memory usage (remove one messge)
70
- def remove_message(bytes)
109
+ # update queue size and memory usage (remove one message)
110
+ def remove_message(message)
71
111
  @size -= 1
72
- @bytes -= bytes
112
+ @bytes -= message.bytes
113
+ return message
114
+ end
115
+
116
+ # check all constraints that are available.
117
+ # throws an exception if a constraint failed
118
+ def check_constraints_with_new(message)
119
+ check_max_size_constraint(message)
120
+ check_max_messages_constraint(message)
121
+ end
122
+
123
+ # check if max size of messages will exceed with new message.
124
+ # throws an exception if a constraint failed
125
+ def check_max_size_constraint(message)
126
+ if @max_size != INFINITE && (@max_size < self.bytes + message.bytes)
127
+ raise QueueException.new("[Queue] The queue is full, max amount of space (#{@max_size} bytes) is exceeded", caller)
128
+ end
129
+ end
130
+
131
+ # check if max count of messages will exceed with new message.
132
+ # throws an exception if a constraint failed
133
+ def check_max_messages_constraint(message)
134
+ if @max_messages != INFINITE && (@max_messages < self.size + 1)
135
+ raise QueueException.new("[Queue] The queue is full, max amount of messages (#{@max_messages}) is exceeded", caller)
136
+ end
73
137
  end
74
138
  end
75
139
  end
@@ -37,6 +37,8 @@ module FreeMessageQueue
37
37
  def put(message)
38
38
  return false if message == nil
39
39
 
40
+ add_message(message) # update stats and check constraints
41
+
40
42
  # insert at end of list
41
43
  if @first_message == nil
42
44
  # first and last item are same if there is no item to the queue
@@ -46,7 +48,7 @@ module FreeMessageQueue
46
48
  @last_message = @last_message.next = message
47
49
  end
48
50
 
49
- add_message(message.bytes) # update stats
51
+ return true
50
52
  end
51
53
 
52
54
  # Return an message from the queue or nil if the queue is empty
@@ -59,9 +61,7 @@ module FreeMessageQueue
59
61
  @first_message = message.next
60
62
  @last_message = nil if @first_message.nil?
61
63
  message.next = nil # unlink the message
62
- remove_message(message.bytes) # update stats
63
-
64
- return message
64
+ remove_message(message) # update stats
65
65
  else
66
66
  return nil
67
67
  end
@@ -75,6 +75,16 @@ module FreeMessageQueue
75
75
  @queues[next_put_index].put(data)
76
76
  end
77
77
 
78
+ # queue has infinite count
79
+ def max_messages
80
+ BaseQueue::INFINITE
81
+ end
82
+
83
+ # queue has infinite messages
84
+ def max_size
85
+ BaseQueue::INFINITE
86
+ end
87
+
78
88
  private
79
89
 
80
90
  # next index acts like 'round robin'
data/lib/fmq/server.rb CHANGED
@@ -34,11 +34,11 @@ module FreeMessageQueue
34
34
  end
35
35
 
36
36
  # Process incoming request and send them to the right sub processing method like <em>process_get</em>
37
- def call(env)
37
+ def call(env)
38
38
  request = Rack::Request.new(env)
39
39
  queue_path = request.env["REQUEST_PATH"]
40
40
  @log.debug("[Server] Request params: #{YAML.dump(request.params)})")
41
-
41
+
42
42
  response = nil
43
43
  begin
44
44
  # process supported features
@@ -50,9 +50,9 @@ module FreeMessageQueue
50
50
  end
51
51
  rescue QueueManagerException => ex
52
52
  response = client_exception(request, queue_path, ex)
53
- end
53
+ end
54
54
 
55
- response.header["SERVER"] = SERVER_HEADER
55
+ response.header["SERVER"] = SERVER_HEADER
56
56
  return response.finish
57
57
  end
58
58
 
@@ -61,15 +61,15 @@ module FreeMessageQueue
61
61
  # Returns an item from queue and sends it to the client.
62
62
  # If there is no item to fetch send an 204 (NoContent) and same as HEAD
63
63
  def process_get(request, queue_path)
64
- message = @queue_manager.poll(queue_path)
64
+ message = @queue_manager.poll(queue_path)
65
65
 
66
66
  unless message.nil? then
67
- response = Rack::Response.new([], 200)
67
+ response = Rack::Response.new([], 200)
68
68
 
69
69
  @log.debug("[Server] Response to GET (200)")
70
70
  response.header["CONTENT-TYPE"] = message.content_type
71
- response.header["QUEUE_SIZE"] = @queue_manager.queue_size(queue_path).to_s
72
- response.header["QUEUE_BYTES"] = @queue_manager.queue_bytes(queue_path).to_s
71
+ response.header["QUEUE_SIZE"] = @queue_manager.queue(queue_path).size.to_s
72
+ response.header["QUEUE_BYTES"] = @queue_manager.queue(queue_path).bytes.to_s
73
73
 
74
74
  # send all options of the message back to the client
75
75
  if message.respond_to?(:option) && message.option.size > 0
@@ -86,13 +86,13 @@ module FreeMessageQueue
86
86
  response = Rack::Response.new([], 204)
87
87
  @log.debug("[Server] Response to GET (204)")
88
88
  response.header["QUEUE_SIZE"] = response["QUEUE_BYTES"] = 0.to_s
89
- end
89
+ end
90
90
  return response
91
91
  end
92
92
 
93
93
  # Put new item to the queue and and return sam e as head action (HTTP 200)
94
94
  def process_post(request, queue_path)
95
- @log.debug("[Server] Response to POST (200)")
95
+ @log.debug("[Server] Response to POST (200)")
96
96
  post_body = request.body.read
97
97
  message = Message.new(post_body, request.content_type)
98
98
  @log.debug("[Server] Message payload: #{post_body}")
@@ -107,8 +107,8 @@ module FreeMessageQueue
107
107
  @queue_manager.put(queue_path, message)
108
108
 
109
109
  response = Rack::Response.new([], 200)
110
- response.header["QUEUE_SIZE"] = @queue_manager.queue_size(queue_path).to_s
111
- response.header["QUEUE_BYTES"] = @queue_manager.queue_bytes(queue_path).to_s
110
+ response.header["QUEUE_SIZE"] = @queue_manager.queue(queue_path).size.to_s
111
+ response.header["QUEUE_BYTES"] = @queue_manager.queue(queue_path).bytes.to_s
112
112
  return response
113
113
  end
114
114
 
@@ -117,8 +117,8 @@ module FreeMessageQueue
117
117
  @log.debug("[Server] Response to HEAD (200)")
118
118
 
119
119
  response = Rack::Response.new([], 200)
120
- response.header["QUEUE_SIZE"] = @queue_manager.queue_size(queue_path).to_s
121
- response.header["QUEUE_BYTES"] = @queue_manager.queue_bytes(queue_path).to_s
120
+ response.header["QUEUE_SIZE"] = @queue_manager.queue(queue_path).size.to_s
121
+ response.header["QUEUE_BYTES"] = @queue_manager.queue(queue_path).bytes.to_s
122
122
  return response
123
123
  end
124
124
 
@@ -134,11 +134,11 @@ module FreeMessageQueue
134
134
  # HTTP-Header field Error contains information about the problem.
135
135
  # The client errorwill also be reported to warn level of logger.
136
136
  def client_exception(request, queue_path, ex)
137
- @log.warn("[Server] Client error: #{ex}")
137
+ @log.warn("[Server] Client error: #{ex}")
138
138
 
139
139
  response = Rack::Response.new([], 400)
140
- response.header["ERROR"] = ex.message
140
+ response.header["ERROR"] = ex.message
141
141
  return response
142
142
  end
143
143
  end
144
- end
144
+ end
data/lib/fmq/version.rb CHANGED
@@ -20,7 +20,7 @@ module FreeMessageQueue
20
20
  module VERSION #:nodoc:
21
21
  MAJOR = 0
22
22
  MINOR = 3
23
- TINY = 0
23
+ TINY = 1
24
24
 
25
25
  STRING = [MAJOR, MINOR, TINY].join('.')
26
26
  end
data/test/test_basic.rb CHANGED
@@ -26,11 +26,61 @@ class TestMessage < Test::Unit::TestCase
26
26
  end
27
27
 
28
28
  class BaseQueue < Test::Unit::TestCase
29
- def test_initialize
30
- manager = "pseudo manager"
31
- queue = FreeMessageQueue::BaseQueue.new(manager)
32
- assert_equal 0, queue.size
33
- assert_equal 0, queue.bytes
34
- assert_equal manager, queue.manager
29
+ def setup
30
+ @manager = FreeMessageQueue::QueueManager.new()
31
+
32
+ @manager.setup do |m|
33
+ @queue1 = m.setup_queue "/dummy1"
34
+ @queue2 = m.setup_queue "/dummy2" do |q|
35
+ q.max_messages = 100
36
+ q.max_size = 100.kb
37
+ end
38
+ @queue3 = m.setup_queue "/dummy3" do |q|
39
+ q.max_size = 0
40
+ q.max_messages = -10
41
+ end
42
+ end
43
+ end
44
+
45
+ def test_creating
46
+ # check first queue
47
+ assert_equal 0, @queue1.size
48
+ assert_equal 0, @queue1.bytes
49
+ assert_equal FreeMessageQueue::BaseQueue::INFINITE, @queue1.max_messages
50
+ assert_equal FreeMessageQueue::BaseQueue::INFINITE, @queue1.max_size
51
+
52
+ # check 2. queue
53
+ assert_equal 0, @queue2.size
54
+ assert_equal 0, @queue2.bytes
55
+ assert_equal 100, @queue2.max_messages
56
+ assert_equal 100 * 1024, @queue2.max_size
57
+
58
+ # check 3. queue
59
+ assert_equal 0, @queue3.size
60
+ assert_equal 0, @queue3.bytes
61
+ assert_equal FreeMessageQueue::BaseQueue::INFINITE, @queue3.max_messages
62
+ assert_equal FreeMessageQueue::BaseQueue::INFINITE, @queue3.max_size
63
+
64
+ assert_equal @manager, @queue1.manager
65
+ end
66
+
67
+ def test_constraint_max_messages
68
+ 100.times do |v|
69
+ @queue2.put(new_msg("test"))
70
+ end
71
+
72
+ assert_raise(FreeMessageQueue::QueueException) do
73
+ @queue2.put(new_msg("test"))
74
+ end
75
+ end
76
+
77
+ def test_constraint_max_size
78
+ 11.times do |v|
79
+ @queue2.put(new_msg("X" * 9.kb))
80
+ end
81
+
82
+ assert_raise(FreeMessageQueue::QueueException) do
83
+ @queue2.put(new_msg("X" * 10.kb))
84
+ end
35
85
  end
36
86
  end
@@ -12,54 +12,58 @@ class TestQueueManager < Test::Unit::TestCase
12
12
  @queue_manager.setup do |qm|
13
13
  qm.auto_create_queues = false
14
14
 
15
- qm.setup_queue do |q|
16
- q.path = DEFAULT_QUEUE_NAME
15
+ qm.setup_queue DEFAULT_QUEUE_NAME do |q|
17
16
  q.max_messages = 100
18
- q.max_size = "100mb"
17
+ q.max_size = 100.mb
19
18
  end
19
+
20
+ qm.setup_queue "/second_test_queue"
21
+ qm.setup_queue "/third_test_queue"
20
22
  end
21
23
  end
22
24
 
23
25
  def test_config
24
- # check constraints
25
- constraints = { :max_messages => 100, :max_size => 104857600 }
26
- assert_equal constraints, @queue_manager.queue_constraints[DEFAULT_QUEUE_NAME]
27
-
28
26
  # check that the simple config will work
29
27
  FreeMessageQueue::QueueManager.new()
30
28
  @queue_manager.setup do |qm|
31
29
  qm.auto_create_queues = false
32
30
  end
31
+
32
+ # check if all queues are available
33
+ assert_equal 3, @queue_manager.queues.size
34
+ [DEFAULT_QUEUE_NAME, "/second_test_queue", "/third_test_queue"].each do |e|
35
+ assert @queue_manager.queues.include? e
36
+ end
33
37
  end
34
38
 
35
39
  def test_poll_and_get
36
40
  10.times do
37
41
  @queue_manager.put(DEFAULT_QUEUE_NAME, new_msg("XXX" * 20))
38
42
  end
39
- assert_equal 10, @queue_manager.queue_size(DEFAULT_QUEUE_NAME)
43
+ assert_equal 10, @queue_manager.queue(DEFAULT_QUEUE_NAME).size
40
44
  i = 0
41
45
  while message = @queue_manager.poll(DEFAULT_QUEUE_NAME)
42
46
  i += 1
43
47
  end
44
48
  assert_equal 10, i
45
- assert_equal 0, @queue_manager.queue_size(DEFAULT_QUEUE_NAME)
49
+ assert_equal 0, @queue_manager.queue(DEFAULT_QUEUE_NAME).size
46
50
 
47
51
  # should raise a exception because of the maximum messages limitation
48
52
  i = 0
49
- assert_raise(FreeMessageQueue::QueueManagerException) {
53
+ assert_raise(FreeMessageQueue::QueueException) {
50
54
  101.times do
51
55
  @queue_manager.put(DEFAULT_QUEUE_NAME, new_msg("XXX" * 20))
52
56
  i += 1
53
57
  end
54
58
  }
55
- @queue_manager.queue[DEFAULT_QUEUE_NAME].clear
56
- assert_equal 0, @queue_manager.queue_size(DEFAULT_QUEUE_NAME)
59
+ @queue_manager.queue(DEFAULT_QUEUE_NAME).clear
60
+ assert_equal 0, @queue_manager.queue(DEFAULT_QUEUE_NAME).size
57
61
  assert i = 100
58
62
 
59
63
  # should raise a exception because of the maximum byte size limitation
60
64
  i = 0
61
65
  two_mb_message = new_msg("X" * 1024 * 1024 * 2)
62
- assert_raise(FreeMessageQueue::QueueManagerException) {
66
+ assert_raise(FreeMessageQueue::QueueException) {
63
67
  101.times do
64
68
  @queue_manager.put(DEFAULT_QUEUE_NAME, two_mb_message)
65
69
  i += 1
@@ -70,7 +74,7 @@ class TestQueueManager < Test::Unit::TestCase
70
74
 
71
75
  def test_creating_and_deleting
72
76
  url = "/XX123"
73
- @queue_manager.create_queue(url)
77
+ @queue_manager.setup_queue url
74
78
  @queue_manager.put(url, new_msg("X_X_X_X_X_X"))
75
79
  assert_equal "X_X_X_X_X_X", @queue_manager.poll(url).payload
76
80
  @queue_manager.delete_queue(url)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fmq
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vincent Landgraf
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-08-26 00:00:00 +02:00
12
+ date: 2008-08-27 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency