bricolage-streamingload 0.1.0 → 0.3.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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/bricolage/snsdatasource.rb +40 -0
- data/lib/bricolage/sqsdatasource.rb +86 -42
- data/lib/bricolage/streamingload/alertinglogger.rb +19 -0
- data/lib/bricolage/streamingload/dispatcher.rb +14 -12
- data/lib/bricolage/streamingload/loaderservice.rb +8 -1
- data/lib/bricolage/streamingload/version.rb +1 -1
- data/test/streamingload/test_event.rb +2 -1
- data/test/test_sqsdatasource.rb +113 -0
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d81ff86cb9addccb7ca9db4d240218679b1f72f9
|
4
|
+
data.tar.gz: f2ec045c994f1c6b619695f74a13aebcc9318722
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a78c3b8f35f8d10cbc3da301667ea811874ccadb7653b02388990d63afc2183ee3d0c4e357dccc7799721e1dcd8e33b88e9b3d66147903c32ff109595bced0f6
|
7
|
+
data.tar.gz: a3632f13d3ea039aa690deca646659e0d89ad636b2af55abf5f7011f54cfecddcef53d57152de513bcbaf5c03671af7a512a10781e7846efc60af9c752b8c364
|
data/README.md
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'bricolage/datasource'
|
2
|
+
require 'aws-sdk'
|
3
|
+
require 'json'
|
4
|
+
require 'time'
|
5
|
+
|
6
|
+
module Bricolage
|
7
|
+
|
8
|
+
class SNSTopicDataSource < DataSource
|
9
|
+
|
10
|
+
declare_type 'sns'
|
11
|
+
|
12
|
+
def initialize(region: 'ap-northeast-1', topic_arn:, access_key_id:, secret_access_key:)
|
13
|
+
@region = region
|
14
|
+
@topic_arn = topic_arn
|
15
|
+
@access_key_id = access_key_id
|
16
|
+
@secret_access_key = secret_access_key
|
17
|
+
@client = Aws::SNS::Client.new(region: region, access_key_id: access_key_id, secret_access_key: secret_access_key)
|
18
|
+
@topic = Aws::SNS::Topic.new(topic_arn, client: @client)
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :region
|
22
|
+
attr_reader :client, :topic
|
23
|
+
|
24
|
+
def publish(message)
|
25
|
+
@topic.publish(build_message(message))
|
26
|
+
end
|
27
|
+
|
28
|
+
alias write publish
|
29
|
+
|
30
|
+
def close
|
31
|
+
# do nothing
|
32
|
+
end
|
33
|
+
|
34
|
+
def build_message(message)
|
35
|
+
{message: message}
|
36
|
+
end
|
37
|
+
|
38
|
+
end # SNSDataSource
|
39
|
+
|
40
|
+
end # module Bricolage
|
@@ -12,14 +12,13 @@ module Bricolage
|
|
12
12
|
declare_type 'sqs'
|
13
13
|
|
14
14
|
def initialize(region: 'ap-northeast-1', url:, access_key_id:, secret_access_key:,
|
15
|
-
visibility_timeout:, max_number_of_messages: 10,
|
15
|
+
visibility_timeout:, max_number_of_messages: 10, wait_time_seconds: 20, noop: false)
|
16
16
|
@region = region
|
17
17
|
@url = url
|
18
18
|
@access_key_id = access_key_id
|
19
19
|
@secret_access_key = secret_access_key
|
20
20
|
@visibility_timeout = visibility_timeout
|
21
21
|
@max_number_of_messages = max_number_of_messages
|
22
|
-
@max_delete_batch_size = max_delete_batch_size
|
23
22
|
@wait_time_seconds = wait_time_seconds
|
24
23
|
@noop = noop
|
25
24
|
end
|
@@ -40,20 +39,21 @@ module Bricolage
|
|
40
39
|
# High-Level Polling Interface
|
41
40
|
#
|
42
41
|
|
43
|
-
def main_handler_loop(handlers)
|
42
|
+
def main_handler_loop(handlers:, message_class:)
|
44
43
|
trap_signals
|
45
44
|
|
46
45
|
n_zero = 0
|
47
46
|
until terminating?
|
48
47
|
insert_handler_wait(n_zero)
|
49
|
-
n_msg = handle_messages(handlers)
|
48
|
+
n_msg = handle_messages(handlers: handlers, message_class: message_class)
|
50
49
|
if n_msg == 0
|
51
50
|
n_zero += 1
|
52
51
|
else
|
53
52
|
n_zero = 0
|
54
53
|
end
|
54
|
+
delete_message_buffer.flush
|
55
55
|
end
|
56
|
-
|
56
|
+
delete_message_buffer.flush_force
|
57
57
|
logger.info "shutdown gracefully"
|
58
58
|
end
|
59
59
|
|
@@ -115,8 +115,6 @@ module Bricolage
|
|
115
115
|
def receive_messages
|
116
116
|
result = client.receive_message(
|
117
117
|
queue_url: @url,
|
118
|
-
attribute_names: ["All"],
|
119
|
-
message_attribute_names: ["All"],
|
120
118
|
max_number_of_messages: @max_number_of_messages,
|
121
119
|
visibility_timeout: @visibility_timeout,
|
122
120
|
wait_time_seconds: @wait_time_seconds
|
@@ -125,19 +123,18 @@ module Bricolage
|
|
125
123
|
end
|
126
124
|
|
127
125
|
def delete_message(msg)
|
128
|
-
# TODO: use batch request?
|
129
126
|
client.delete_message(
|
130
127
|
queue_url: @url,
|
131
128
|
receipt_handle: msg.receipt_handle
|
132
129
|
)
|
133
130
|
end
|
134
131
|
|
135
|
-
def
|
132
|
+
def delete_message_async(msg)
|
136
133
|
delete_message_buffer.put(msg)
|
137
134
|
end
|
138
135
|
|
139
136
|
def delete_message_buffer
|
140
|
-
@delete_message_buffer ||= DeleteMessageBuffer.new(client, @url,
|
137
|
+
@delete_message_buffer ||= DeleteMessageBuffer.new(client, @url, logger)
|
141
138
|
end
|
142
139
|
|
143
140
|
def put(msg)
|
@@ -154,60 +151,107 @@ module Bricolage
|
|
154
151
|
|
155
152
|
class DeleteMessageBuffer
|
156
153
|
|
157
|
-
|
154
|
+
BATCH_SIZE_MAX = 10 # SQS system limit
|
155
|
+
MAX_RETRY_COUNT = 3
|
156
|
+
|
157
|
+
def initialize(sqs_client, url, logger)
|
158
158
|
@sqs_client = sqs_client
|
159
159
|
@url = url
|
160
|
-
@max_buffer_size = max_buffer_size
|
161
160
|
@logger = logger
|
162
161
|
@buf = {}
|
163
|
-
@retry_counts = Hash.new(0)
|
164
162
|
end
|
165
163
|
|
166
|
-
MAX_RETRY_COUNT = 3
|
167
|
-
|
168
164
|
def put(msg)
|
169
|
-
|
170
|
-
|
165
|
+
ent = Entry.new(msg)
|
166
|
+
@buf[ent.id] = ent
|
167
|
+
flush if full?
|
168
|
+
end
|
169
|
+
|
170
|
+
def empty?
|
171
|
+
@buf.empty?
|
172
|
+
end
|
173
|
+
|
174
|
+
def full?
|
175
|
+
@buf.size >= BATCH_SIZE_MAX
|
171
176
|
end
|
172
177
|
|
173
178
|
def size
|
174
179
|
@buf.size
|
175
180
|
end
|
176
181
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
entries: @buf.to_a.map {|item| {id: item[0], receipt_handle: item[1].receipt_handle} }
|
182
|
-
})
|
183
|
-
clear_successes(response.successful)
|
184
|
-
retry_failures(response.failed)
|
185
|
-
@logger.debug "DeleteMessageBatch executed: #{response.successful.size} succeeded, #{response.failed.size} failed."
|
182
|
+
# Flushes all delayed delete requests, including pending requests
|
183
|
+
def flush_force
|
184
|
+
# retry continues in only 2m, now+1h must be after than all @next_issue_time
|
185
|
+
flush(Time.now + 3600)
|
186
186
|
end
|
187
187
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
188
|
+
def flush(now = Time.now)
|
189
|
+
entries = @buf.values.select {|ent| ent.issuable?(now) }
|
190
|
+
return if entries.empty?
|
191
|
+
@logger.info "flushing async delete requests"
|
192
|
+
entries.each_slice(BATCH_SIZE_MAX) do |ents|
|
193
|
+
res = @sqs_client.delete_message_batch(queue_url: @url, entries: ents.map(&:request_params))
|
194
|
+
@logger.info "DeleteMessageBatch executed: #{res.successful.size} succeeded, #{res.failed.size} failed"
|
195
|
+
issued_time = Time.now
|
196
|
+
res.successful.each do |s|
|
197
|
+
@buf.delete s.id
|
198
|
+
end
|
199
|
+
res.failed.each do |f|
|
200
|
+
ent = @buf[f.id]
|
201
|
+
unless ent
|
202
|
+
@logger.error "[BUG] no corrensponding DeleteMessageBuffer entry: id=#{f.id}"
|
203
|
+
next
|
204
|
+
end
|
205
|
+
ent.failed!(issued_time)
|
206
|
+
if ent.too_many_failure?
|
207
|
+
@logger.warn "DeleteMessage failure count exceeded the limit; give up: message_id=#{ent.message.message_id}, receipt_handle=#{ent.message.receipt_handle}"
|
208
|
+
@buf.delete f.id
|
209
|
+
next
|
210
|
+
end
|
211
|
+
@logger.info "DeleteMessageBatch partially failed (#{ent.n_failure} times): sender_fault=#{f.sender_fault}, code=#{f.code}, message=#{f.message}"
|
212
|
+
end
|
193
213
|
end
|
194
214
|
end
|
195
215
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
@
|
216
|
+
class Entry
|
217
|
+
def initialize(msg)
|
218
|
+
@message = msg
|
219
|
+
@id = SecureRandom.uuid
|
220
|
+
@n_failure = 0
|
221
|
+
@last_issued_time = nil
|
222
|
+
@next_issue_time = nil
|
200
223
|
end
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
224
|
+
|
225
|
+
attr_reader :id
|
226
|
+
attr_reader :message
|
227
|
+
attr_reader :n_failure
|
228
|
+
|
229
|
+
def issuable?(now)
|
230
|
+
@n_failure == 0 or now > @next_issue_time
|
231
|
+
end
|
232
|
+
|
233
|
+
def failed!(issued_time = Time.now)
|
234
|
+
@n_failure += 1
|
235
|
+
@last_issued_time = issued_time
|
236
|
+
@next_issue_time = @last_issued_time + next_retry_interval
|
237
|
+
end
|
238
|
+
|
239
|
+
def next_retry_interval
|
240
|
+
# 16s, 32s, 64s -> total 2m
|
241
|
+
2 ** (3 + @n_failure)
|
242
|
+
end
|
243
|
+
|
244
|
+
def too_many_failure?
|
245
|
+
# (first request) + (3 retry requests) = (4 requests)
|
246
|
+
@n_failure > MAX_RETRY_COUNT
|
247
|
+
end
|
248
|
+
|
249
|
+
def request_params
|
250
|
+
{ id: @id, receipt_handle: @message.receipt_handle }
|
207
251
|
end
|
208
252
|
end
|
209
253
|
|
210
|
-
end # DeleteMessageBuffer
|
254
|
+
end # class DeleteMessageBuffer
|
211
255
|
|
212
256
|
end # class SQSDataSource
|
213
257
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Bricolage
|
2
|
+
module StreamingLoad
|
3
|
+
class AlertingLogger
|
4
|
+
extend Forwardable
|
5
|
+
|
6
|
+
def initialize(logger: , sns_datasource: , alert_level: 'warn')
|
7
|
+
@logger = logger
|
8
|
+
@sns_logger = Bricolage::Logger.new(device: sns_datasource)
|
9
|
+
@sns_logger.level = Kernel.const_get("Logger").const_get(alert_level.upcase)
|
10
|
+
end
|
11
|
+
|
12
|
+
%w(log debug info warn error fatal unknown).each do |m|
|
13
|
+
define_method(m) do |*args|
|
14
|
+
[@logger, @sns_logger].map {|t| t.send(m, *args) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -5,6 +5,7 @@ require 'bricolage/logger'
|
|
5
5
|
require 'bricolage/streamingload/event'
|
6
6
|
require 'bricolage/streamingload/objectbuffer'
|
7
7
|
require 'bricolage/streamingload/urlpatterns'
|
8
|
+
require 'bricolage/streamingload/alertinglogger'
|
8
9
|
require 'aws-sdk'
|
9
10
|
require 'yaml'
|
10
11
|
require 'optparse'
|
@@ -29,10 +30,15 @@ module Bricolage
|
|
29
30
|
ctx = Context.for_application('.', environment: opts.environment, logger: logger)
|
30
31
|
event_queue = ctx.get_data_source('sqs', config.fetch('event-queue-ds'))
|
31
32
|
task_queue = ctx.get_data_source('sqs', config.fetch('task-queue-ds'))
|
33
|
+
alert_logger = AlertingLogger.new(
|
34
|
+
logger: ctx.logger,
|
35
|
+
sns_datasource: ctx.get_data_source('sns', config.fetch('sns-ds')),
|
36
|
+
alert_level: config.fetch('alert-level', 'warn')
|
37
|
+
)
|
32
38
|
|
33
39
|
object_buffer = ObjectBuffer.new(
|
34
40
|
control_data_source: ctx.get_data_source('sql', config.fetch('ctl-postgres-ds')),
|
35
|
-
logger:
|
41
|
+
logger: alert_logger
|
36
42
|
)
|
37
43
|
|
38
44
|
url_patterns = URLPatterns.for_config(config.fetch('url_patterns'))
|
@@ -43,7 +49,7 @@ module Bricolage
|
|
43
49
|
object_buffer: object_buffer,
|
44
50
|
url_patterns: url_patterns,
|
45
51
|
dispatch_interval: 60,
|
46
|
-
logger:
|
52
|
+
logger: alert_logger
|
47
53
|
)
|
48
54
|
|
49
55
|
Process.daemon(true) if opts.daemon?
|
@@ -84,17 +90,18 @@ module Bricolage
|
|
84
90
|
|
85
91
|
def handle_shutdown(e)
|
86
92
|
@event_queue.initiate_terminate
|
93
|
+
# Delete this event immediately
|
87
94
|
@event_queue.delete_message(e)
|
88
95
|
end
|
89
96
|
|
90
97
|
def handle_data(e)
|
91
98
|
unless e.created?
|
92
|
-
@event_queue.
|
99
|
+
@event_queue.delete_message_async(e)
|
93
100
|
return
|
94
101
|
end
|
95
102
|
obj = e.loadable_object(@url_patterns)
|
96
103
|
@object_buffer.put(obj)
|
97
|
-
@event_queue.
|
104
|
+
@event_queue.delete_message_async(e)
|
98
105
|
end
|
99
106
|
|
100
107
|
def handle_dispatch(e)
|
@@ -103,18 +110,13 @@ module Bricolage
|
|
103
110
|
tasks.each {|task| @task_queue.put task }
|
104
111
|
set_dispatch_timer
|
105
112
|
end
|
113
|
+
# Delete this event immediately
|
106
114
|
@event_queue.delete_message(e)
|
107
115
|
end
|
108
116
|
|
109
117
|
def set_dispatch_timer
|
110
|
-
|
111
|
-
@dispatch_message_id =
|
112
|
-
end
|
113
|
-
|
114
|
-
def delete_events(events)
|
115
|
-
events.each do |e|
|
116
|
-
@event_queue.delete_message(e)
|
117
|
-
end
|
118
|
+
res = @event_queue.send_message(DispatchEvent.create(delay_seconds: @dispatch_interval))
|
119
|
+
@dispatch_message_id = res.message_id
|
118
120
|
end
|
119
121
|
|
120
122
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'bricolage/sqsdatasource'
|
2
2
|
require 'bricolage/streamingload/task'
|
3
3
|
require 'bricolage/streamingload/loader'
|
4
|
+
require 'bricolage/streamingload/alertinglogger'
|
4
5
|
require 'bricolage/logger'
|
5
6
|
require 'bricolage/exception'
|
6
7
|
require 'bricolage/version'
|
@@ -25,13 +26,18 @@ module Bricolage
|
|
25
26
|
ctx = Context.for_application('.', environment: opts.environment, logger: logger)
|
26
27
|
redshift_ds = ctx.get_data_source('sql', config.fetch('redshift-ds'))
|
27
28
|
task_queue = ctx.get_data_source('sqs', config.fetch('task-queue-ds'))
|
29
|
+
alert_logger = AlertingLogger.new(
|
30
|
+
logger: ctx.logger,
|
31
|
+
sns_datasource: ctx.get_data_source('sns', config.fetch('sns-ds')),
|
32
|
+
alert_level: config.fetch('alert-level', 'warn')
|
33
|
+
)
|
28
34
|
|
29
35
|
service = new(
|
30
36
|
context: ctx,
|
31
37
|
control_data_source: ctx.get_data_source('sql', config.fetch('ctl-postgres-ds')),
|
32
38
|
data_source: redshift_ds,
|
33
39
|
task_queue: task_queue,
|
34
|
-
logger:
|
40
|
+
logger: alert_logger
|
35
41
|
)
|
36
42
|
|
37
43
|
if opts.task_id
|
@@ -89,6 +95,7 @@ module Bricolage
|
|
89
95
|
loadtask = load_task(task.id, force: task.force)
|
90
96
|
return if loadtask.disabled # skip if disabled, but don't delete sqs msg
|
91
97
|
execute_task(loadtask)
|
98
|
+
# Delete load task immediately (do not use async delete)
|
92
99
|
@task_queue.delete_message(task)
|
93
100
|
end
|
94
101
|
|
@@ -5,12 +5,13 @@ module Bricolage::StreamingLoad
|
|
5
5
|
|
6
6
|
class TestEvent < Test::Unit::TestCase
|
7
7
|
|
8
|
-
def new_s3event(message_id: nil, receipt_handle: nil, name: nil, time: nil, region: nil, bucket: nil, key: nil, size: nil)
|
8
|
+
def new_s3event(message_id: nil, receipt_handle: nil, name: nil, time: nil, source: nil, region: nil, bucket: nil, key: nil, size: nil)
|
9
9
|
S3ObjectEvent.new(
|
10
10
|
message_id: message_id,
|
11
11
|
receipt_handle: receipt_handle,
|
12
12
|
name: name,
|
13
13
|
time: time,
|
14
|
+
source: source,
|
14
15
|
region: region,
|
15
16
|
bucket: bucket,
|
16
17
|
key: key,
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'bricolage/streamingload/event'
|
3
|
+
require 'bricolage/logger'
|
4
|
+
|
5
|
+
module Bricolage
|
6
|
+
|
7
|
+
class TestSQSDataSource < Test::Unit::TestCase
|
8
|
+
|
9
|
+
def new_sqs_ds(mock_client = nil)
|
10
|
+
SQSDataSource.new(
|
11
|
+
url: 'http://sqs/000000000000/queue-name',
|
12
|
+
access_key_id: 'access_key_id_1',
|
13
|
+
secret_access_key: 'secret_access_key_1',
|
14
|
+
visibility_timeout: 30
|
15
|
+
).tap {|ds|
|
16
|
+
logger = NullLogger.new
|
17
|
+
#logger = Bricolage::Logger.default
|
18
|
+
ds.__send__(:initialize_base, 'name', nil, logger)
|
19
|
+
ds.instance_variable_set(:@client, mock_client) if mock_client
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
class MockSQSClient
|
24
|
+
def initialize(&block)
|
25
|
+
@handler = block
|
26
|
+
end
|
27
|
+
|
28
|
+
def delete_message_batch(**args)
|
29
|
+
@handler.call(args)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class NullLogger
|
34
|
+
def debug(*args) end
|
35
|
+
def info(*args) end
|
36
|
+
def warn(*args) end
|
37
|
+
def error(*args) end
|
38
|
+
def exception(*args) end
|
39
|
+
def with_elapsed_time(*args) yield end
|
40
|
+
def elapsed_time(*args) yield end
|
41
|
+
end
|
42
|
+
|
43
|
+
def sqs_message(seq)
|
44
|
+
MockSQSMessage.new("message_id_#{seq}", "receipt_handle_#{seq}")
|
45
|
+
end
|
46
|
+
|
47
|
+
MockSQSMessage = Struct.new(:message_id, :receipt_handle)
|
48
|
+
|
49
|
+
class MockSQSResponse
|
50
|
+
def initialize(successful: [], failed: [])
|
51
|
+
@successful = successful
|
52
|
+
@failed = failed
|
53
|
+
end
|
54
|
+
|
55
|
+
attr_reader :successful
|
56
|
+
attr_reader :failed
|
57
|
+
|
58
|
+
Success = Struct.new(:id)
|
59
|
+
Failure = Struct.new(:id, :sender_fault, :code, :message)
|
60
|
+
|
61
|
+
def add_success_for(ent)
|
62
|
+
@successful.push Success.new(ent[:id])
|
63
|
+
end
|
64
|
+
|
65
|
+
def add_failure_for(ent)
|
66
|
+
@failed.push Failure.new(ent[:id], true, '400', 'some reason')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
test "#delete_message_async" do
|
71
|
+
messages = [sqs_message(0), sqs_message(1), sqs_message(2)]
|
72
|
+
mock = MockSQSClient.new {|args|
|
73
|
+
entries = args[:entries]
|
74
|
+
if entries.size == 3
|
75
|
+
# first time
|
76
|
+
assert_equal messages[0].receipt_handle, entries[0][:receipt_handle]
|
77
|
+
assert_equal messages[1].receipt_handle, entries[1][:receipt_handle]
|
78
|
+
assert_equal messages[2].receipt_handle, entries[2][:receipt_handle]
|
79
|
+
MockSQSResponse.new.tap {|res|
|
80
|
+
res.add_success_for(entries[0])
|
81
|
+
res.add_failure_for(entries[1])
|
82
|
+
res.add_success_for(entries[2])
|
83
|
+
}
|
84
|
+
else
|
85
|
+
# second time
|
86
|
+
MockSQSResponse.new.tap {|res|
|
87
|
+
res.add_success_for(entries[0])
|
88
|
+
}
|
89
|
+
end
|
90
|
+
}
|
91
|
+
ds = new_sqs_ds(mock)
|
92
|
+
ds.delete_message_async(messages[0])
|
93
|
+
ds.delete_message_async(messages[1])
|
94
|
+
ds.delete_message_async(messages[2])
|
95
|
+
|
96
|
+
# first flush
|
97
|
+
flush_time = Time.now
|
98
|
+
ds.delete_message_buffer.flush(flush_time)
|
99
|
+
assert_equal 1, ds.delete_message_buffer.size
|
100
|
+
bufent = ds.delete_message_buffer.instance_variable_get(:@buf).values.first
|
101
|
+
assert_equal 'receipt_handle_1', bufent.message.receipt_handle
|
102
|
+
assert_equal 1, bufent.n_failure
|
103
|
+
assert_false bufent.issuable?(flush_time)
|
104
|
+
assert_true bufent.issuable?(flush_time + 180)
|
105
|
+
|
106
|
+
# second flush
|
107
|
+
ds.delete_message_buffer.flush(flush_time + 180)
|
108
|
+
assert_true ds.delete_message_buffer.empty?
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bricolage-streamingload
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Minero Aoki
|
@@ -107,8 +107,10 @@ files:
|
|
107
107
|
- README.md
|
108
108
|
- bin/bricolage-streaming-dispatcher
|
109
109
|
- bin/bricolage-streaming-loader
|
110
|
+
- lib/bricolage/snsdatasource.rb
|
110
111
|
- lib/bricolage/sqsdatasource.rb
|
111
112
|
- lib/bricolage/sqswrapper.rb
|
113
|
+
- lib/bricolage/streamingload/alertinglogger.rb
|
112
114
|
- lib/bricolage/streamingload/dispatcher.rb
|
113
115
|
- lib/bricolage/streamingload/event.rb
|
114
116
|
- lib/bricolage/streamingload/loader.rb
|
@@ -121,6 +123,7 @@ files:
|
|
121
123
|
- lib/bricolage/streamingload/version.rb
|
122
124
|
- test/all.rb
|
123
125
|
- test/streamingload/test_event.rb
|
126
|
+
- test/test_sqsdatasource.rb
|
124
127
|
homepage: https://github.com/aamine/bricolage-streamingload
|
125
128
|
licenses:
|
126
129
|
- MIT
|