bricolage-streamingload 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/bricolage-streaming-loader +2 -2
- data/lib/bricolage/sqsmock.rb +0 -1
- data/lib/bricolage/streamingload/dispatcher.rb +2 -1
- data/lib/bricolage/streamingload/job.rb +387 -0
- data/lib/bricolage/streamingload/{loaderparams.rb → jobparams.rb} +14 -39
- data/lib/bricolage/streamingload/manifest.rb +7 -1
- data/lib/bricolage/streamingload/objectbuffer.rb +0 -3
- data/lib/bricolage/streamingload/task.rb +5 -68
- data/lib/bricolage/streamingload/{loaderservice.rb → taskhandler.rb} +102 -61
- data/lib/bricolage/streamingload/version.rb +1 -1
- data/test/streamingload/test_dispatcher.rb +6 -6
- data/test/streamingload/test_job.rb +438 -0
- metadata +8 -9
- data/lib/bricolage/nulllogger.rb +0 -20
- data/lib/bricolage/snsdatasource.rb +0 -40
- data/lib/bricolage/streamingload/loader.rb +0 -158
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'bricolage/context'
|
2
2
|
require 'bricolage/sqsdatasource'
|
3
3
|
require 'bricolage/streamingload/task'
|
4
|
-
require 'bricolage/streamingload/
|
4
|
+
require 'bricolage/streamingload/job'
|
5
5
|
require 'bricolage/streamingload/alertinglogger'
|
6
6
|
require 'bricolage/logger'
|
7
7
|
require 'bricolage/exception'
|
@@ -13,60 +13,60 @@ module Bricolage
|
|
13
13
|
|
14
14
|
module StreamingLoad
|
15
15
|
|
16
|
-
class
|
16
|
+
class TaskHandler < SQSDataSource::MessageHandler
|
17
17
|
|
18
|
-
def
|
19
|
-
opts =
|
18
|
+
def TaskHandler.main
|
19
|
+
opts = TaskHandlerOptions.new(ARGV)
|
20
20
|
opts.parse
|
21
|
-
unless opts.rest_arguments.size
|
21
|
+
unless opts.rest_arguments.size <= 1
|
22
22
|
$stderr.puts opts.usage
|
23
23
|
exit 1
|
24
24
|
end
|
25
|
-
config_path
|
25
|
+
config_path = opts.rest_arguments[0] || "#{opts.working_dir}/config/#{opts.environment}/streamingload.yml"
|
26
26
|
config = YAML.load(File.read(config_path))
|
27
|
+
|
27
28
|
logger = opts.log_file_path ? new_logger(opts.log_file_path, config) : nil
|
28
29
|
ctx = Context.for_application(opts.working_dir, environment: opts.environment, logger: logger)
|
29
|
-
|
30
|
+
|
31
|
+
ctl_ds = ctx.get_data_source('sql', config.fetch('ctl-postgres-ds', 'db_ctl'))
|
30
32
|
task_queue = ctx.get_data_source('sqs', config.fetch('task-queue-ds', 'sqs_task'))
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
)
|
38
|
-
end
|
33
|
+
service_logger =
|
34
|
+
if config.key?('alert-level')
|
35
|
+
new_alerting_logger(ctx, config)
|
36
|
+
else
|
37
|
+
ctx.logger
|
38
|
+
end
|
39
39
|
|
40
|
-
|
40
|
+
task_handler = new(
|
41
41
|
context: ctx,
|
42
|
-
|
43
|
-
data_source: redshift_ds,
|
42
|
+
ctl_ds: ctl_ds,
|
44
43
|
task_queue: task_queue,
|
45
44
|
working_dir: opts.working_dir,
|
46
|
-
logger:
|
45
|
+
logger: service_logger,
|
46
|
+
job_class: opts.noop? ? NoopJob : Job
|
47
47
|
)
|
48
48
|
|
49
49
|
if opts.task_id
|
50
50
|
# Single task mode
|
51
|
-
|
51
|
+
task_handler.execute_task_by_id opts.task_id, force: opts.force?
|
52
52
|
else
|
53
53
|
# Server mode
|
54
54
|
Process.daemon(true) if opts.daemon?
|
55
55
|
Dir.chdir '/'
|
56
56
|
create_pid_file opts.pid_file_path if opts.pid_file_path
|
57
57
|
begin
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
service_logger.info "*** bricolage-streaming-loader started: pid=#{$$}"
|
59
|
+
task_handler.event_loop
|
60
|
+
service_logger.info "*** bricolage-streaming-loader shutdown gracefully: pid=#{$$}"
|
61
61
|
rescue Exception => ex
|
62
|
-
|
63
|
-
|
62
|
+
service_logger.exception(ex)
|
63
|
+
service_logger.error "*** bricolage-streaming-loader abort: pid=#{$$}"
|
64
64
|
raise
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
def
|
69
|
+
def TaskHandler.new_logger(path, config)
|
70
70
|
Logger.new(
|
71
71
|
device: path,
|
72
72
|
rotation_period: config.fetch('log-rotation-period', 'daily'),
|
@@ -74,7 +74,15 @@ module Bricolage
|
|
74
74
|
)
|
75
75
|
end
|
76
76
|
|
77
|
-
def
|
77
|
+
def TaskHandler.new_alerting_logger(ctx, config)
|
78
|
+
AlertingLogger.new(
|
79
|
+
logger: ctx.logger,
|
80
|
+
sns_datasource: ctx.get_data_source('sns', config.fetch('sns-ds', 'sns')),
|
81
|
+
alert_level: config.fetch('alert-level', 'warn')
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
def TaskHandler.create_pid_file(path)
|
78
86
|
File.open(path, 'w') {|f|
|
79
87
|
f.puts $$
|
80
88
|
}
|
@@ -82,76 +90,91 @@ module Bricolage
|
|
82
90
|
# ignore
|
83
91
|
end
|
84
92
|
|
85
|
-
def initialize(context:,
|
93
|
+
def initialize(context:, ctl_ds:, task_queue:, working_dir:, logger:, job_class: Job)
|
86
94
|
@ctx = context
|
87
|
-
@ctl_ds =
|
88
|
-
@ds = data_source
|
95
|
+
@ctl_ds = ctl_ds
|
89
96
|
@task_queue = task_queue
|
90
97
|
@working_dir = working_dir
|
91
98
|
@logger = logger
|
99
|
+
@job_class = job_class
|
92
100
|
end
|
93
101
|
|
94
102
|
attr_reader :logger
|
95
103
|
|
96
|
-
def
|
97
|
-
@
|
98
|
-
|
99
|
-
|
100
|
-
def execute_task_by_id(task_id)
|
101
|
-
execute_task load_task(task_id)
|
104
|
+
def execute_task_by_id(task_id, force: false)
|
105
|
+
job = @job_class.new(context: @ctx, ctl_ds: @ctl_ds, task_id: task_id, force: force, logger: @logger)
|
106
|
+
job.execute(fail_fast: true)
|
102
107
|
end
|
103
108
|
|
104
|
-
def
|
105
|
-
@
|
109
|
+
def event_loop
|
110
|
+
@task_queue.handle_messages(handler: self, message_class: Task)
|
106
111
|
end
|
107
112
|
|
108
113
|
# message handler
|
109
|
-
def handle_unknown(
|
110
|
-
@logger.warn "unknown task: #{
|
111
|
-
@task_queue.delete_message
|
114
|
+
def handle_unknown(t)
|
115
|
+
@logger.warn "unknown task: #{t.message_body}"
|
116
|
+
@task_queue.delete_message t
|
112
117
|
end
|
113
118
|
|
114
119
|
# message handler
|
115
|
-
def handle_streaming_load_v3(
|
120
|
+
def handle_streaming_load_v3(t)
|
116
121
|
Dir.chdir(@working_dir) {
|
117
|
-
|
118
|
-
if
|
119
|
-
|
120
|
-
@logger.info "skip disabled task: task_id=#{task.id}"
|
121
|
-
return
|
122
|
+
job = @job_class.new(context: @ctx, ctl_ds: @ctl_ds, task_id: t.task_id, force: t.force?, logger: @logger)
|
123
|
+
if job.execute
|
124
|
+
@task_queue.delete_message(t)
|
122
125
|
end
|
123
|
-
execute_task(loadtask)
|
124
|
-
# Do not use async delete
|
125
|
-
@task_queue.delete_message(task)
|
126
126
|
}
|
127
|
-
rescue => ex
|
127
|
+
rescue Exception => ex
|
128
128
|
@logger.exception ex
|
129
129
|
end
|
130
130
|
|
131
|
-
def
|
132
|
-
@
|
133
|
-
|
134
|
-
|
131
|
+
def job_class
|
132
|
+
@job_class ||= Job
|
133
|
+
end
|
134
|
+
|
135
|
+
attr_writer :job_class
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
class NoopJob
|
141
|
+
|
142
|
+
def initialize(context:, ctl_ds:, task_id:, force: false, logger:)
|
143
|
+
@ctx = context
|
144
|
+
@ctl_ds = ctl_ds
|
145
|
+
@task_id = task_id
|
146
|
+
@force = force
|
147
|
+
@logger = logger
|
148
|
+
end
|
149
|
+
|
150
|
+
def execute(fail_fast: false)
|
151
|
+
@logger.info "execute: fail_fast=#{fail_fast}"
|
152
|
+
execute_task
|
153
|
+
true
|
154
|
+
end
|
155
|
+
|
156
|
+
def execute_task
|
157
|
+
@logger.info "execute_task: task_id=#{@task_id} force=#{@force} ctx=#{@ctx.home_path} ctl_ds=#{@ctl_ds.name} dir=#{@working_dir}"
|
135
158
|
end
|
136
159
|
|
137
160
|
end
|
138
161
|
|
139
|
-
|
162
|
+
|
163
|
+
class TaskHandlerOptions
|
140
164
|
|
141
165
|
def initialize(argv)
|
142
166
|
@argv = argv
|
143
|
-
@task_id = nil
|
144
167
|
@environment = Context::DEFAULT_ENV
|
145
168
|
@daemon = false
|
146
169
|
@log_file_path = nil
|
147
170
|
@pid_file_path = nil
|
148
171
|
@working_dir = Dir.getwd
|
172
|
+
@task_id = nil
|
173
|
+
@force = false
|
174
|
+
@noop = false
|
149
175
|
@rest_arguments = nil
|
150
176
|
|
151
177
|
@opts = opts = OptionParser.new("Usage: #{$0} CONFIG_PATH")
|
152
|
-
opts.on('--task-id=ID', 'Execute oneshot load task (implicitly disables daemon mode).') {|task_id|
|
153
|
-
@task_id = task_id
|
154
|
-
}
|
155
178
|
opts.on('-e', '--environment=NAME', "Sets execution environment [default: #{@environment}]") {|env|
|
156
179
|
@environment = env
|
157
180
|
}
|
@@ -167,6 +190,15 @@ module Bricolage
|
|
167
190
|
opts.on('--working-dir=PATH', "Loader working directory. [default: #{@working_dir}]") {|path|
|
168
191
|
@working_dir = path
|
169
192
|
}
|
193
|
+
opts.on('--task-id=ID', 'Execute oneshot load task (implicitly disables daemon mode).') {|task_id|
|
194
|
+
@task_id = task_id
|
195
|
+
}
|
196
|
+
opts.on('--force', 'Disables loaded check.') {|path|
|
197
|
+
@force = true
|
198
|
+
}
|
199
|
+
opts.on('--noop', 'Does not execute tasks.') {
|
200
|
+
@noop = true
|
201
|
+
}
|
170
202
|
opts.on('--help', 'Prints this message and quit.') {
|
171
203
|
puts opts.help
|
172
204
|
exit 0
|
@@ -190,7 +222,6 @@ module Bricolage
|
|
190
222
|
|
191
223
|
attr_reader :rest_arguments
|
192
224
|
|
193
|
-
attr_reader :task_id
|
194
225
|
attr_reader :environment
|
195
226
|
|
196
227
|
def daemon?
|
@@ -201,6 +232,16 @@ module Bricolage
|
|
201
232
|
attr_reader :pid_file_path
|
202
233
|
attr_reader :working_dir
|
203
234
|
|
235
|
+
attr_reader :task_id
|
236
|
+
|
237
|
+
def force?
|
238
|
+
@force
|
239
|
+
end
|
240
|
+
|
241
|
+
def noop?
|
242
|
+
@noop
|
243
|
+
end
|
244
|
+
|
204
245
|
end
|
205
246
|
|
206
247
|
end
|
@@ -87,9 +87,9 @@ module Bricolage
|
|
87
87
|
|
88
88
|
# Object Buffer
|
89
89
|
assert_equal [], unassigned_objects(ctl_ds)
|
90
|
-
task =
|
91
|
-
assert_equal 'testschema', task.
|
92
|
-
assert_equal 'desttable', task.
|
90
|
+
task = Job::ControlConnection.open(ctl_ds) {|ctl| ctl.load_task(task_id) }
|
91
|
+
assert_equal 'testschema', task.schema_name
|
92
|
+
assert_equal 'desttable', task.table_name
|
93
93
|
assert_equal 10, task.object_urls.size
|
94
94
|
end
|
95
95
|
|
@@ -180,9 +180,9 @@ module Bricolage
|
|
180
180
|
|
181
181
|
# Object Buffer
|
182
182
|
assert_equal [], unassigned_table_objects(ctl_ds, 'testschema.bbb')
|
183
|
-
task =
|
184
|
-
assert_equal 'testschema', task.
|
185
|
-
assert_equal 'bbb', task.
|
183
|
+
task = Job::ControlConnection.open(ctl_ds) {|ctl| ctl.load_task(task_id) }
|
184
|
+
assert_equal 'testschema', task.schema_name
|
185
|
+
assert_equal 'bbb', task.table_name
|
186
186
|
assert_equal 2, task.object_urls.size
|
187
187
|
end
|
188
188
|
|