rocketjob 5.4.0.beta2 → 6.0.0.rc3

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +149 -5
  3. data/bin/rocketjob_batch_perf +1 -1
  4. data/bin/rocketjob_perf +1 -1
  5. data/lib/rocket_job/batch.rb +3 -1
  6. data/lib/rocket_job/batch/categories.rb +341 -0
  7. data/lib/rocket_job/batch/io.rb +128 -60
  8. data/lib/rocket_job/batch/model.rb +20 -68
  9. data/lib/rocket_job/batch/performance.rb +19 -7
  10. data/lib/rocket_job/batch/statistics.rb +34 -12
  11. data/lib/rocket_job/batch/tabular.rb +2 -0
  12. data/lib/rocket_job/batch/tabular/input.rb +8 -6
  13. data/lib/rocket_job/batch/tabular/output.rb +4 -2
  14. data/lib/rocket_job/batch/throttle_running_workers.rb +8 -17
  15. data/lib/rocket_job/batch/worker.rb +27 -24
  16. data/lib/rocket_job/category/base.rb +78 -0
  17. data/lib/rocket_job/category/input.rb +110 -0
  18. data/lib/rocket_job/category/output.rb +25 -0
  19. data/lib/rocket_job/cli.rb +25 -17
  20. data/lib/rocket_job/dirmon_entry.rb +22 -12
  21. data/lib/rocket_job/event.rb +1 -1
  22. data/lib/rocket_job/extensions/iostreams/path.rb +32 -0
  23. data/lib/rocket_job/extensions/mongoid/contextual/mongo.rb +2 -2
  24. data/lib/rocket_job/extensions/mongoid/factory.rb +4 -12
  25. data/lib/rocket_job/extensions/mongoid/stringified_symbol.rb +50 -0
  26. data/lib/rocket_job/extensions/psych/yaml_tree.rb +8 -0
  27. data/lib/rocket_job/extensions/rocket_job_adapter.rb +2 -2
  28. data/lib/rocket_job/jobs/conversion_job.rb +39 -0
  29. data/lib/rocket_job/jobs/dirmon_job.rb +2 -2
  30. data/lib/rocket_job/jobs/housekeeping_job.rb +7 -7
  31. data/lib/rocket_job/jobs/on_demand_batch_job.rb +17 -6
  32. data/lib/rocket_job/jobs/on_demand_job.rb +1 -2
  33. data/lib/rocket_job/jobs/performance_job.rb +3 -1
  34. data/lib/rocket_job/jobs/re_encrypt/relational_job.rb +103 -96
  35. data/lib/rocket_job/jobs/upload_file_job.rb +44 -8
  36. data/lib/rocket_job/lookup_collection.rb +69 -0
  37. data/lib/rocket_job/plugins/job/model.rb +25 -50
  38. data/lib/rocket_job/plugins/job/throttle.rb +2 -2
  39. data/lib/rocket_job/plugins/job/throttle_running_jobs.rb +12 -4
  40. data/lib/rocket_job/plugins/job/worker.rb +2 -7
  41. data/lib/rocket_job/plugins/restart.rb +12 -5
  42. data/lib/rocket_job/plugins/state_machine.rb +2 -1
  43. data/lib/rocket_job/plugins/throttle_dependent_jobs.rb +38 -0
  44. data/lib/rocket_job/ractor_worker.rb +42 -0
  45. data/lib/rocket_job/server/model.rb +1 -1
  46. data/lib/rocket_job/sliced.rb +15 -70
  47. data/lib/rocket_job/sliced/bzip2_output_slice.rb +1 -1
  48. data/lib/rocket_job/sliced/input.rb +1 -1
  49. data/lib/rocket_job/sliced/slice.rb +5 -13
  50. data/lib/rocket_job/sliced/slices.rb +14 -2
  51. data/lib/rocket_job/sliced/writer/output.rb +33 -45
  52. data/lib/rocket_job/subscribers/server.rb +1 -1
  53. data/lib/rocket_job/thread_worker.rb +46 -0
  54. data/lib/rocket_job/throttle_definitions.rb +7 -1
  55. data/lib/rocket_job/version.rb +1 -1
  56. data/lib/rocket_job/worker.rb +21 -55
  57. data/lib/rocket_job/worker_pool.rb +5 -7
  58. data/lib/rocketjob.rb +53 -43
  59. metadata +36 -26
  60. data/lib/rocket_job/extensions/mongoid/remove_warnings.rb +0 -12
  61. data/lib/rocket_job/jobs/on_demand_batch_tabular_job.rb +0 -28
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df527427b1abf142761ba3be11df6f146708763a371c345c1a2c4a2d5d160f73
4
- data.tar.gz: 2cf7a11dc3b82fd5fceb147991eb3dfa448d454c40264a96a2e9318cd2783e10
3
+ metadata.gz: 6a04a33b0cd03bdf0a7cb948fc87dd6c7d7bb3b392e566a8c15df50b73e27459
4
+ data.tar.gz: fc62e740a0a92bae8daf1f4ffbe199af1debcb84f8859aed10ea5954dc44c7b6
5
5
  SHA512:
6
- metadata.gz: 8af8995b77274fad9d791a9598191ca0dc1f28dcc13f1391d91accc39f193bb9a15a1447526cc550312d2160925276a271c89a9eb2be5927199d5ba8b96cfa1d
7
- data.tar.gz: e0f48e2b522eae0a470ce1fa0af9daa02900a446990e52bbe472880818fde220b15575e365135cae2843c4aceeac8680a8f316f70a7961cdf788eb856f6771d3
6
+ metadata.gz: 74cac01d253cf21a856e1ca4a5cf63d5e90320303bdf310cf90325c9cca242c4ed1b7a0a1c43ca00764f2f40d29822df6e6bee499c1bff56c9ddaa2401bc3862
7
+ data.tar.gz: 1bbc47c7d869ef28fd578a7b2575f62957aa2f83f9fc927af1d6fba7866270b15fd21cef30007b78d58847137357c75ccae2d03545560d2ffe0d674fe34c1d0e
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Rocket Job
2
- [![Gem Version](https://img.shields.io/gem/v/rocketjob.svg)](https://rubygems.org/gems/rocketjob) [![Build Status](https://travis-ci.org/rocketjob/rocketjob.svg?branch=master)](https://travis-ci.org/rocketjob/rocketjob) [![Downloads](https://img.shields.io/gem/dt/rocketjob.svg)](https://rubygems.org/gems/semantic_logger) [![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](http://opensource.org/licenses/Apache-2.0) ![](https://img.shields.io/badge/status-Production%20Ready-blue.svg) [![Support](https://img.shields.io/badge/IRC%20(gitter)-Support-brightgreen.svg)](https://gitter.im/rocketjob/support)
2
+ [![Gem Version](https://img.shields.io/gem/v/rocketjob.svg)](https://rubygems.org/gems/rocketjob) [![Downloads](https://img.shields.io/gem/dt/rocketjob.svg)](https://rubygems.org/gems/rocketjob) [![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](http://opensource.org/licenses/Apache-2.0) ![](https://img.shields.io/badge/status-Production%20Ready-blue.svg) [![Support](https://img.shields.io/badge/IRC%20(gitter)-Support-brightgreen.svg)](https://gitter.im/rocketjob/support)
3
3
 
4
4
  Ruby's missing batch system
5
5
 
@@ -17,11 +17,153 @@ Checkout https://rocketjob.io/
17
17
  * Questions? Join the chat room on Gitter for [rocketjob support](https://gitter.im/rocketjob/support)
18
18
  * [Report bugs](https://github.com/rocketjob/rocketjob/issues)
19
19
 
20
- ## Rocket Job 4
20
+ ## Rocket Job v6
21
21
 
22
- Rocket Job Pro is now open sourced and included within Rocket Job.
22
+ - Support for Ruby v3 and Rails 6.
23
+ - Major enhancements in Batch job support:
24
+ - Direct built-in Tabular support for all input and output categories.
25
+ - Multiple output file support, each with its own settings for:
26
+ - Compression
27
+ - GZip, Zip, BZip2 (Chunked for much faster loading into Apache Spark).
28
+ - Encryption
29
+ - PGP, Symmetric Encryption.
30
+ - File format
31
+ - CSV, PSV, JSON, Fixed Format, xlsx.
32
+ - Significant error handling improvements, especially around throttle failures
33
+ that used to result in "hanging" jobs.
34
+ - Support AWS DocumentDB in addition to MongoDB as the data store.
35
+ - Removed use of Symbols to meet Symbol deprecation in MongoDB and Mongoid.
23
36
 
24
- The `RocketJob::Batch` plugin now adds batch processing capabilites to break up a single task into many
37
+ ### Upgrading to Rocket Job v6
38
+
39
+ The following plugins have been deprecated and are no longer loaded by default.
40
+ - `RocketJob::Batch::Tabular::Input`
41
+ - `RocketJob::Batch::Tabular::Output`
42
+
43
+ If your code relies on these plugins and you still want to upgrade to Rocket Job v6,
44
+ add the following require statement to any jobs that still use them:
45
+
46
+ ~~~ruby
47
+ require "rocket_job/batch/tabular"
48
+ ~~~
49
+
50
+ It is important to migrate away from these plugins, since they will be removed in a future release.
51
+
52
+ #### Upgrading Batch Jobs to Rocket Job v6
53
+
54
+ Rocket Job v6 replaces the array of symbol type for `input_categories` and `output_categories`
55
+ with an array of `RocketJob::Category::Input` and `RocketJob::Category::Output`.
56
+
57
+ Jobs that added or modified the input or output categories need to be upgraded. For example:
58
+ ~~~ruby
59
+ class MyJob < RocketJob::Job
60
+ include RocketJob::Batch
61
+
62
+ self.output_categories = [:main, :errors, :ignored]
63
+ end
64
+ ~~~
65
+
66
+ Needs to be changed to:
67
+ ~~~ruby
68
+ class MyJob < RocketJob::Job
69
+ include RocketJob::Batch
70
+
71
+ output_category name: :main
72
+ output_category name: :errors
73
+ output_category name: :ignored
74
+ end
75
+ ~~~
76
+
77
+ ##### slice_size, encrypt, compress
78
+
79
+ These fields have been removed from the job itself:
80
+ ~~~ruby
81
+ class MyJob < RocketJob::Job
82
+ include RocketJob::Batch
83
+
84
+ self.slice_sice = 1_000
85
+ self.encrypt = true
86
+ self.compress = true
87
+ end
88
+ ~~~
89
+
90
+ They are now specified on the `input_category` as follows:
91
+ - `slice_size` just moves under `input_category`.
92
+ - `encrypt` becomes an option to `serializer`.
93
+ - `compress` is now the default for all batch jobs so is not needed.
94
+
95
+ If the serializer is set to `encrypt` then it is automatically compressed.
96
+
97
+ ~~~ruby
98
+ class MyJob < RocketJob::Job
99
+ include RocketJob::Batch
100
+
101
+ input_category slice_sice: 1_000, serializer: :encrypt
102
+ end
103
+ ~~~
104
+
105
+ ##### collect_output, collect_nil_output
106
+
107
+ The following fields have been moved from the job itself:
108
+ ~~~ruby
109
+ class MyJob < RocketJob::Job
110
+ include RocketJob::Batch
111
+
112
+ self.collect_output = true
113
+ self.collect_nil_output = true
114
+ end
115
+ ~~~
116
+
117
+ Into the corresponding `output_category`:
118
+ - `collect_output` no longer has any meaning. Output is collected anytime an `output_category` is defined.
119
+ - `collect_nil_output` is now the option `nils` on the `output_category.
120
+ It defaults to `false` so that by default any `nil` output from the `perform` method is not collected.
121
+ ~~~ruby
122
+ class MyJob < RocketJob::Job
123
+ include RocketJob::Batch
124
+
125
+ output_category nils: true
126
+ end
127
+ ~~~
128
+
129
+ ##### name
130
+
131
+ For both `input_category` and `output_category`, when the `name` argument is not supplied
132
+ it defaults to `:main`.
133
+
134
+ For Example:
135
+ ~~~ruby
136
+ class MyJob < RocketJob::Job
137
+ include RocketJob::Batch
138
+
139
+ input_category name: :main, serializer: :encrypt
140
+ output_category name: :main
141
+ end
142
+ ~~~
143
+
144
+ Is the same as:
145
+ ~~~ruby
146
+ class MyJob < RocketJob::Job
147
+ include RocketJob::Batch
148
+
149
+ input_category serializer: :encrypt
150
+ output_category
151
+ end
152
+ ~~~
153
+
154
+ ##### Existing and inflight jobs
155
+
156
+ When migrating to Rocket Job 6, it is recommended to load every job and then save it back again as part of the
157
+ deployment. When the job loads it will automatically convert itself from the old schema to the new v6 schema.
158
+
159
+ In flight jobs should not be affected, other than it is important to shutdown all running batch
160
+ servers _before_ running any new instances.
161
+
162
+ ## Rocket Job v4
163
+
164
+ Rocket Job Pro is now fully open source and included in Rocket Job under the Apache License.
165
+
166
+ The `RocketJob::Batch` plugin now adds batch processing capabilities to break up a single task into many
25
167
  concurrent workers processing slices of the entire job at the same time.
26
168
 
27
169
 
@@ -33,7 +175,9 @@ class MyJob < RocketJob::Job
33
175
 
34
176
  self.description = "Reverse names"
35
177
  self.destroy_on_complete = false
36
- self.collect_output = true
178
+
179
+ # Collect the output for this job in the default output category: `:main`
180
+ output_category
37
181
 
38
182
  # Method to call by all available workers at the same time.
39
183
  # Reverse the characters for each line:
@@ -2,7 +2,7 @@
2
2
  require "rocketjob_batch"
3
3
 
4
4
  # Log to console
5
- SemanticLogger.add_appender(io: STDOUT, formatter: :color)
5
+ SemanticLogger.add_appender(io: $stdout, formatter: :color)
6
6
 
7
7
  perf = RocketJob::Batch::Performance.new
8
8
  perf.parse(ARGV)
data/bin/rocketjob_perf CHANGED
@@ -2,7 +2,7 @@
2
2
  require "rocketjob"
3
3
 
4
4
  # Log to console
5
- SemanticLogger.add_appender(io: STDOUT, formatter: :color)
5
+ SemanticLogger.add_appender(io: $stdout, formatter: :color)
6
6
 
7
7
  perf = RocketJob::Performance.new
8
8
  perf.parse(ARGV)
@@ -7,6 +7,8 @@ require "rocket_job/batch/state_machine"
7
7
  require "rocket_job/batch/throttle"
8
8
  require "rocket_job/batch/throttle_running_workers"
9
9
  require "rocket_job/batch/worker"
10
+ # Ensure after_perform is run first and #upload override is after IO#upload is defined.
11
+ require "rocket_job/batch/categories"
10
12
 
11
13
  module RocketJob
12
14
  module Batch
@@ -17,6 +19,7 @@ module RocketJob
17
19
  include Callbacks
18
20
  include Logger
19
21
  include Worker
22
+ include Categories
20
23
  include Throttle
21
24
  include ThrottleRunningWorkers
22
25
  include IO
@@ -27,6 +30,5 @@ module RocketJob
27
30
  autoload :ThrottleWindows, "rocket_job/batch/throttle_windows"
28
31
  autoload :Result, "rocket_job/batch/result"
29
32
  autoload :Results, "rocket_job/batch/results"
30
- autoload :Tabular, "rocket_job/batch/tabular"
31
33
  end
32
34
  end
@@ -0,0 +1,341 @@
1
+ require "active_support/concern"
2
+
3
+ module RocketJob
4
+ module Batch
5
+ module Categories
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ after_initialize :rocketjob_categories_assign, if: :new_record?
10
+ after_initialize :rocketjob_categories_migrate, unless: :new_record?
11
+ before_perform :rocketjob_categories_input_render
12
+ after_perform :rocketjob_categories_output_render
13
+
14
+ # List of categories that this job can load input data into
15
+ embeds_many :input_categories, class_name: "RocketJob::Category::Input"
16
+
17
+ # List of categories that this job can save output data into
18
+ embeds_many :output_categories, class_name: "RocketJob::Category::Output"
19
+
20
+ # Internal attributes
21
+ class_attribute :defined_input_categories, instance_accessor: false, instance_predicate: false
22
+ class_attribute :defined_output_categories, instance_accessor: false, instance_predicate: false
23
+
24
+ # For RJMC to be able to edit jobs
25
+ accepts_nested_attributes_for :input_categories, :output_categories
26
+ end
27
+
28
+ module ClassMethods
29
+ # Define a new input category
30
+ # @see RocketJob::Category::Input
31
+ def input_category(**args)
32
+ category = RocketJob::Category::Input.new(**args)
33
+ if defined_input_categories.nil?
34
+ self.defined_input_categories = [category]
35
+ else
36
+ rocketjob_categories_set(category, defined_input_categories)
37
+ end
38
+ end
39
+
40
+ # Define a new output category
41
+ # @see RocketJob::Category::Output
42
+ def output_category(**args)
43
+ category = RocketJob::Category::Output.new(**args)
44
+ if defined_output_categories.nil?
45
+ self.defined_output_categories = [category]
46
+ else
47
+ rocketjob_categories_set(category, defined_output_categories)
48
+ end
49
+ end
50
+
51
+ # Builds this job instance from the supplied properties hash that may contain input and output categories.
52
+ # Keeps the defaults and merges in settings without replacing existing categories.
53
+ def from_properties(properties)
54
+ return super(properties) unless properties.key?("input_categories") || properties.key?("output_categories")
55
+
56
+ properties = properties.dup
57
+ input_categories = properties.delete("input_categories")
58
+ output_categories = properties.delete("output_categories")
59
+ job = super(properties)
60
+ job.merge_input_categories(input_categories)
61
+ job.merge_output_categories(output_categories)
62
+ job
63
+ end
64
+
65
+ private
66
+
67
+ def rocketjob_categories_set(category, categories)
68
+ index = categories.find_index { |cat| cat.name == category.name }
69
+ index ? categories[index] = category : categories << category
70
+ category
71
+ end
72
+ end
73
+
74
+ def input_category(category_name = :main)
75
+ category_name = category_name.to_sym
76
+ category = nil
77
+ # .find does not work against this association
78
+ input_categories.each { |catg| category = catg if catg.name == category_name }
79
+ unless category
80
+ # Auto-register main input category if missing
81
+ if category_name == :main
82
+ category = Category::Input.new
83
+ self.input_categories = [category]
84
+ else
85
+ raise(ArgumentError,
86
+ "Unknown Input Category: #{category_name.inspect}. Registered categories: #{input_categories.collect(&:name).join(',')}")
87
+ end
88
+ end
89
+ category
90
+ end
91
+
92
+ def output_category(category_name = :main)
93
+ category_name = category_name.to_sym
94
+ category = nil
95
+ # .find does not work against this association
96
+ output_categories.each { |catg| category = catg if catg.name == category_name }
97
+ unless category
98
+ raise(ArgumentError,
99
+ "Unknown Output Category: #{category_name.inspect}. Registered categories: #{output_categories.collect(&:name).join(',')}")
100
+ end
101
+
102
+ category
103
+ end
104
+
105
+ # Returns [true|false] whether the named category has already been defined
106
+ def input_category?(category_name)
107
+ category_name = category_name.to_sym
108
+ # .find does not work against this association
109
+ input_categories.each { |catg| return true if catg.name == category_name }
110
+ false
111
+ end
112
+
113
+ def output_category?(category_name)
114
+ category_name = category_name.to_sym
115
+ # .find does not work against this association
116
+ output_categories.each { |catg| return true if catg.name == category_name }
117
+ false
118
+ end
119
+
120
+ def merge_input_categories(categories)
121
+ return if categories.blank?
122
+
123
+ categories.each do |properties|
124
+ category_name = (properties["name"] || properties[:name] || :main).to_sym
125
+ category = input_category(category_name)
126
+ properties.each { |key, value| category.public_send("#{key}=".to_sym, value) }
127
+ end
128
+ end
129
+
130
+ def merge_output_categories(categories)
131
+ return if categories.blank?
132
+
133
+ categories.each do |properties|
134
+ category_name = (properties["name"] || properties[:name] || :main).to_sym
135
+ category = output_category(category_name)
136
+ properties.each { |key, value| category.public_send("#{key}=".to_sym, value) }
137
+ end
138
+ end
139
+
140
+ private
141
+
142
+ def rocketjob_categories_assign
143
+ # Input categories defaults to :main if none was set in the class
144
+ if input_categories.empty?
145
+ self.input_categories =
146
+ if self.class.defined_input_categories
147
+ self.class.defined_input_categories.deep_dup
148
+ else
149
+ [RocketJob::Category::Input.new]
150
+ end
151
+ end
152
+
153
+ return if !self.class.defined_output_categories || !output_categories.empty?
154
+
155
+ # Input categories defaults to nil if none was set in the class
156
+ self.output_categories = self.class.defined_output_categories.deep_dup
157
+ end
158
+
159
+ # Render the output from the perform.
160
+ def rocketjob_categories_output_render
161
+ return if @rocket_job_output.nil?
162
+
163
+ # TODO: ..
164
+ return unless output_categories
165
+ return if output_categories.empty?
166
+
167
+ @rocket_job_output = rocketjob_categories_output_render_row(@rocket_job_output)
168
+ end
169
+
170
+ # Parse the input data before passing to the perform method
171
+ def rocketjob_categories_input_render
172
+ return if @rocket_job_input.nil?
173
+
174
+ @rocket_job_input = rocketjob_categories_input_render_row(@rocket_job_input)
175
+ end
176
+
177
+ def rocketjob_categories_input_render_row(row)
178
+ return if row.nil?
179
+
180
+ category = input_category
181
+ return row if category.nil? || !category.tabular?
182
+ return nil if row.blank?
183
+
184
+ tabular = category.tabular
185
+
186
+ # Return the row as-is if the required header has not yet been set.
187
+ if tabular.header?
188
+ raise(ArgumentError,
189
+ "The tabular header columns _must_ be set before attempting to parse data that requires it.")
190
+ end
191
+
192
+ tabular.record_parse(row)
193
+ end
194
+
195
+ def rocketjob_categories_output_render_row(row)
196
+ return if row.nil?
197
+
198
+ if row.is_a?(Batch::Result)
199
+ category = output_category(row.category)
200
+ row.value = category.tabular.render(row.value) if category.tabular?
201
+ return row
202
+ end
203
+
204
+ if row.is_a?(Batch::Results)
205
+ results = Batch::Results.new
206
+ row.each { |result| results << rocketjob_categories_output_render_row(result) }
207
+ return results
208
+ end
209
+
210
+ category = output_category
211
+ return row unless category.tabular?
212
+ return nil if row.blank?
213
+
214
+ category.tabular.render(row)
215
+ end
216
+
217
+ # Migrate existing v4 batch jobs to v5.0
218
+ def rocketjob_categories_migrate
219
+ return unless attribute_present?(:input_categories) && self[:input_categories]&.first.is_a?(Symbol)
220
+
221
+ serializer = :none
222
+ if attribute_present?(:compress)
223
+ serializer = :compress if self[:compress]
224
+ remove_attribute(:compress)
225
+ end
226
+
227
+ if attribute_present?(:encrypt)
228
+ serializer = :encrypt if self[:encrypt]
229
+ remove_attribute(:encrypt)
230
+ end
231
+
232
+ slice_size = 100
233
+ if attribute_present?(:slice_size)
234
+ slice_size = self[:slice_size].to_i
235
+ remove_attribute(:slice_size)
236
+ end
237
+
238
+ main_input_format = nil
239
+ main_input_mode = :line
240
+ main_input_columns = nil
241
+ # Only migrate tabular attributes if the job also removed the tabular plugin.
242
+ unless respond_to?(:tabular_input_render)
243
+ if attribute_present?(:tabular_input_format)
244
+ main_input_format = self[:tabular_input_format]
245
+ remove_attribute(:tabular_input_format)
246
+ end
247
+
248
+ if attribute_present?(:tabular_input_mode)
249
+ main_input_mode = self[:tabular_input_mode]
250
+ remove_attribute(:tabular_input_mode)
251
+ end
252
+
253
+ if attribute_present?(:tabular_input_header)
254
+ main_input_columns = self[:tabular_input_header]
255
+ remove_attribute(:tabular_input_header)
256
+ end
257
+ end
258
+
259
+ file_name = nil
260
+ if attribute_present?(:upload_file_name)
261
+ file_name = self[:upload_file_name]
262
+ remove_attribute(:upload_file_name)
263
+ end
264
+
265
+ existing = self[:input_categories]
266
+ self[:input_categories] = []
267
+ self[:input_categories] = existing.collect do |category_name|
268
+ RocketJob::Category::Input.new(
269
+ name: category_name,
270
+ file_name: file_name,
271
+ serializer: serializer,
272
+ slice_size: slice_size,
273
+ format: [:main, "main"].include?(category_name) ? main_input_format : nil,
274
+ columns: [:main, "main"].include?(category_name) ? main_input_columns : nil,
275
+ mode: [:main, "main"].include?(category_name) ? main_input_mode : nil
276
+ ).as_document
277
+ end
278
+
279
+ collect_output = false
280
+ if attribute_present?(:collect_output)
281
+ collect_output = self[:collect_output]
282
+ remove_attribute(:collect_output)
283
+ end
284
+
285
+ collect_nil_output = true
286
+ if attribute_present?(:collect_nil_output)
287
+ collect_nil_output = self[:collect_nil_output]
288
+ remove_attribute(:collect_nil_output)
289
+ end
290
+
291
+ main_output_format = nil
292
+ main_output_columns = nil
293
+ main_output_options = nil
294
+
295
+ # Only migrate tabular attributes if the job also removed the tabular plugin.
296
+ unless respond_to?(:tabular_output_render)
297
+ if attribute_present?(:tabular_output_format)
298
+ main_output_format = self[:tabular_output_format]
299
+ remove_attribute(:tabular_output_format)
300
+ end
301
+
302
+ if attribute_present?(:tabular_output_header)
303
+ main_output_columns = self[:tabular_output_header]
304
+ remove_attribute(:tabular_output_header)
305
+ end
306
+
307
+ if attribute_present?(:tabular_output_options)
308
+ main_output_options = self[:tabular_output_options]
309
+ remove_attribute(:tabular_output_options)
310
+ end
311
+ end
312
+
313
+ existing = self[:output_categories]
314
+ self[:output_categories] = []
315
+ if collect_output
316
+ if existing.blank?
317
+ self[:output_categories] = [
318
+ RocketJob::Category::Output.new(
319
+ nils: collect_nil_output,
320
+ format: main_output_format,
321
+ columns: main_output_columns,
322
+ format_options: main_output_options
323
+ ).as_document
324
+ ]
325
+ elsif existing.first.is_a?(Symbol)
326
+ self[:output_categories] = existing.collect do |category_name|
327
+ RocketJob::Category::Output.new(
328
+ name: category_name,
329
+ serializer: serializer,
330
+ nils: collect_nil_output,
331
+ format: [:main, "main"].include?(category_name) ? main_output_format : nil,
332
+ columns: [:main, "main"].include?(category_name) ? main_output_columns : nil,
333
+ format_options: [:main, "main"].include?(category_name) ? main_output_options : nil
334
+ ).as_document
335
+ end
336
+ end
337
+ end
338
+ end
339
+ end
340
+ end
341
+ end