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.
@@ -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