taskinator 0.5.0 → 0.5.2

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.
data/Gemfile.lock CHANGED
@@ -1,36 +1,35 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- taskinator (0.5.0)
4
+ taskinator (0.5.2)
5
5
  builder (>= 3.2.2)
6
6
  connection_pool (>= 2.2.0)
7
- globalid (~> 0.3)
7
+ globalid (>= 0.3)
8
8
  json (>= 1.8.2)
9
9
  redis (>= 3.2.1)
10
10
  redis-namespace (>= 1.5.2)
11
- statsd-ruby (~> 1.4.0)
12
- thwait (~> 0.2)
11
+ thwait (>= 0.2)
13
12
 
14
13
  GEM
15
14
  remote: https://rubygems.org/
16
15
  specs:
17
- actionpack (5.2.6.2)
18
- actionview (= 5.2.6.2)
19
- activesupport (= 5.2.6.2)
16
+ actionpack (5.2.8.1)
17
+ actionview (= 5.2.8.1)
18
+ activesupport (= 5.2.8.1)
20
19
  rack (~> 2.0, >= 2.0.8)
21
20
  rack-test (>= 0.6.3)
22
21
  rails-dom-testing (~> 2.0)
23
22
  rails-html-sanitizer (~> 1.0, >= 1.0.2)
24
- actionview (5.2.6.2)
25
- activesupport (= 5.2.6.2)
23
+ actionview (5.2.8.1)
24
+ activesupport (= 5.2.8.1)
26
25
  builder (~> 3.1)
27
26
  erubi (~> 1.4)
28
27
  rails-dom-testing (~> 2.0)
29
28
  rails-html-sanitizer (~> 1.0, >= 1.0.3)
30
- activejob (5.2.6.2)
31
- activesupport (= 5.2.6.2)
29
+ activejob (5.2.8.1)
30
+ activesupport (= 5.2.8.1)
32
31
  globalid (>= 0.3.6)
33
- activesupport (5.2.6.2)
32
+ activesupport (5.2.8.1)
34
33
  concurrent-ruby (~> 1.0, >= 1.0.2)
35
34
  i18n (>= 0.7, < 2)
36
35
  minitest (~> 5.1)
@@ -38,8 +37,8 @@ GEM
38
37
  builder (3.2.4)
39
38
  byebug (11.1.3)
40
39
  coderay (1.1.3)
41
- concurrent-ruby (1.1.9)
42
- connection_pool (2.2.5)
40
+ concurrent-ruby (1.1.10)
41
+ connection_pool (2.3.0)
43
42
  coveralls (0.8.23)
44
43
  json (>= 1.8, < 3)
45
44
  simplecov (~> 0.16.1)
@@ -47,83 +46,82 @@ GEM
47
46
  thor (>= 0.19.4, < 2.0)
48
47
  tins (~> 1.6)
49
48
  crass (1.0.6)
50
- delayed_job (4.1.10)
49
+ delayed_job (4.1.11)
51
50
  activesupport (>= 3.0, < 8.0)
52
51
  diff-lcs (1.5.0)
53
52
  docile (1.4.0)
54
53
  e2mmap (0.1.0)
55
- erubi (1.10.0)
54
+ erubi (1.12.0)
56
55
  fakeredis (0.7.0)
57
56
  redis (>= 3.2, < 5.0)
58
- globalid (0.6.0)
57
+ globalid (1.0.0)
59
58
  activesupport (>= 5.0)
60
- i18n (1.9.1)
59
+ i18n (1.12.0)
61
60
  concurrent-ruby (~> 1.0)
62
- json (2.6.1)
63
- loofah (2.14.0)
61
+ json (2.6.3)
62
+ loofah (2.19.1)
64
63
  crass (~> 1.0.2)
65
64
  nokogiri (>= 1.5.9)
66
65
  method_source (1.0.0)
67
- mini_portile2 (2.7.1)
68
- minitest (5.15.0)
66
+ mini_portile2 (2.8.1)
67
+ minitest (5.17.0)
69
68
  mono_logger (1.1.1)
70
69
  multi_json (1.15.0)
71
- mustermann (1.1.1)
70
+ mustermann (3.0.0)
72
71
  ruby2_keywords (~> 0.0.1)
73
- nokogiri (1.13.1)
74
- mini_portile2 (~> 2.7.0)
72
+ nokogiri (1.13.10)
73
+ mini_portile2 (~> 2.8.0)
75
74
  racc (~> 1.4)
76
- pry (0.13.1)
75
+ pry (0.14.1)
77
76
  coderay (~> 1.1)
78
77
  method_source (~> 1.0)
79
- pry-byebug (3.9.0)
78
+ pry-byebug (3.10.1)
80
79
  byebug (~> 11.0)
81
- pry (~> 0.13.0)
82
- racc (1.6.0)
83
- rack (2.2.3)
84
- rack-protection (2.1.0)
80
+ pry (>= 0.13, < 0.15)
81
+ racc (1.6.2)
82
+ rack (2.2.5)
83
+ rack-protection (3.0.5)
85
84
  rack
86
- rack-test (1.1.0)
87
- rack (>= 1.0, < 3)
85
+ rack-test (2.0.2)
86
+ rack (>= 1.3)
88
87
  rails-dom-testing (2.0.3)
89
88
  activesupport (>= 4.2.0)
90
89
  nokogiri (>= 1.6)
91
- rails-html-sanitizer (1.4.2)
92
- loofah (~> 2.3)
93
- railties (5.2.6.2)
94
- actionpack (= 5.2.6.2)
95
- activesupport (= 5.2.6.2)
90
+ rails-html-sanitizer (1.4.4)
91
+ loofah (~> 2.19, >= 2.19.1)
92
+ railties (5.2.8.1)
93
+ actionpack (= 5.2.8.1)
94
+ activesupport (= 5.2.8.1)
96
95
  method_source
97
96
  rake (>= 0.8.7)
98
97
  thor (>= 0.19.0, < 2.0)
99
98
  rake (13.0.6)
100
- redis (4.6.0)
101
- redis-namespace (1.8.1)
102
- redis (>= 3.0.4)
103
- resque (2.2.0)
99
+ redis (4.8.0)
100
+ redis-namespace (1.10.0)
101
+ redis (>= 4)
102
+ resque (2.4.0)
104
103
  mono_logger (~> 1.0)
105
104
  multi_json (~> 1.0)
106
105
  redis-namespace (~> 1.6)
107
106
  sinatra (>= 0.9.2)
108
- vegas (~> 0.1.2)
109
107
  resque_spec (0.18.1)
110
108
  resque (>= 1.26.0)
111
109
  rspec-core (>= 3.0.0)
112
110
  rspec-expectations (>= 3.0.0)
113
111
  rspec-mocks (>= 3.0.0)
114
- rspec (3.11.0)
115
- rspec-core (~> 3.11.0)
116
- rspec-expectations (~> 3.11.0)
117
- rspec-mocks (~> 3.11.0)
118
- rspec-core (3.11.0)
119
- rspec-support (~> 3.11.0)
120
- rspec-expectations (3.11.0)
112
+ rspec (3.12.0)
113
+ rspec-core (~> 3.12.0)
114
+ rspec-expectations (~> 3.12.0)
115
+ rspec-mocks (~> 3.12.0)
116
+ rspec-core (3.12.0)
117
+ rspec-support (~> 3.12.0)
118
+ rspec-expectations (3.12.1)
121
119
  diff-lcs (>= 1.2.0, < 2.0)
122
- rspec-support (~> 3.11.0)
123
- rspec-mocks (3.11.0)
120
+ rspec-support (~> 3.12.0)
121
+ rspec-mocks (3.12.1)
124
122
  diff-lcs (>= 1.2.0, < 2.0)
125
- rspec-support (~> 3.11.0)
126
- rspec-rails (5.1.0)
123
+ rspec-support (~> 3.12.0)
124
+ rspec-rails (5.1.2)
127
125
  actionpack (>= 5.2)
128
126
  activesupport (>= 5.2)
129
127
  railties (>= 5.2)
@@ -134,23 +132,22 @@ GEM
134
132
  rspec-sidekiq (3.1.0)
135
133
  rspec-core (~> 3.0, >= 3.0.0)
136
134
  sidekiq (>= 2.4.0)
137
- rspec-support (3.11.0)
135
+ rspec-support (3.12.0)
138
136
  ruby2_keywords (0.0.5)
139
- sidekiq (6.4.1)
140
- connection_pool (>= 2.2.2)
137
+ sidekiq (6.5.8)
138
+ connection_pool (>= 2.2.5, < 3)
141
139
  rack (~> 2.0)
142
- redis (>= 4.2.0)
140
+ redis (>= 4.5.0, < 5)
143
141
  simplecov (0.16.1)
144
142
  docile (~> 1.1)
145
143
  json (>= 1.8, < 3)
146
144
  simplecov-html (~> 0.10.0)
147
145
  simplecov-html (0.10.2)
148
- sinatra (2.1.0)
149
- mustermann (~> 1.0)
150
- rack (~> 2.2)
151
- rack-protection (= 2.1.0)
146
+ sinatra (3.0.5)
147
+ mustermann (~> 3.0)
148
+ rack (~> 2.2, >= 2.2.4)
149
+ rack-protection (= 3.0.5)
152
150
  tilt (~> 2.0)
153
- statsd-ruby (1.4.0)
154
151
  sync (0.5.0)
155
152
  term-ansicolor (1.7.1)
156
153
  tins (~> 1.0)
@@ -158,13 +155,11 @@ GEM
158
155
  thread_safe (0.3.6)
159
156
  thwait (0.2.0)
160
157
  e2mmap
161
- tilt (2.0.10)
162
- tins (1.31.0)
158
+ tilt (2.0.11)
159
+ tins (1.32.1)
163
160
  sync
164
- tzinfo (1.2.9)
161
+ tzinfo (1.2.10)
165
162
  thread_safe (~> 0.1)
166
- vegas (0.1.11)
167
- rack (>= 1.0.0)
168
163
 
169
164
  PLATFORMS
170
165
  ruby
@@ -184,7 +179,7 @@ DEPENDENCIES
184
179
  rspec
185
180
  rspec-rails (>= 2.0)
186
181
  rspec-sidekiq (>= 2.1.0)
187
- sidekiq (>= 3.5.0)
182
+ sidekiq (>= 3.5.0, < 7.0.0)
188
183
  taskinator!
189
184
 
190
185
  BUNDLED WITH
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Taskinator
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/taskinator.svg)](http://badge.fury.io/rb/taskinator)
4
- [![Build Status](https://img.shields.io/github/workflow/status/virtualstaticvoid/taskinator/Taskinator?style=flat-square)](https://github.com/virtualstaticvoid/taskinator/actions)
4
+ [![Build Status](https://github.com/virtualstaticvoid/taskinator/actions/workflows/build.yml/badge.svg)](https://github.com/virtualstaticvoid/taskinator/actions/workflows/build.yml)
5
5
  [![Code Climate](https://codeclimate.com/github/virtualstaticvoid/taskinator.png)](https://codeclimate.com/github/virtualstaticvoid/taskinator)
6
6
 
7
7
  A simple orchestration library for running complex processes or workflows in Ruby.
@@ -53,8 +53,8 @@ If you are using Taskinator within a Rails application, then add an initializer,
53
53
  Taskinator.configure do |config|
54
54
 
55
55
  # configure the queue adapter to use
56
- # can be :active_job, :delayed_job, :redis or :sidekiq
57
- config.queue_adapter = :redis
56
+ # can be :active_job, :delayed_job, :resque or :sidekiq
57
+ config.queue_adapter = :resque
58
58
 
59
59
  # configure redis
60
60
  config.redis = {
@@ -171,39 +171,6 @@ module MyProcess
171
171
  end
172
172
  ```
173
173
 
174
- #### Reusing ActiveJob jobs
175
-
176
- It is likely that you already have one or more [jobs](https://guides.rubyonrails.org/active_job_basics.html)
177
- and want to reuse them within the process definition.
178
-
179
- Define a `job` step, providing the class of the Active Job to run and then taskinator will
180
- invoke that job as part of the process.
181
-
182
- The `job` step will be queued and executed on same queue as
183
- [configured by the job](https://guides.rubyonrails.org/active_job_basics.html#queues).
184
-
185
- ```ruby
186
- # E.g. A resque worker
187
- class DoSomeWork
188
- queue :high_priority
189
-
190
- def self.perform(arg1, arg2)
191
- # code to do the work
192
- end
193
- end
194
-
195
- module MyProcess
196
- extend Taskinator::Definition
197
-
198
- # when creating the process, supply the same arguments
199
- # that the DoSomeWork worker expects
200
-
201
- define_process do
202
- job DoSomeWork
203
- end
204
- end
205
- ```
206
-
207
174
  #### Data Driven Process Definitions
208
175
 
209
176
  You can also define data driven tasks using the `for_each` method, which takes an iterator method
@@ -271,7 +238,7 @@ process2 = MyProcess.create_process
271
238
  process2.tasks.count #=> 1
272
239
  ```
273
240
 
274
- #### Transformations
241
+ #### Argument Transformations
275
242
 
276
243
  In addition, it is possible to transform the arguments used by a task or job, by including
277
244
  a `transform` step in the definition.
@@ -396,16 +363,54 @@ MyProcess.create_process(1, 2, 3, :send_notification => true)
396
363
 
397
364
  ```
398
365
 
366
+ #### Reusing ActiveJob jobs
367
+
368
+ It is likely that you already have one or more [jobs](https://guides.rubyonrails.org/active_job_basics.html)
369
+ and want to reuse them within the process definition.
370
+
371
+ Define a `job` step, providing the class of the Active Job to run and then taskinator will
372
+ invoke that job as part of the process.
373
+
374
+ The `job` step will be queued and executed on same queue as
375
+ [configured by the job](https://guides.rubyonrails.org/active_job_basics.html#queues).
376
+
377
+ ```ruby
378
+ # E.g. A resque worker
379
+ class DoSomeWork
380
+ queue :high_priority
381
+
382
+ def self.perform(arg1, arg2)
383
+ # code to do the work
384
+ end
385
+ end
386
+
387
+ module MyProcess
388
+ extend Taskinator::Definition
389
+
390
+ # when creating the process, supply the same arguments
391
+ # that the DoSomeWork worker expects
392
+
393
+ define_process do
394
+ job DoSomeWork
395
+ end
396
+ end
397
+ ```
398
+
399
399
  ### Execution
400
400
 
401
- A process is executed by calling the generated `create_process` method on your "process" module.
401
+ A process is created by calling the generated `create_process` method on your "process" module.
402
402
 
403
403
  ```ruby
404
404
  process = MyProcess.create_process
405
+ ```
406
+
407
+ And then enqueued for execution by calling the `enqueue!` method of the process.
408
+
409
+ ```ruby
405
410
  process.enqueue!
406
411
  ```
407
412
 
408
- Or, to start immediately, call the `start!` method.
413
+ Or, started immediately by calling the `start!` method of the process.
409
414
 
410
415
  ```ruby
411
416
  process = MyProcess.create_process
@@ -637,6 +642,7 @@ process_id = "SUPPLY-PROCESS-IDENTIFIER"
637
642
  process = Taskinator::Api.find_process(process_id)
638
643
 
639
644
  puts process.inspect
645
+ puts process.definition
640
646
  puts process.current_state
641
647
  puts process.tasks
642
648
  # etc...
@@ -655,6 +661,7 @@ task = Taskinator::Api.find_task(task_id)
655
661
 
656
662
  puts task.inspect
657
663
  puts task.class
664
+ puts task.definition
658
665
  puts task.args # for Step and Job types
659
666
  puts task.sub_process.tasks # for SubProcess type
660
667
  # etc...
@@ -708,7 +715,7 @@ To configure the queue adapter to use, set `config.queue_adapter` to one of the
708
715
 
709
716
  * `:active_job`
710
717
  * `:delayed_job`
711
- * `:redis`
718
+ * `:resque`
712
719
  * `:sidekiq`
713
720
 
714
721
  As follows:
@@ -717,8 +724,8 @@ As follows:
717
724
  Taskinator.configure do |config|
718
725
 
719
726
  # configure the queue adapter to use
720
- # can be :active_job, :delayed_job, :redis or :sidekiq
721
- config.queue_adapter = :redis
727
+ # can be :active_job, :delayed_job, :resque or :sidekiq
728
+ config.queue_adapter = :resque
722
729
 
723
730
  end
724
731
  ```
@@ -787,6 +794,7 @@ For all events, the data included contains the following information:
787
794
  | Key | Value |
788
795
  |---------------------------------|----------------------------------------------------------|
789
796
  | `:type` | The type name of the component reporting the event |
797
+ | `:definition` | The type name of the process definition |
790
798
  | `:process_uuid` | The UUID of the root process |
791
799
  | `:process_options` | Options hash of the root process |
792
800
  | `:uuid` | The UUID of the respective task, job or sub process |
@@ -0,0 +1,129 @@
1
+ module Taskinator
2
+ class Builder
3
+
4
+ attr_reader :process
5
+ attr_reader :definition
6
+ attr_reader :args
7
+ attr_reader :builder_options
8
+
9
+ def initialize(process, definition, *args)
10
+ @process = process
11
+ @definition = definition
12
+ @builder_options = args.last.is_a?(Hash) ? args.pop : {}
13
+ @args = args
14
+ @executor = Taskinator::Executor.new(@definition)
15
+ end
16
+
17
+ def option?(key, &block)
18
+ yield if builder_options[key]
19
+ end
20
+
21
+ # defines a sub process of tasks which are executed sequentially
22
+ def sequential(options={}, &block)
23
+ raise ArgumentError, 'block' unless block_given?
24
+
25
+ sub_process = Process.define_sequential_process_for(@definition, options)
26
+ task = define_sub_process_task(@process, sub_process, options)
27
+ Builder.new(sub_process, @definition, *@args).instance_eval(&block)
28
+ @process.tasks << task if sub_process.tasks.any?
29
+ nil
30
+ end
31
+
32
+ # defines a sub process of tasks which are executed concurrently
33
+ def concurrent(complete_on=CompleteOn::Default, options={}, &block)
34
+ raise ArgumentError, 'block' unless block_given?
35
+
36
+ sub_process = Process.define_concurrent_process_for(@definition, complete_on, options)
37
+ task = define_sub_process_task(@process, sub_process, options)
38
+ Builder.new(sub_process, @definition, *@args).instance_eval(&block)
39
+ @process.tasks << task if sub_process.tasks.any?
40
+ nil
41
+ end
42
+
43
+ # dynamically defines tasks, using the given @iterator method
44
+ # the definition will be evaluated for each yielded item
45
+ def for_each(method, options={}, &block)
46
+ raise ArgumentError, 'method' if method.nil?
47
+ raise NoMethodError, method unless @executor.respond_to?(method)
48
+ raise ArgumentError, 'block' unless block_given?
49
+
50
+ #
51
+ # `for_each` is an exception, since it invokes the definition
52
+ # in order to yield elements to the builder, and any options passed
53
+ # are included with the builder options
54
+ #
55
+ method_args = options.any? ? [*@args, options] : @args
56
+ @executor.send(method, *method_args) do |*args|
57
+ Builder.new(@process, @definition, *args).instance_eval(&block)
58
+ end
59
+ nil
60
+ end
61
+
62
+ alias_method :transform, :for_each
63
+
64
+ # defines a task which executes the given @method
65
+ def task(method, options={})
66
+ raise ArgumentError, 'method' if method.nil?
67
+ raise NoMethodError, method unless @executor.respond_to?(method)
68
+
69
+ define_step_task(@process, method, @args, options)
70
+ nil
71
+ end
72
+
73
+ # defines a task which executes the given @job
74
+ # which is expected to implement a perform method either as a class or instance method
75
+ def job(job, options={})
76
+ raise ArgumentError, 'job' if job.nil?
77
+ raise ArgumentError, 'job' unless job.methods.include?(:perform) || job.instance_methods.include?(:perform)
78
+
79
+ define_job_task(@process, job, @args, options)
80
+ nil
81
+ end
82
+
83
+ # TODO: add mailer
84
+ # TODO: add complete!
85
+ # TODO: add fail!
86
+
87
+ # defines a sub process task, for the given @definition
88
+ # the definition specified must have input compatible arguments
89
+ # to the current definition
90
+ def sub_process(definition, options={})
91
+ raise ArgumentError, 'definition' if definition.nil?
92
+ raise ArgumentError, "#{definition.name} does not extend the #{Definition.name} module" unless definition.kind_of?(Definition)
93
+
94
+ sub_process = definition.create_sub_process(*@args, combine_options(options))
95
+ task = define_sub_process_task(@process, sub_process, options)
96
+ Builder.new(sub_process, definition, *@args)
97
+ @process.tasks << task if sub_process.tasks.any?
98
+ nil
99
+ end
100
+
101
+ private
102
+
103
+ def define_step_task(process, method, args, options={})
104
+ define_task(process) {
105
+ Task.define_step_task(process, method, args, combine_options(options))
106
+ }
107
+ end
108
+
109
+ def define_job_task(process, job, args, options={})
110
+ define_task(process) {
111
+ Task.define_job_task(process, job, args, combine_options(options))
112
+ }
113
+ end
114
+
115
+ def define_sub_process_task(process, sub_process, options={})
116
+ Task.define_sub_process_task(process, sub_process, combine_options(options))
117
+ end
118
+
119
+ def define_task(process)
120
+ process.tasks << task = yield
121
+ task
122
+ end
123
+
124
+ def combine_options(options={})
125
+ builder_options.merge(options)
126
+ end
127
+
128
+ end
129
+ end
@@ -1,3 +1,5 @@
1
+ require 'taskinator/builder'
2
+
1
3
  module Taskinator
2
4
  module Definition
3
5
 
@@ -120,5 +122,3 @@ module Taskinator
120
122
 
121
123
  end
122
124
  end
123
-
124
- require 'taskinator/definition/builder'
@@ -58,6 +58,7 @@ module Taskinator
58
58
  return OpenStruct.new(
59
59
  {
60
60
  :type => self.class.name,
61
+ :definition => self.definition.name,
61
62
  :process_uuid => process_uuid,
62
63
  :process_options => process_options.dup,
63
64
  :uuid => uuid,
@@ -1,3 +1,5 @@
1
+ require 'builder'
2
+
1
3
  module Taskinator
2
4
  module Persistence
3
5
 
@@ -113,13 +115,13 @@ module Taskinator
113
115
  transaction.hmset(
114
116
  self.key,
115
117
  :state, new_state,
116
- :updated_at, @updated_at
118
+ :updated_at, @updated_at.iso8601(3)
117
119
  )
118
120
 
119
121
  # also update the "root" process
120
122
  transaction.hset(
121
123
  process_key,
122
- :updated_at, @updated_at
124
+ :updated_at, @updated_at.iso8601(3)
123
125
  )
124
126
  end
125
127
  end
@@ -136,7 +138,7 @@ module Taskinator
136
138
  :error_type, error.class.name,
137
139
  :error_message, error.message,
138
140
  :error_backtrace, JSON.generate(error.backtrace || []),
139
- :updated_at, Time.now.utc
141
+ :updated_at, Time.now.utc.iso8601(3)
140
142
  )
141
143
  end
142
144
  end
@@ -180,7 +182,7 @@ module Taskinator
180
182
  process_key = self.process_key
181
183
  conn.multi do |transaction|
182
184
  transaction.hincrby process_key, "tasks_#{status}", 1
183
- transaction.hset process_key, :updated_at, Time.now.utc
185
+ transaction.hset process_key, :updated_at, Time.now.utc.iso8601(3)
184
186
  end
185
187
  end
186
188
  end
@@ -292,7 +294,8 @@ module Taskinator
292
294
  end
293
295
 
294
296
  def visit_attribute_time(attribute)
295
- visit_attribute(attribute)
297
+ value = @instance.send(attribute)
298
+ @hmset += [attribute, value.iso8601(3)] if value
296
299
  end
297
300
 
298
301
  def visit_attribute_enum(attribute, type)
@@ -447,6 +450,46 @@ module Taskinator
447
450
  end
448
451
  end
449
452
 
453
+ class UnknownTypeError < StandardError
454
+ end
455
+
456
+ module UnknownType
457
+
458
+ @unknown_types = {}
459
+
460
+ def self.new(type)
461
+ Taskinator.logger.error("Unknown type '#{type}' while deserializing.")
462
+ @unknown_types[type] ||= Module.new do
463
+ extend UnknownType
464
+ @type = type
465
+
466
+ # for unknown definitions
467
+ def method_missing(_, *_)
468
+ raise UnknownTypeError.new(to_s)
469
+ end
470
+ end
471
+ end
472
+
473
+ attr_reader :type
474
+
475
+ def to_s
476
+ "Unknown type '#{type}'."
477
+ end
478
+
479
+ def allocate
480
+ self
481
+ end
482
+
483
+ def accept(*_)
484
+ # nothing doing
485
+ end
486
+
487
+ # for unknown job types
488
+ def perform(*_)
489
+ raise UnknownTypeError.new(to_s)
490
+ end
491
+ end
492
+
450
493
  class RedisDeserializationVisitor < Taskinator::Visitor::Base
451
494
 
452
495
  #
@@ -480,7 +523,7 @@ module Taskinator
480
523
  return unless @attribute_values.key?(:type)
481
524
 
482
525
  type = @attribute_values[:type]
483
- klass = Kernel.const_get(type)
526
+ klass = Kernel.const_get(type) rescue UnknownType.new(type)
484
527
 
485
528
  #
486
529
  # NOTE:
@@ -539,16 +582,18 @@ module Taskinator
539
582
  def visit_attribute_enum(attribute, type)
540
583
  visit_attribute(attribute) do |value|
541
584
  const_value = type.constants.select {|c| type.const_get(c) == value.to_i }.first
542
- const_value ?
543
- type.const_get(const_value) :
544
- (defined?(type::Default) ? type::Default : nil)
585
+ if const_value
586
+ type.const_get(const_value)
587
+ else
588
+ defined?(type::Default) ? type::Default : nil
589
+ end
545
590
  end
546
591
  end
547
592
 
548
593
  def visit_type(attribute)
549
594
  value = @attribute_values[attribute]
550
595
  if value
551
- type = Kernel.const_get(value)
596
+ type = Kernel.const_get(value) rescue UnknownType.new(value)
552
597
  @instance.instance_variable_set("@#{attribute}", type)
553
598
  end
554
599
  end
@@ -576,6 +621,8 @@ module Taskinator
576
621
  type = Taskinator.redis do |conn|
577
622
  conn.hget(base.key_for(uuid), :type)
578
623
  end
624
+ # these types are always from taskinator
625
+ # so no need to rescue for unknown types!
579
626
  klass = Kernel.const_get(type)
580
627
  LazyLoader.new(klass, uuid, @instance_cache)
581
628
  end