bricolage-streamingload 0.7.1 → 0.8.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.
@@ -1,7 +1,7 @@
1
1
  require 'bricolage/context'
2
2
  require 'bricolage/sqsdatasource'
3
3
  require 'bricolage/streamingload/task'
4
- require 'bricolage/streamingload/loader'
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 LoaderService < SQSDataSource::MessageHandler
16
+ class TaskHandler < SQSDataSource::MessageHandler
17
17
 
18
- def LoaderService.main
19
- opts = LoaderServiceOptions.new(ARGV)
18
+ def TaskHandler.main
19
+ opts = TaskHandlerOptions.new(ARGV)
20
20
  opts.parse
21
- unless opts.rest_arguments.size == 1
21
+ unless opts.rest_arguments.size <= 1
22
22
  $stderr.puts opts.usage
23
23
  exit 1
24
24
  end
25
- config_path, * = opts.rest_arguments
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
- redshift_ds = ctx.get_data_source('sql', config.fetch('redshift-ds', 'db_data'))
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
- raw_logger = logger = ctx.logger
32
- if config.key?('alert-level')
33
- logger = AlertingLogger.new(
34
- logger: raw_logger,
35
- sns_datasource: ctx.get_data_source('sns', config.fetch('sns-ds', 'sns')),
36
- alert_level: config.fetch('alert-level', 'warn')
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
- service = new(
40
+ task_handler = new(
41
41
  context: ctx,
42
- control_data_source: ctx.get_data_source('sql', config.fetch('ctl-postgres-ds', 'db_ctl')),
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: 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
- service.execute_task_by_id opts.task_id
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
- logger.info "*** bricolage-streaming-loader started: pid=#{$$}"
59
- service.event_loop
60
- logger.info "*** bricolage-streaming-loader shutdown gracefully: pid=#{$$}"
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
- logger.exception(ex)
63
- logger.error "*** bricolage-streaming-loader abort: pid=#{$$}"
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 LoaderService.new_logger(path, config)
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 LoaderService.create_pid_file(path)
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:, control_data_source:, data_source:, task_queue:, working_dir:, logger:)
93
+ def initialize(context:, ctl_ds:, task_queue:, working_dir:, logger:, job_class: Job)
86
94
  @ctx = context
87
- @ctl_ds = control_data_source
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 event_loop
97
- @task_queue.handle_messages(handler: self, message_class: Task)
98
- end
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 load_task(task_id, force: true)
105
- @ctl_ds.open {|conn| LoadTask.load(conn, task_id, force: force) }
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(task)
110
- @logger.warn "unknown task: #{task.message_body}"
111
- @task_queue.delete_message task
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(task)
120
+ def handle_streaming_load_v3(t)
116
121
  Dir.chdir(@working_dir) {
117
- loadtask = load_task(task.id, force: task.force?)
118
- if loadtask.disabled
119
- # Skip if disabled, and don't delete SQS message.
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 execute_task(task)
132
- @logger.info "execute task: task_id=#{task.id} table=#{task.qualified_name}"
133
- loader = Loader.load_from_file(@ctx, @ctl_ds, task, logger: @logger)
134
- loader.execute
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
- class LoaderServiceOptions
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
@@ -1,5 +1,5 @@
1
1
  module Bricolage
2
2
  module StreamingLoad
3
- VERSION = '0.7.1'
3
+ VERSION = '0.8.0'
4
4
  end
5
5
  end
@@ -87,9 +87,9 @@ module Bricolage
87
87
 
88
88
  # Object Buffer
89
89
  assert_equal [], unassigned_objects(ctl_ds)
90
- task = ctl_ds.open {|conn| LoadTask.load(conn, task_id) }
91
- assert_equal 'testschema', task.schema
92
- assert_equal 'desttable', task.table
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 = ctl_ds.open {|conn| LoadTask.load(conn, task_id) }
184
- assert_equal 'testschema', task.schema
185
- assert_equal 'bbb', task.table
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