fluent-plugin-droonga 0.9.9 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.dir-locals.el +3 -0
  3. data/.travis.yml +6 -2
  4. data/README.md +6 -7
  5. data/Rakefile +23 -6
  6. data/fluent-plugin-droonga.gemspec +2 -2
  7. data/lib/droonga/adapter.rb +12 -3
  8. data/lib/droonga/adapter_runner.rb +28 -23
  9. data/lib/droonga/catalog/base.rb +7 -111
  10. data/lib/droonga/catalog/dataset.rb +13 -25
  11. data/lib/droonga/catalog/errors.rb +94 -0
  12. data/lib/droonga/catalog/schema.rb +277 -0
  13. data/lib/droonga/catalog/version1.rb +404 -0
  14. data/lib/droonga/catalog/version2.rb +160 -0
  15. data/lib/droonga/catalog_loader.rb +27 -4
  16. data/lib/droonga/catalog_observer.rb +44 -6
  17. data/lib/droonga/collector.rb +12 -10
  18. data/lib/droonga/{handler_plugin.rb → collector_message.rb} +47 -20
  19. data/lib/droonga/collector_runner.rb +64 -0
  20. data/lib/droonga/collectors.rb +18 -0
  21. data/lib/droonga/{catalog.rb → collectors/add.rb} +9 -7
  22. data/lib/droonga/{command_repository.rb → collectors/and.rb} +7 -14
  23. data/lib/droonga/collectors/sum.rb +26 -0
  24. data/lib/droonga/dispatcher.rb +74 -41
  25. data/lib/droonga/distributed_command_planner.rb +2 -2
  26. data/lib/droonga/engine.rb +13 -5
  27. data/lib/droonga/{message_processing_error.rb → error.rb} +33 -12
  28. data/lib/droonga/{plugin/planner/search.rb → error_messages.rb} +12 -10
  29. data/lib/droonga/farm.rb +15 -14
  30. data/lib/droonga/fluent_message_sender.rb +15 -11
  31. data/lib/droonga/forwarder.rb +22 -18
  32. data/lib/droonga/handler.rb +8 -2
  33. data/lib/droonga/handler_runner.rb +47 -26
  34. data/lib/droonga/input_message.rb +6 -6
  35. data/lib/droonga/{command.rb → loggable.rb} +7 -14
  36. data/lib/droonga/logger.rb +56 -15
  37. data/lib/droonga/message_matcher.rb +12 -7
  38. data/lib/droonga/message_pusher.rb +8 -4
  39. data/lib/droonga/message_receiver.rb +11 -9
  40. data/lib/droonga/output_message.rb +2 -0
  41. data/lib/droonga/planner.rb +21 -10
  42. data/lib/droonga/plugin.rb +15 -0
  43. data/lib/droonga/plugin/metadata/{adapter_message.rb → adapter_input_message.rb} +6 -14
  44. data/lib/droonga/plugin/metadata/adapter_output_message.rb +39 -0
  45. data/lib/droonga/plugin/metadata/collector_message.rb +39 -0
  46. data/lib/droonga/plugin/metadata/input_message.rb +15 -0
  47. data/lib/droonga/plugin_loader.rb +33 -25
  48. data/lib/droonga/plugin_registry.rb +9 -1
  49. data/lib/droonga/plugins/basic.rb +54 -0
  50. data/lib/droonga/plugins/crud.rb +36 -15
  51. data/lib/droonga/plugins/error.rb +5 -4
  52. data/lib/droonga/plugins/groonga.rb +9 -6
  53. data/lib/droonga/plugins/groonga/column_create.rb +10 -5
  54. data/lib/droonga/plugins/groonga/generic_command.rb +2 -8
  55. data/lib/droonga/plugins/groonga/generic_response.rb +2 -2
  56. data/lib/droonga/plugins/groonga/select.rb +2 -2
  57. data/lib/droonga/plugins/groonga/table_create.rb +9 -4
  58. data/lib/droonga/plugins/groonga/table_remove.rb +10 -5
  59. data/lib/droonga/plugins/search.rb +106 -5
  60. data/lib/droonga/plugins/search/distributed_search_planner.rb +398 -0
  61. data/lib/droonga/plugins/watch.rb +41 -20
  62. data/lib/droonga/processor.rb +12 -9
  63. data/lib/droonga/{plugin/collector/basic.rb → reducer.rb} +36 -50
  64. data/lib/droonga/replier.rb +7 -4
  65. data/lib/droonga/searcher.rb +40 -37
  66. data/lib/droonga/server.rb +8 -6
  67. data/lib/droonga/session.rb +17 -7
  68. data/lib/droonga/single_step.rb +53 -0
  69. data/lib/droonga/{plugin/planner/watch.rb → single_step_definition.rb} +27 -26
  70. data/lib/droonga/{partition.rb → slice.rb} +23 -12
  71. data/lib/droonga/status_code.rb +25 -0
  72. data/lib/droonga/step_runner.rb +63 -0
  73. data/lib/droonga/watch_schema.rb +7 -3
  74. data/lib/droonga/watcher.rb +4 -4
  75. data/lib/droonga/worker.rb +6 -6
  76. data/lib/fluent/plugin/out_droonga.rb +27 -2
  77. data/sample/cluster/catalog.json +33 -32
  78. data/test/command/config/default/catalog.json +72 -45
  79. data/test/command/config/version1/catalog.json +68 -0
  80. data/test/command/config/version1/fluentd.conf +11 -0
  81. data/test/command/suite/message/error/missing-dataset.expected +1 -1
  82. data/test/command/suite/message/error/unknown-dataset.expected +1 -1
  83. data/test/command/suite/message/error/unknown-type.expected +13 -0
  84. data/test/command/suite/message/error/{unknown-command.test → unknown-type.test} +1 -1
  85. data/test/command/suite/search/error/missing-source-parameter.expected +1 -1
  86. data/test/command/suite/search/error/unknown-source.expected +15 -3
  87. data/test/command/suite/watch/subscribe.expected +1 -3
  88. data/test/command/suite/watch/unsubscribe.expected +1 -3
  89. data/test/performance/watch/catalog.json +1 -0
  90. data/test/unit/catalog/test_dataset.rb +16 -358
  91. data/test/unit/catalog/test_schema.rb +285 -0
  92. data/test/unit/catalog/test_version1.rb +222 -28
  93. data/test/unit/catalog/test_version2.rb +155 -0
  94. data/test/unit/fixtures/catalog/version2.json +62 -0
  95. data/test/unit/helper/distributed_search_planner_helper.rb +2 -2
  96. data/test/unit/plugins/crud/test_add.rb +13 -13
  97. data/test/unit/plugins/groonga/test_column_create.rb +14 -11
  98. data/test/unit/plugins/groonga/test_table_create.rb +4 -9
  99. data/test/unit/plugins/groonga/test_table_remove.rb +4 -9
  100. data/test/unit/{plugin/planner/search_planner → plugins/search/planner}/test_basic.rb +0 -0
  101. data/test/unit/{plugin/planner/search_planner → plugins/search/planner}/test_group_by.rb +0 -0
  102. data/test/unit/{plugin/planner/search_planner → plugins/search/planner}/test_output.rb +0 -0
  103. data/test/unit/{plugin/planner/search_planner → plugins/search/planner}/test_sort_by.rb +0 -0
  104. data/test/unit/{plugin/collector/test_search.rb → plugins/search/test_collector.rb} +40 -39
  105. data/test/unit/plugins/{test_search.rb → search/test_handler.rb} +6 -5
  106. data/test/unit/{plugin/planner/test_search.rb → plugins/search/test_planner.rb} +3 -3
  107. data/test/unit/{plugin/collector → plugins}/test_basic.rb +68 -50
  108. data/test/unit/plugins/test_groonga.rb +2 -15
  109. data/test/unit/plugins/test_watch.rb +25 -22
  110. data/test/unit/test_message_matcher.rb +29 -6
  111. data/test/unit/test_output.rb +4 -0
  112. metadata +58 -50
  113. data/lib/droonga/collector_plugin.rb +0 -50
  114. data/lib/droonga/legacy_pluggable.rb +0 -66
  115. data/lib/droonga/legacy_plugin.rb +0 -57
  116. data/lib/droonga/legacy_plugin_repository.rb +0 -54
  117. data/lib/droonga/planner_plugin.rb +0 -54
  118. data/lib/droonga/plugin/collector/search.rb +0 -98
  119. data/lib/droonga/plugin/planner/crud.rb +0 -49
  120. data/lib/droonga/plugin/planner/distributed_search_planner.rb +0 -393
  121. data/lib/droonga/plugin/planner/groonga.rb +0 -54
  122. data/lib/droonga/plugin_registerable.rb +0 -75
  123. data/test/command/suite/message/error/unknown-command.expected +0 -13
  124. data/test/unit/test_command_repository.rb +0 -39
  125. data/test/unit/test_legacy_plugin.rb +0 -50
  126. data/test/unit/test_legacy_plugin_repository.rb +0 -89
@@ -0,0 +1,398 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2013-2014 Droonga Project
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License version 2.1 as published by the Free Software Foundation.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+
18
+ require "droonga/searcher"
19
+ require "droonga/distributed_command_planner"
20
+
21
+ module Droonga
22
+ module Plugins
23
+ module Search
24
+ class DistributedSearchPlanner < DistributedCommandPlanner
25
+ def initialize(search_request_message)
26
+ super
27
+
28
+ @request = @source_message["body"]
29
+ raise NoQuery.new unless @request
30
+
31
+ @request = Marshal.load(Marshal.dump(@request))
32
+ @queries = @request["queries"]
33
+ end
34
+
35
+ def plan
36
+ raise Searcher::NoQuery.new if @queries.nil? or @queries.empty?
37
+
38
+ Searcher::QuerySorter.validate_dependencies(@queries)
39
+
40
+ ensure_unifiable!
41
+
42
+ @queries.each do |input_name, query|
43
+ transform_query(input_name, query)
44
+ end
45
+
46
+ @dataset = @source_message["dataset"] || @request["dataset"]
47
+ broadcast(:body => @request)
48
+
49
+ super
50
+ end
51
+
52
+ private
53
+ UNLIMITED = -1
54
+
55
+ def reduce_command
56
+ "search_reduce"
57
+ end
58
+
59
+ def gather_command
60
+ "search_gather"
61
+ end
62
+
63
+ def ensure_unifiable!
64
+ @queries.each do |name, query|
65
+ if unifiable?(name) and query["output"]
66
+ query["output"]["unifiable"] = true
67
+ end
68
+ end
69
+ end
70
+
71
+ def unifiable?(name)
72
+ query = @queries[name]
73
+ return true if query["groupBy"]
74
+ name = query["source"]
75
+ return false unless @queries.keys.include?(name)
76
+ unifiable?(name)
77
+ end
78
+
79
+ def transform_query(input_name, query)
80
+ output = query["output"]
81
+
82
+ # Skip reducing phase for a result with no output.
83
+ if output.nil? or
84
+ output["elements"].nil? or
85
+ (!output["elements"].include?("count") and
86
+ !output["elements"].include?("records"))
87
+ return
88
+ end
89
+
90
+ transformer = QueryTransformer.new(query)
91
+
92
+ elements = transformer.mappers
93
+ mapper = {}
94
+ mapper["elements"] = elements unless elements.empty?
95
+ reduce(input_name => { :reduce => transformer.reducers,
96
+ :gather => mapper })
97
+ end
98
+
99
+ class QueryTransformer
100
+ attr_reader :reducers, :mappers
101
+
102
+ def initialize(query)
103
+ @query = query
104
+ @output = @query["output"]
105
+ @reducers = {}
106
+ @mappers = {}
107
+ @output_records = true
108
+ transform!
109
+ end
110
+
111
+ def transform!
112
+ # The collector module supports only "simple" format search results.
113
+ # So we have to override the format and restore it on the gathering
114
+ # phase.
115
+ @records_format = @output["format"] || "simple"
116
+ if @output["format"] and @output["format"] != "simple"
117
+ @output["format"] = "simple"
118
+ end
119
+
120
+ @sort_keys = @query["sortBy"] || []
121
+ @sort_keys = @sort_keys["keys"] || [] if @sort_keys.is_a?(Hash)
122
+
123
+ calculate_offset_and_limit!
124
+ build_count_mapper_and_reducer!
125
+ build_records_mapper_and_reducer!
126
+ end
127
+
128
+ def calculate_offset_and_limit!
129
+ @original_sort_offset = sort_offset
130
+ @original_output_offset = output_offset
131
+ @original_sort_limit = sort_limit
132
+ @original_output_limit = output_limit
133
+
134
+ calculate_sort_offset!
135
+ calculate_output_offset!
136
+
137
+ # We have to calculate limit based on offset.
138
+ # <A, B = limited integer (0...MAXINT)>
139
+ # | sort limit | output limit | => | worker's sort limit | worker's output limit | final limit |
140
+ # ============================= ====================================================================
141
+ # | UNLIMITED | UNLIMITED | => | UNLIMITED | UNLIMITED | UNLIMITED |
142
+ # | UNLIMITED | B | => | final_offset + B | final_offset + B | B |
143
+ # | A | UNLIMITED | => | final_offset + A | final_offset + A | A |
144
+ # | A | B | => | final_offset + max(A, B) | final_offset + min(A, B)| min(A, B) |
145
+
146
+ # XXX final_limit and final_offset calculated in many times
147
+
148
+ @records_offset = final_offset
149
+ @records_limit = final_limit
150
+
151
+ updated_sort_limit = nil
152
+ updated_output_limit = nil
153
+ if final_limit == UNLIMITED
154
+ updated_output_limit = UNLIMITED
155
+ else
156
+ if rich_sort?
157
+ updated_sort_limit = final_offset + [sort_limit, output_limit].max
158
+ end
159
+ updated_output_limit = final_offset + final_limit
160
+ end
161
+
162
+ if updated_sort_limit and updated_sort_limit != @query["sortBy"]["limit"]
163
+ @query["sortBy"]["limit"] = updated_sort_limit
164
+ end
165
+ if updated_output_limit and @output["limit"] and updated_output_limit != @output["limit"]
166
+ @output["limit"] = updated_output_limit
167
+ end
168
+ end
169
+
170
+ def calculate_sort_offset!
171
+ # Offset for workers must be zero, because we have to apply "limit" and
172
+ # "offset" on the last gathering phase instead of each reducing phase.
173
+ if rich_sort?
174
+ @query["sortBy"]["offset"] = 0
175
+ end
176
+ end
177
+
178
+ def sort_offset
179
+ if rich_sort?
180
+ @query["sortBy"]["offset"] || 0
181
+ else
182
+ 0
183
+ end
184
+ end
185
+
186
+ def output_offset
187
+ @output["offset"] || 0
188
+ end
189
+
190
+ def sort_limit
191
+ if rich_sort?
192
+ @query["sortBy"]["limit"] || UNLIMITED
193
+ else
194
+ UNLIMITED
195
+ end
196
+ end
197
+
198
+ def output_limit
199
+ @output["limit"] || 0
200
+ end
201
+
202
+ def calculate_output_offset!
203
+ @output["offset"] = 0 if have_records? and @output["offset"]
204
+ end
205
+
206
+ def final_offset
207
+ @original_sort_offset + @original_output_offset
208
+ end
209
+
210
+ def final_limit
211
+ if @original_sort_limit == UNLIMITED and
212
+ @original_output_limit == UNLIMITED
213
+ UNLIMITED
214
+ else
215
+ if @original_sort_limit == UNLIMITED
216
+ @original_output_limit
217
+ elsif @original_output_limit == UNLIMITED
218
+ @original_sort_limit
219
+ else
220
+ [@original_sort_limit, @original_output_limit].min
221
+ end
222
+ end
223
+ end
224
+
225
+ def have_records?
226
+ @output["elements"].include?("records")
227
+ end
228
+
229
+ def rich_sort?
230
+ @query["sortBy"].is_a?(Hash)
231
+ end
232
+
233
+ def unifiable?
234
+ @output["unifiable"]
235
+ end
236
+
237
+ def build_count_mapper_and_reducer!
238
+ return unless @output["elements"].include?("count")
239
+
240
+ @reducers["count"] = {
241
+ "type" => "sum",
242
+ }
243
+ if unifiable?
244
+ @query["sortBy"]["limit"] = -1 if @query["sortBy"].is_a?(Hash)
245
+ @output["limit"] = -1
246
+ mapper = {
247
+ "target" => "records",
248
+ }
249
+ unless @output["elements"].include?("records")
250
+ @records_limit = -1
251
+ @output["elements"] << "records"
252
+ @output["attributes"] ||= ["_key"]
253
+ @output_records = false
254
+ end
255
+ @mappers["count"] = mapper
256
+ end
257
+ end
258
+
259
+ def build_records_mapper_and_reducer!
260
+ # Skip reducing phase for a result with no record output.
261
+ return if !@output["elements"].include?("records") || @records_limit.zero?
262
+
263
+ # Append sort key attributes to the list of output attributes
264
+ # temporarily, for the reducing phase. After all extra columns
265
+ # are removed on the gathering phase.
266
+ final_attributes = output_attribute_names
267
+ update_output_attributes!
268
+
269
+ @reducers["records"] = build_records_reducer
270
+
271
+ mapper = {}
272
+ if @output_records
273
+ mapper["format"] = @records_format unless @records_format == "simple"
274
+ mapper["attributes"] = final_attributes unless final_attributes.empty?
275
+ mapper["offset"] = @records_offset unless @records_offset.zero?
276
+ mapper["limit"] = @records_limit unless @records_limit.zero?
277
+ else
278
+ mapper["no_output"] = true
279
+ end
280
+ @mappers["records"] = mapper
281
+ end
282
+
283
+ def output_attribute_names
284
+ attributes = @output["attributes"] || []
285
+ if attributes.is_a?(Hash)
286
+ attributes.keys
287
+ else
288
+ attributes.collect do |attribute|
289
+ if attribute.is_a?(Hash)
290
+ attribute["label"] || attribute["source"]
291
+ else
292
+ attribute
293
+ end
294
+ end
295
+ end
296
+ end
297
+
298
+ def update_output_attributes!
299
+ @output["attributes"] = array_style_attributes
300
+ @output["attributes"] += sort_attribute_names
301
+ if unifiable? and !source_column_names.include?("_key")
302
+ @output["attributes"] << "_key"
303
+ end
304
+ end
305
+
306
+ def array_style_attributes
307
+ attributes = @output["attributes"] || []
308
+ if attributes.is_a?(Hash)
309
+ attributes.keys.collect do |key|
310
+ attribute = attributes[key]
311
+ case attribute
312
+ when String
313
+ {
314
+ "label" => key,
315
+ "source" => attribute,
316
+ }
317
+ when Hash
318
+ attribute["label"] = key
319
+ attribute
320
+ end
321
+ end
322
+ else
323
+ attributes
324
+ end
325
+ end
326
+
327
+ def source_column_names
328
+ attributes = @output["attributes"] || []
329
+ if attributes.is_a?(Hash)
330
+ attributes_hash = attributes
331
+ attributes = []
332
+ attributes_hash.each do |key, attribute|
333
+ attributes << attribute["source"] || key
334
+ end
335
+ attributes
336
+ else
337
+ attributes.collect do |attribute|
338
+ if attribute.is_a?(Hash)
339
+ attribute["source"] || attribute["label"]
340
+ else
341
+ attribute
342
+ end
343
+ end
344
+ end
345
+ end
346
+
347
+ def sort_attribute_names
348
+ sort_attributes = @sort_keys.collect do |key|
349
+ key = key[1..-1] if key[0] == "-"
350
+ key
351
+ end
352
+ attributes = source_column_names
353
+ sort_attributes.reject! do |attribute|
354
+ attributes.include?(attribute)
355
+ end
356
+ sort_attributes
357
+ end
358
+
359
+ ASCENDING_OPERATOR = "<"
360
+ DESCENDING_OPERATOR = ">"
361
+
362
+ def build_records_reducer
363
+ attributes = source_column_names
364
+ key_column_index = attributes.index("_key")
365
+
366
+ operators = @sort_keys.collect do |sort_key|
367
+ operator = ASCENDING_OPERATOR
368
+ if sort_key[0] == "-"
369
+ operator = DESCENDING_OPERATOR
370
+ sort_key = sort_key[1..-1]
371
+ end
372
+ {
373
+ "operator" => operator,
374
+ "column" => attributes.index(sort_key),
375
+ }
376
+ end
377
+
378
+ reducer = {
379
+ "type" => "sort",
380
+ "operators" => operators,
381
+ }
382
+ if unifiable? and !key_column_index.nil?
383
+ reducer["key_column"] = key_column_index
384
+ end
385
+
386
+ # On the reducing phase, we apply only "limit". We cannot apply
387
+ # "offset" on this phase because the collector merges a pair of
388
+ # results step by step even if there are three or more results.
389
+ # Instead, we apply "offset" on the gathering phase.
390
+ reducer["limit"] = @output["limit"]
391
+
392
+ reducer
393
+ end
394
+ end
395
+ end
396
+ end
397
+ end
398
+ end
@@ -21,7 +21,8 @@ require "droonga/watch_schema"
21
21
  module Droonga
22
22
  module Plugins
23
23
  module Watch
24
- Plugin.registry.register("watch", self)
24
+ extend Plugin
25
+ register("watch")
25
26
 
26
27
  module SchemaCreatable
27
28
  private
@@ -51,7 +52,11 @@ module Droonga
51
52
  subscriber = request["subscriber"]
52
53
  condition = request["condition"]
53
54
  route = request["route"] || message["from"]
54
- query = condition && condition.to_json
55
+ if condition
56
+ query = condition.to_json
57
+ else
58
+ query = nilondition
59
+ end
55
60
  [subscriber, condition, query, route]
56
61
  end
57
62
  end
@@ -60,14 +65,12 @@ module Droonga
60
65
  include SchemaCreatable
61
66
  include MessageParsable
62
67
 
63
- message.type = "watch.subscribe"
64
-
65
68
  def initialize(*args)
66
69
  super
67
70
  ensure_schema_created # TODO: REMOVE ME
68
71
  end
69
72
 
70
- def handle(message, messenger)
73
+ def handle(message)
71
74
  subscriber, condition, query, route = parse_message(message)
72
75
  normalized_request = {
73
76
  :subscriber => subscriber,
@@ -77,25 +80,27 @@ module Droonga
77
80
  }
78
81
  watcher = Watcher.new(@context)
79
82
  watcher.subscribe(normalized_request)
80
- outputs = {
81
- "success" => true,
82
- }
83
- messenger.emit(outputs)
83
+ true
84
84
  end
85
85
  end
86
86
 
87
+ define_single_step do |step|
88
+ step.name = "watch.subscribe"
89
+ step.write = true
90
+ step.handler = SubscribeHandler
91
+ step.collector = Collectors::And
92
+ end
93
+
87
94
  class UnsubscribeHandler < Droonga::Handler
88
95
  include SchemaCreatable
89
96
  include MessageParsable
90
97
 
91
- message.type = "watch.unsubscribe"
92
-
93
98
  def initialize(*args)
94
99
  super
95
100
  ensure_schema_created # TODO: REMOVE ME
96
101
  end
97
102
 
98
- def handle(message, messenger)
103
+ def handle(message)
99
104
  subscriber, condition, query, route = parse_message(message)
100
105
  normalized_request = {
101
106
  :subscriber => subscriber,
@@ -104,24 +109,26 @@ module Droonga
104
109
  }
105
110
  watcher = Watcher.new(@context)
106
111
  watcher.unsubscribe(normalized_request)
107
- outputs = {
108
- "success" => true,
109
- }
110
- messenger.emit(outputs)
112
+ true
111
113
  end
112
114
  end
113
115
 
116
+ define_single_step do |step|
117
+ step.name = "watch.unsubscribe"
118
+ step.write = true
119
+ step.handler = UnsubscribeHandler
120
+ step.collector = Collectors::And
121
+ end
122
+
114
123
  class FeedHandler < Droonga::Handler
115
124
  include SchemaCreatable
116
125
 
117
- message.type = "watch.feed"
118
-
119
126
  def initialize(*args)
120
127
  super
121
128
  ensure_schema_created # TODO: REMOVE ME
122
129
  end
123
130
 
124
- def handle(message, messenger)
131
+ def handle(message)
125
132
  request = message.request
126
133
  watcher = Watcher.new(@context)
127
134
  watcher.feed(:targets => request["targets"]) do |route, subscribers|
@@ -133,9 +140,16 @@ module Droonga
133
140
  messenger.forward(published_message,
134
141
  "to" => route, "type" => "watch.publish")
135
142
  end
143
+ nil
136
144
  end
137
145
  end
138
146
 
147
+ define_single_step do |step|
148
+ step.name = "watch.feed"
149
+ step.write = true
150
+ step.handler = FeedHandler
151
+ end
152
+
139
153
  class SweepHandler < Droonga::Handler
140
154
  include SchemaCreatable
141
155
 
@@ -146,11 +160,18 @@ module Droonga
146
160
  ensure_schema_created # TODO: REMOVE ME
147
161
  end
148
162
 
149
- def sweep(message, messenger)
163
+ def handle(message)
150
164
  sweeper = Sweeper.new(@context)
151
165
  sweeper.sweep_expired_subscribers
166
+ nil
152
167
  end
153
168
  end
169
+
170
+ define_single_step do |step|
171
+ step.name = "watch.sweep"
172
+ step.write = true
173
+ step.handler = SweepHandler
174
+ end
154
175
  end
155
176
  end
156
177
  end