rocketjob 5.4.1 → 6.0.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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +175 -5
  3. data/bin/rocketjob_batch_perf +1 -1
  4. data/bin/rocketjob_perf +1 -1
  5. data/lib/rocket_job/batch/categories.rb +345 -0
  6. data/lib/rocket_job/batch/io.rb +174 -106
  7. data/lib/rocket_job/batch/model.rb +20 -68
  8. data/lib/rocket_job/batch/performance.rb +19 -7
  9. data/lib/rocket_job/batch/statistics.rb +34 -12
  10. data/lib/rocket_job/batch/throttle_running_workers.rb +2 -6
  11. data/lib/rocket_job/batch/worker.rb +31 -26
  12. data/lib/rocket_job/batch.rb +3 -1
  13. data/lib/rocket_job/category/base.rb +81 -0
  14. data/lib/rocket_job/category/input.rb +170 -0
  15. data/lib/rocket_job/category/output.rb +34 -0
  16. data/lib/rocket_job/cli.rb +25 -17
  17. data/lib/rocket_job/dirmon_entry.rb +23 -13
  18. data/lib/rocket_job/event.rb +1 -1
  19. data/lib/rocket_job/extensions/iostreams/path.rb +32 -0
  20. data/lib/rocket_job/extensions/mongoid/contextual/mongo.rb +2 -2
  21. data/lib/rocket_job/extensions/mongoid/factory.rb +4 -12
  22. data/lib/rocket_job/extensions/mongoid/stringified_symbol.rb +50 -0
  23. data/lib/rocket_job/extensions/psych/yaml_tree.rb +8 -0
  24. data/lib/rocket_job/extensions/rocket_job_adapter.rb +2 -2
  25. data/lib/rocket_job/jobs/conversion_job.rb +43 -0
  26. data/lib/rocket_job/jobs/dirmon_job.rb +25 -36
  27. data/lib/rocket_job/jobs/housekeeping_job.rb +11 -12
  28. data/lib/rocket_job/jobs/on_demand_batch_job.rb +24 -11
  29. data/lib/rocket_job/jobs/on_demand_job.rb +3 -4
  30. data/lib/rocket_job/jobs/performance_job.rb +3 -1
  31. data/lib/rocket_job/jobs/re_encrypt/relational_job.rb +103 -96
  32. data/lib/rocket_job/jobs/upload_file_job.rb +48 -8
  33. data/lib/rocket_job/lookup_collection.rb +69 -0
  34. data/lib/rocket_job/plugins/cron.rb +60 -20
  35. data/lib/rocket_job/plugins/job/model.rb +25 -50
  36. data/lib/rocket_job/plugins/job/persistence.rb +36 -0
  37. data/lib/rocket_job/plugins/job/throttle.rb +2 -2
  38. data/lib/rocket_job/plugins/job/throttle_running_jobs.rb +1 -1
  39. data/lib/rocket_job/plugins/job/worker.rb +2 -7
  40. data/lib/rocket_job/plugins/restart.rb +3 -103
  41. data/lib/rocket_job/plugins/state_machine.rb +4 -3
  42. data/lib/rocket_job/plugins/throttle_dependent_jobs.rb +37 -0
  43. data/lib/rocket_job/ractor_worker.rb +42 -0
  44. data/lib/rocket_job/server/model.rb +1 -1
  45. data/lib/rocket_job/sliced/bzip2_output_slice.rb +18 -19
  46. data/lib/rocket_job/sliced/compressed_slice.rb +3 -6
  47. data/lib/rocket_job/sliced/encrypted_bzip2_output_slice.rb +49 -0
  48. data/lib/rocket_job/sliced/encrypted_slice.rb +4 -6
  49. data/lib/rocket_job/sliced/input.rb +42 -54
  50. data/lib/rocket_job/sliced/slice.rb +12 -16
  51. data/lib/rocket_job/sliced/slices.rb +26 -11
  52. data/lib/rocket_job/sliced/writer/input.rb +46 -18
  53. data/lib/rocket_job/sliced/writer/output.rb +33 -45
  54. data/lib/rocket_job/sliced.rb +1 -74
  55. data/lib/rocket_job/subscribers/server.rb +1 -1
  56. data/lib/rocket_job/thread_worker.rb +46 -0
  57. data/lib/rocket_job/throttle_definitions.rb +7 -1
  58. data/lib/rocket_job/version.rb +1 -1
  59. data/lib/rocket_job/worker.rb +21 -55
  60. data/lib/rocket_job/worker_pool.rb +5 -7
  61. data/lib/rocketjob.rb +53 -43
  62. metadata +36 -28
  63. data/lib/rocket_job/batch/tabular/input.rb +0 -131
  64. data/lib/rocket_job/batch/tabular/output.rb +0 -65
  65. data/lib/rocket_job/batch/tabular.rb +0 -56
  66. data/lib/rocket_job/extensions/mongoid/remove_warnings.rb +0 -12
  67. 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: 97910a2bbdcc67b808677e01f9ef9650935deac9f47ee415ad7665227e06e2a3
4
- data.tar.gz: 9c560b2a1deea93eb4c8e9cdf6fb28f2308e8f9a85457660c292ad38a2b76137
3
+ metadata.gz: e313f192b854d066258a614ceac1131851c8df94c7e08f7cea6681fff6946d69
4
+ data.tar.gz: 10804682bee08715671696db4610ce4f93679398398bc385e93619f5a3aca715
5
5
  SHA512:
6
- metadata.gz: 768538825ba34f58d915205fb1c61066ef2d86d9c3743f487db381074e30bd75c420f99f017adbb338c0dd4f202a69cf699b0b4e2a9ebc0581423fb102c85284
7
- data.tar.gz: 17d494818bf341a6b3340f4c0c5d5b77ec68c05eeb26d10eccb43c81221c14acd64ffe73ea1f610b514f233c84d5cc7cf3c2a10f4d1410b9b427308d22f5ad53
6
+ metadata.gz: 158675e5ddec87a8b277708887b037746e3f1573569edd5a8959eabdf5668b144553cbe6164844f2cf69bc603798b3b5b052697506dad8a29e8477afc62cc45f
7
+ data.tar.gz: 680efe5603de3649b7e09340a545d2e1df1e02697d34af9451869310e9f2a87bbd05423686bb7d40d60f104553f7311721870e52ac2171bb1491b3a8decaf439
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,179 @@ 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
+ #### Scheduled Jobs
53
+
54
+ For any scheduled jobs that include the `RocketJob::Plugins::Cron` plugin, the default behavior has changed
55
+ so that the scheduled job instance is created immediately after the currently scheduled instance starts.
56
+
57
+ To maintain the old behavior of creating the job when it fails, aborts, or completes, add the following line
58
+ to each of the applicable jobs:
59
+
60
+ ~~~ruby
61
+ self.cron_after_start = false
62
+ ~~~
63
+
64
+ Additionally, scheduled jobs will now prevent a new one from being created when another scheduled instance
65
+ of the same job is already queued, or running with the _same_ `cron_schedule`.
66
+
67
+ To maintain the old behavior of allowing multiple instances with the same cron schedule, add the following
68
+ line to each of the applicable jobs:
69
+
70
+ ~~~ruby
71
+ self.cron_singleton = false
72
+ ~~~
73
+
74
+ ##### Singleton
75
+
76
+ Since Scheduled jobs now implement their own singleton logic, remove the singleton plugin from any scheduled jobs.
77
+
78
+ #### Upgrading Batch Jobs to Rocket Job v6
79
+
80
+ Rocket Job v6 replaces the array of symbol type for `input_categories` and `output_categories`
81
+ with an array of `RocketJob::Category::Input` and `RocketJob::Category::Output`.
82
+
83
+ Jobs that added or modified the input or output categories need to be upgraded. For example:
84
+ ~~~ruby
85
+ class MyJob < RocketJob::Job
86
+ include RocketJob::Batch
87
+
88
+ self.output_categories = [:main, :errors, :ignored]
89
+ end
90
+ ~~~
91
+
92
+ Needs to be changed to:
93
+ ~~~ruby
94
+ class MyJob < RocketJob::Job
95
+ include RocketJob::Batch
96
+
97
+ output_category name: :main
98
+ output_category name: :errors
99
+ output_category name: :ignored
100
+ end
101
+ ~~~
102
+
103
+ ##### slice_size, encrypt, compress
104
+
105
+ These fields have been removed from the job itself:
106
+ ~~~ruby
107
+ class MyJob < RocketJob::Job
108
+ include RocketJob::Batch
109
+
110
+ self.slice_sice = 1_000
111
+ self.encrypt = true
112
+ self.compress = true
113
+ end
114
+ ~~~
115
+
116
+ They are now specified on the `input_category` as follows:
117
+ - `slice_size` just moves under `input_category`.
118
+ - `encrypt` becomes an option to `serializer`.
119
+ - `compress` is now the default for all batch jobs so is not needed.
120
+
121
+ If the serializer is set to `encrypt` then it is automatically compressed.
122
+
123
+ ~~~ruby
124
+ class MyJob < RocketJob::Job
125
+ include RocketJob::Batch
126
+
127
+ input_category slice_sice: 1_000, serializer: :encrypt
128
+ end
129
+ ~~~
130
+
131
+ ##### collect_output, collect_nil_output
132
+
133
+ The following fields have been moved from the job itself:
134
+ ~~~ruby
135
+ class MyJob < RocketJob::Job
136
+ include RocketJob::Batch
137
+
138
+ self.collect_output = true
139
+ self.collect_nil_output = true
140
+ end
141
+ ~~~
142
+
143
+ Into the corresponding `output_category`:
144
+ - `collect_output` no longer has any meaning. Output is collected anytime an `output_category` is defined.
145
+ - `collect_nil_output` is now the option `nils` on the `output_category.
146
+ It defaults to `false` so that by default any `nil` output from the `perform` method is not collected.
147
+ ~~~ruby
148
+ class MyJob < RocketJob::Job
149
+ include RocketJob::Batch
150
+
151
+ output_category nils: true
152
+ end
153
+ ~~~
154
+
155
+ ##### name
156
+
157
+ For both `input_category` and `output_category`, when the `name` argument is not supplied
158
+ it defaults to `:main`.
159
+
160
+ For Example:
161
+ ~~~ruby
162
+ class MyJob < RocketJob::Job
163
+ include RocketJob::Batch
164
+
165
+ input_category name: :main, serializer: :encrypt
166
+ output_category name: :main
167
+ end
168
+ ~~~
169
+
170
+ Is the same as:
171
+ ~~~ruby
172
+ class MyJob < RocketJob::Job
173
+ include RocketJob::Batch
174
+
175
+ input_category serializer: :encrypt
176
+ output_category
177
+ end
178
+ ~~~
179
+
180
+ ##### Existing and inflight jobs
181
+
182
+ When migrating to Rocket Job 6, it is recommended to load every job and then save it back again as part of the
183
+ deployment. When the job loads it will automatically convert itself from the old schema to the new v6 schema.
184
+
185
+ In flight jobs should not be affected, other than it is important to shutdown all running batch
186
+ servers _before_ running any new instances.
187
+
188
+ ## Rocket Job v4
189
+
190
+ Rocket Job Pro is now fully open source and included in Rocket Job under the Apache License.
191
+
192
+ The `RocketJob::Batch` plugin now adds batch processing capabilities to break up a single task into many
25
193
  concurrent workers processing slices of the entire job at the same time.
26
194
 
27
195
 
@@ -33,7 +201,9 @@ class MyJob < RocketJob::Job
33
201
 
34
202
  self.description = "Reverse names"
35
203
  self.destroy_on_complete = false
36
- self.collect_output = true
204
+
205
+ # Collect the output for this job in the default output category: `:main`
206
+ output_category
37
207
 
38
208
  # Method to call by all available workers at the same time.
39
209
  # 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)
@@ -0,0 +1,345 @@
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
+ return category_name if category_name.is_a?(Category::Input)
76
+ raise(ArgumentError, "Cannot supply Output Category to input category") if category_name.is_a?(Category::Output)
77
+
78
+ category_name = category_name.to_sym
79
+ # find does not work against this association
80
+ input_categories.each { |category| return category if category.name == category_name }
81
+
82
+ unless category_name == :main
83
+ raise(
84
+ ArgumentError,
85
+ "Unknown Input Category: #{category_name.inspect}. Registered categories: #{input_categories.collect(&:name).join(',')}"
86
+ )
87
+ end
88
+
89
+ # Auto-register main input category when not defined
90
+ category = Category::Input.new(job: self)
91
+ self.input_categories << category
92
+ category
93
+ end
94
+
95
+ def output_category(category_name = :main)
96
+ return category_name if category_name.is_a?(Category::Output)
97
+ raise(ArgumentError, "Cannot supply Input Category to output category") if category_name.is_a?(Category::Input)
98
+
99
+ category_name = category_name.to_sym
100
+ # .find does not work against this association
101
+ output_categories.each { |category| return category if category.name == category_name }
102
+
103
+ raise(
104
+ ArgumentError,
105
+ "Unknown Output Category: #{category_name.inspect}. Registered categories: #{output_categories.collect(&:name).join(',')}"
106
+ )
107
+ end
108
+
109
+ # Returns [true|false] whether the named category has already been defined
110
+ def input_category?(category_name)
111
+ category_name = category_name.to_sym
112
+ # .find does not work against this association
113
+ input_categories.each { |catg| return true if catg.name == category_name }
114
+ false
115
+ end
116
+
117
+ def output_category?(category_name)
118
+ category_name = category_name.to_sym
119
+ # .find does not work against this association
120
+ output_categories.each { |catg| return true if catg.name == category_name }
121
+ false
122
+ end
123
+
124
+ def merge_input_categories(categories)
125
+ return if categories.blank?
126
+
127
+ categories.each do |properties|
128
+ category_name = (properties["name"] || properties[:name] || :main).to_sym
129
+ category = input_category(category_name)
130
+ properties.each { |key, value| category.public_send("#{key}=".to_sym, value) }
131
+ end
132
+ end
133
+
134
+ def merge_output_categories(categories)
135
+ return if categories.blank?
136
+
137
+ categories.each do |properties|
138
+ category_name = (properties["name"] || properties[:name] || :main).to_sym
139
+ category = output_category(category_name)
140
+ properties.each { |key, value| category.public_send("#{key}=".to_sym, value) }
141
+ end
142
+ end
143
+
144
+ private
145
+
146
+ def rocketjob_categories_assign
147
+ # Input categories defaults to :main if none was set in the class
148
+ if input_categories.empty?
149
+ self.input_categories =
150
+ if self.class.defined_input_categories
151
+ self.class.defined_input_categories.deep_dup
152
+ else
153
+ [RocketJob::Category::Input.new]
154
+ end
155
+ end
156
+
157
+ return if !self.class.defined_output_categories || !output_categories.empty?
158
+
159
+ # Input categories defaults to nil if none was set in the class
160
+ self.output_categories = self.class.defined_output_categories.deep_dup
161
+ end
162
+
163
+ # Render the output from the perform.
164
+ def rocketjob_categories_output_render
165
+ return if @rocket_job_output.nil?
166
+
167
+ # TODO: ..
168
+ return unless output_categories
169
+ return if output_categories.empty?
170
+
171
+ @rocket_job_output = rocketjob_categories_output_render_row(@rocket_job_output)
172
+ end
173
+
174
+ # Parse the input data before passing to the perform method
175
+ def rocketjob_categories_input_render
176
+ return if @rocket_job_input.nil?
177
+
178
+ @rocket_job_input = rocketjob_categories_input_render_row(@rocket_job_input)
179
+ end
180
+
181
+ def rocketjob_categories_input_render_row(row)
182
+ return if row.nil?
183
+
184
+ category = input_category
185
+ return row if category.nil? || !category.tabular?
186
+ return nil if row.blank?
187
+
188
+ tabular = category.tabular
189
+
190
+ # Return the row as-is if the required header has not yet been set.
191
+ if tabular.header?
192
+ raise(ArgumentError,
193
+ "The tabular header columns _must_ be set before attempting to parse data that requires it.")
194
+ end
195
+
196
+ tabular.record_parse(row)
197
+ end
198
+
199
+ def rocketjob_categories_output_render_row(row)
200
+ return if row.nil?
201
+
202
+ if row.is_a?(Batch::Result)
203
+ category = output_category(row.category)
204
+ row.value = category.tabular.render(row.value) if category.tabular?
205
+ return row
206
+ end
207
+
208
+ if row.is_a?(Batch::Results)
209
+ results = Batch::Results.new
210
+ row.each { |result| results << rocketjob_categories_output_render_row(result) }
211
+ return results
212
+ end
213
+
214
+ category = output_category
215
+ return row unless category.tabular?
216
+ return nil if row.blank?
217
+
218
+ category.tabular.render(row)
219
+ end
220
+
221
+ # Migrate existing v5 batch jobs to v6
222
+ def rocketjob_categories_migrate
223
+ return unless attribute_present?(:input_categories) && self[:input_categories]&.first.is_a?(Symbol)
224
+
225
+ serializer = :none
226
+ if attribute_present?(:compress)
227
+ serializer = :compress if self[:compress]
228
+ remove_attribute(:compress)
229
+ end
230
+
231
+ if attribute_present?(:encrypt)
232
+ serializer = :encrypt if self[:encrypt]
233
+ remove_attribute(:encrypt)
234
+ end
235
+
236
+ slice_size = 100
237
+ if attribute_present?(:slice_size)
238
+ slice_size = self[:slice_size].to_i
239
+ remove_attribute(:slice_size)
240
+ end
241
+
242
+ main_input_format = nil
243
+ main_input_mode = :line
244
+ main_input_columns = nil
245
+ # Only migrate tabular attributes if the job also removed the tabular plugin.
246
+ unless respond_to?(:tabular_input_render)
247
+ if attribute_present?(:tabular_input_format)
248
+ main_input_format = self[:tabular_input_format]
249
+ remove_attribute(:tabular_input_format)
250
+ end
251
+
252
+ if attribute_present?(:tabular_input_mode)
253
+ main_input_mode = self[:tabular_input_mode]
254
+ remove_attribute(:tabular_input_mode)
255
+ end
256
+
257
+ if attribute_present?(:tabular_input_header)
258
+ main_input_columns = self[:tabular_input_header]
259
+ remove_attribute(:tabular_input_header)
260
+ end
261
+ end
262
+
263
+ file_name = nil
264
+ if attribute_present?(:upload_file_name)
265
+ file_name = self[:upload_file_name]
266
+ remove_attribute(:upload_file_name)
267
+ end
268
+
269
+ existing = self[:input_categories]
270
+ self[:input_categories] = []
271
+ self[:input_categories] = existing.collect do |category_name|
272
+ RocketJob::Category::Input.new(
273
+ name: category_name,
274
+ file_name: file_name,
275
+ serializer: serializer,
276
+ slice_size: slice_size,
277
+ format: [:main, "main"].include?(category_name) ? main_input_format : nil,
278
+ columns: [:main, "main"].include?(category_name) ? main_input_columns : nil,
279
+ mode: [:main, "main"].include?(category_name) ? main_input_mode : nil
280
+ ).as_document
281
+ end
282
+
283
+ collect_output = false
284
+ if attribute_present?(:collect_output)
285
+ collect_output = self[:collect_output]
286
+ remove_attribute(:collect_output)
287
+ end
288
+
289
+ collect_nil_output = true
290
+ if attribute_present?(:collect_nil_output)
291
+ collect_nil_output = self[:collect_nil_output]
292
+ remove_attribute(:collect_nil_output)
293
+ end
294
+
295
+ main_output_format = nil
296
+ main_output_columns = nil
297
+ main_output_options = nil
298
+
299
+ # Only migrate tabular attributes if the job also removed the tabular plugin.
300
+ unless respond_to?(:tabular_output_render)
301
+ if attribute_present?(:tabular_output_format)
302
+ main_output_format = self[:tabular_output_format]
303
+ remove_attribute(:tabular_output_format)
304
+ end
305
+
306
+ if attribute_present?(:tabular_output_header)
307
+ main_output_columns = self[:tabular_output_header]
308
+ remove_attribute(:tabular_output_header)
309
+ end
310
+
311
+ if attribute_present?(:tabular_output_options)
312
+ main_output_options = self[:tabular_output_options]
313
+ remove_attribute(:tabular_output_options)
314
+ end
315
+ end
316
+
317
+ existing = self[:output_categories]
318
+ self[:output_categories] = []
319
+ if collect_output
320
+ if existing.blank?
321
+ self[:output_categories] = [
322
+ RocketJob::Category::Output.new(
323
+ nils: collect_nil_output,
324
+ format: main_output_format,
325
+ columns: main_output_columns,
326
+ format_options: main_output_options
327
+ ).as_document
328
+ ]
329
+ elsif existing.first.is_a?(Symbol)
330
+ self[:output_categories] = existing.collect do |category_name|
331
+ RocketJob::Category::Output.new(
332
+ name: category_name,
333
+ serializer: serializer,
334
+ nils: collect_nil_output,
335
+ format: [:main, "main"].include?(category_name) ? main_output_format : nil,
336
+ columns: [:main, "main"].include?(category_name) ? main_output_columns : nil,
337
+ format_options: [:main, "main"].include?(category_name) ? main_output_options : nil
338
+ ).as_document
339
+ end
340
+ end
341
+ end
342
+ end
343
+ end
344
+ end
345
+ end