taskinator 0.0.18 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/Gemfile.lock +28 -28
- data/README.md +29 -0
- data/Rakefile +5 -0
- data/bin/console +5 -0
- data/lib/taskinator/create_process_worker.rb +5 -2
- data/lib/taskinator/definition/builder.rb +12 -7
- data/lib/taskinator/definition.rb +36 -28
- data/lib/taskinator/executor.rb +4 -4
- data/lib/taskinator/job_worker.rb +5 -10
- data/lib/taskinator/logger.rb +1 -0
- data/lib/taskinator/persistence.rb +74 -36
- data/lib/taskinator/process.rb +75 -49
- data/lib/taskinator/queues/delayed_job.rb +1 -11
- data/lib/taskinator/queues/resque.rb +0 -15
- data/lib/taskinator/queues/sidekiq.rb +1 -14
- data/lib/taskinator/queues.rb +0 -5
- data/lib/taskinator/redis_connection.rb +1 -0
- data/lib/taskinator/task.rb +57 -57
- data/lib/taskinator/task_worker.rb +1 -8
- data/lib/taskinator/version.rb +1 -1
- data/lib/taskinator.rb +7 -6
- data/spec/examples/queue_adapter_examples.rb +0 -10
- data/spec/support/test_definition.rb +4 -0
- data/spec/support/test_flow.rb +2 -0
- data/spec/support/test_flows.rb +54 -3
- data/spec/support/test_queue.rb +41 -6
- data/spec/taskinator/create_process_worker_spec.rb +12 -3
- data/spec/taskinator/definition/builder_spec.rb +39 -9
- data/spec/taskinator/definition_spec.rb +19 -27
- data/spec/taskinator/executor_spec.rb +19 -1
- data/spec/taskinator/job_worker_spec.rb +0 -11
- data/spec/taskinator/persistence_spec.rb +122 -7
- data/spec/taskinator/process_spec.rb +39 -23
- data/spec/taskinator/queues/delayed_job_spec.rb +1 -19
- data/spec/taskinator/queues/resque_spec.rb +1 -22
- data/spec/taskinator/queues/sidekiq_spec.rb +1 -20
- data/spec/taskinator/task_spec.rb +160 -52
- data/spec/taskinator/task_worker_spec.rb +0 -17
- data/spec/taskinator/test_flows_spec.rb +43 -0
- metadata +2 -5
- data/lib/taskinator/process_worker.rb +0 -21
- data/spec/taskinator/process_worker_spec.rb +0 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1905dc0aad01e4bd348ad38a40100df9649e3a18
|
4
|
+
data.tar.gz: d1e4aa938c9d3a0d56fc4090f71024dec84e32fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6cd0c7d2fa8d1f133ddce568ae969fe488401ba9f6311c39143456749b4eea1429edbc63ec080a5a8b60fb84bf312bdcd5758084269b16ae83b7b437877e15d1
|
7
|
+
data.tar.gz: dfcbeced7346f8c0bdcc70e5814e2b2e943ecd10182ac0285a88e8e0bdfc0eb1a227c900390328861bb4012e4feffbf8fe7d41033583d68eb1f25d198f1ef027
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,28 @@
|
|
1
|
+
v0.2.0 - 31 Jul 2015
|
2
|
+
---
|
3
|
+
Bug fix for `create_process_remotely` so that it returns the process uuid instead of nil.
|
4
|
+
Removed reload functionality, since it isn't used anymore
|
5
|
+
Added missing instrumentation events for task, job and subprocess completed events.
|
6
|
+
Bug fix for when `sequential` or `concurrent` steps don't have any tasks to still continue processing.
|
7
|
+
Refactoring to remove dead code and "reload" functionality.
|
8
|
+
Improvements to console and rake to use console instrumenter.
|
9
|
+
Consolidation of instrumentation events. Added `type` to payload.
|
10
|
+
Improvements to error handling.
|
11
|
+
|
12
|
+
v0.1.1 - 23 Jul 2015 [Yanked]
|
13
|
+
---
|
14
|
+
Bug fix for option parameter handling.
|
15
|
+
|
16
|
+
v0.1.0 - 23 Jul 2015 [Yanked]
|
17
|
+
---
|
18
|
+
Fixed issue with persistence of options passed to `create_process` on the respective `Process` and `Task` instances.
|
19
|
+
Improvements to process creation logic.
|
20
|
+
Namespaced instrumentation event names.
|
21
|
+
Added process completed, cancelled and failed instrumentation events.
|
22
|
+
Include additional data in the instrumentation payload. E.g. Process options and percentages.
|
23
|
+
Refactored the way processes/tasks get queued, to prevent unnecessary queuing of contained processes/tasks.
|
24
|
+
Removed `ProcessWorker` since it isn't needed anymore.
|
25
|
+
|
1
26
|
v0.0.18 - 14 Jul 2015
|
2
27
|
---
|
3
28
|
Fixed issue with `Taskinator::Api::Processes#each` method, which was causing a Segmentation fault.
|
data/Gemfile.lock
CHANGED
@@ -8,7 +8,7 @@ GIT
|
|
8
8
|
PATH
|
9
9
|
remote: .
|
10
10
|
specs:
|
11
|
-
taskinator (0.0
|
11
|
+
taskinator (0.2.0)
|
12
12
|
connection_pool (>= 2.2.0)
|
13
13
|
json (>= 1.8.2)
|
14
14
|
redis (>= 3.2.1)
|
@@ -17,20 +17,20 @@ PATH
|
|
17
17
|
GEM
|
18
18
|
remote: https://rubygems.org/
|
19
19
|
specs:
|
20
|
-
activesupport (4.2.
|
20
|
+
activesupport (4.2.3)
|
21
21
|
i18n (~> 0.7)
|
22
22
|
json (~> 1.7, >= 1.7.7)
|
23
23
|
minitest (~> 5.1)
|
24
24
|
thread_safe (~> 0.3, >= 0.3.4)
|
25
25
|
tzinfo (~> 1.1)
|
26
|
-
byebug (
|
26
|
+
byebug (5.0.0)
|
27
27
|
columnize (= 0.9.0)
|
28
28
|
celluloid (0.16.0)
|
29
29
|
timers (~> 4.0.0)
|
30
30
|
coderay (1.1.0)
|
31
31
|
columnize (0.9.0)
|
32
32
|
connection_pool (2.2.0)
|
33
|
-
coveralls (0.8.
|
33
|
+
coveralls (0.8.2)
|
34
34
|
json (~> 1.8)
|
35
35
|
rest-client (>= 1.6.8, < 2)
|
36
36
|
simplecov (~> 0.10.0)
|
@@ -46,21 +46,21 @@ GEM
|
|
46
46
|
http-cookie (1.0.2)
|
47
47
|
domain_name (~> 0.5)
|
48
48
|
i18n (0.7.0)
|
49
|
-
json (1.8.
|
49
|
+
json (1.8.3)
|
50
50
|
method_source (0.8.2)
|
51
51
|
mime-types (2.6.1)
|
52
52
|
minitest (5.7.0)
|
53
53
|
mono_logger (1.1.0)
|
54
|
-
multi_json (1.11.
|
54
|
+
multi_json (1.11.2)
|
55
55
|
netrc (0.10.3)
|
56
56
|
pry (0.10.1)
|
57
57
|
coderay (~> 1.1.0)
|
58
58
|
method_source (~> 0.8.1)
|
59
59
|
slop (~> 3.4)
|
60
|
-
pry-byebug (3.
|
61
|
-
byebug (~>
|
60
|
+
pry-byebug (3.2.0)
|
61
|
+
byebug (~> 5.0)
|
62
62
|
pry (~> 0.10)
|
63
|
-
rack (1.6.
|
63
|
+
rack (1.6.4)
|
64
64
|
rack-protection (1.5.3)
|
65
65
|
rack
|
66
66
|
rake (10.4.2)
|
@@ -82,28 +82,28 @@ GEM
|
|
82
82
|
http-cookie (>= 1.0.2, < 2.0)
|
83
83
|
mime-types (>= 1.16, < 3.0)
|
84
84
|
netrc (~> 0.7)
|
85
|
-
rspec (3.
|
86
|
-
rspec-core (~> 3.
|
87
|
-
rspec-expectations (~> 3.
|
88
|
-
rspec-mocks (~> 3.
|
89
|
-
rspec-core (3.2
|
90
|
-
rspec-support (~> 3.
|
91
|
-
rspec-expectations (3.
|
85
|
+
rspec (3.3.0)
|
86
|
+
rspec-core (~> 3.3.0)
|
87
|
+
rspec-expectations (~> 3.3.0)
|
88
|
+
rspec-mocks (~> 3.3.0)
|
89
|
+
rspec-core (3.3.2)
|
90
|
+
rspec-support (~> 3.3.0)
|
91
|
+
rspec-expectations (3.3.1)
|
92
92
|
diff-lcs (>= 1.2.0, < 2.0)
|
93
|
-
rspec-support (~> 3.
|
94
|
-
rspec-mocks (3.2
|
93
|
+
rspec-support (~> 3.3.0)
|
94
|
+
rspec-mocks (3.3.2)
|
95
95
|
diff-lcs (>= 1.2.0, < 2.0)
|
96
|
-
rspec-support (~> 3.
|
96
|
+
rspec-support (~> 3.3.0)
|
97
97
|
rspec-sidekiq (2.0.0)
|
98
98
|
rspec (~> 3.0, >= 3.0.0)
|
99
99
|
sidekiq (>= 2.4.0)
|
100
|
-
rspec-support (3.
|
101
|
-
sidekiq (3.
|
102
|
-
celluloid (
|
103
|
-
connection_pool (>= 2.
|
104
|
-
json
|
105
|
-
redis (>= 3.
|
106
|
-
redis-namespace (>= 1.
|
100
|
+
rspec-support (3.3.0)
|
101
|
+
sidekiq (3.4.2)
|
102
|
+
celluloid (~> 0.16.0)
|
103
|
+
connection_pool (~> 2.2, >= 2.2.0)
|
104
|
+
json (~> 1.0)
|
105
|
+
redis (~> 3.2, >= 3.2.1)
|
106
|
+
redis-namespace (~> 1.5, >= 1.5.2)
|
107
107
|
simplecov (0.10.0)
|
108
108
|
docile (~> 1.1.0)
|
109
109
|
json (~> 1.8)
|
@@ -114,14 +114,14 @@ GEM
|
|
114
114
|
rack-protection (~> 1.4)
|
115
115
|
tilt (>= 1.3, < 3)
|
116
116
|
slop (3.6.0)
|
117
|
-
term-ansicolor (1.3.
|
117
|
+
term-ansicolor (1.3.2)
|
118
118
|
tins (~> 1.0)
|
119
119
|
thor (0.19.1)
|
120
120
|
thread_safe (0.3.5)
|
121
121
|
tilt (2.0.1)
|
122
122
|
timers (4.0.1)
|
123
123
|
hitimes
|
124
|
-
tins (1.5.
|
124
|
+
tins (1.5.4)
|
125
125
|
tzinfo (1.2.2)
|
126
126
|
thread_safe (~> 0.1)
|
127
127
|
unf (0.1.4)
|
data/README.md
CHANGED
@@ -606,6 +606,35 @@ Taskinator.configure do |config|
|
|
606
606
|
end
|
607
607
|
```
|
608
608
|
|
609
|
+
The following instrumentation events are issued:
|
610
|
+
|
611
|
+
| Event | When |
|
612
|
+
|------------------------------------|---------------------------------------------|
|
613
|
+
| `taskinator.process.created` | After a process gets created |
|
614
|
+
| `taskinator.process.saved` | After a process has been persisted to Redis |
|
615
|
+
| `taskinator.process.enqueued` | After a process is enqueued for processing |
|
616
|
+
| `taskinator.process.completed` | After a process has completed processing |
|
617
|
+
| `taskinator.process.cancelled` | After a process has been cancelled |
|
618
|
+
| `taskinator.process.failed` | After a process has failed |
|
619
|
+
| `taskinator.task.enqueued` | After a task has been enqueued |
|
620
|
+
| `taskinator.task.executed` | After a task has executed |
|
621
|
+
| `taskinator.job.enqueued` | After a job has been enqueued |
|
622
|
+
| `taskinator.job.executed` | After a job has executed |
|
623
|
+
| `taskinator.subprocess.enqueued` | After a sub process has been enqueued |
|
624
|
+
| `taskinator.subprocess.executed` | After a sub process has executed |
|
625
|
+
|
626
|
+
For all events, the data included contains the following information:
|
627
|
+
|
628
|
+
| Key | Value |
|
629
|
+
|--------------------------|-------------------------------------------------------|
|
630
|
+
| `:process_uuid` | The UUID of the root process |
|
631
|
+
| `:process_options` | Options hash of the root process |
|
632
|
+
| `:uuid` | The UUID of the respective task, job or sub process |
|
633
|
+
| `:tasks_count` | The total count of tasks for the given process |
|
634
|
+
| `:percentage_completed` | The percentage of completed tasks |
|
635
|
+
| `:percentage_failed` | The percentage of failed tasks |
|
636
|
+
| `:percentage_cancelled` | The percentage of cancelled tasks |
|
637
|
+
|
609
638
|
## Notes
|
610
639
|
|
611
640
|
The persistence logic is decoupled from the implementation, so it is possible to implement another backing store if required.
|
data/Rakefile
CHANGED
data/bin/console
CHANGED
@@ -7,5 +7,10 @@ require "taskinator"
|
|
7
7
|
# You can add fixtures and/or initialization code here to make experimenting
|
8
8
|
# with your gem easier. You can also use a different console, if you like.
|
9
9
|
|
10
|
+
Taskinator.configure do |config|
|
11
|
+
config.logger.level = 0 # DEBUG
|
12
|
+
config.instrumenter = Taskinator::ConsoleInstrumenter.new
|
13
|
+
end
|
14
|
+
|
10
15
|
require "pry"
|
11
16
|
Pry.start
|
@@ -19,13 +19,16 @@ module Taskinator
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def perform
|
22
|
-
@definition._create_process_(*@args, :uuid => @uuid).enqueue!
|
22
|
+
@definition._create_process_(false, *@args, :uuid => @uuid).enqueue!
|
23
23
|
end
|
24
24
|
|
25
25
|
private
|
26
26
|
|
27
|
-
#
|
27
|
+
# :nocov:
|
28
28
|
def constantize(camel_cased_word)
|
29
|
+
|
30
|
+
# borrowed from activesupport/lib/active_support/inflector/methods.rb
|
31
|
+
|
29
32
|
names = camel_cased_word.split('::')
|
30
33
|
|
31
34
|
# Trigger a built-in NameError exception including the ill-formed constant in the message.
|
@@ -5,18 +5,18 @@ module Taskinator
|
|
5
5
|
attr_reader :process
|
6
6
|
attr_reader :definition
|
7
7
|
attr_reader :args
|
8
|
-
attr_reader :
|
8
|
+
attr_reader :builder_options
|
9
9
|
|
10
10
|
def initialize(process, definition, *args)
|
11
11
|
@process = process
|
12
12
|
@definition = definition
|
13
|
+
@builder_options = args.last.is_a?(Hash) ? args.pop : {}
|
13
14
|
@args = args
|
14
|
-
@options = args.last.is_a?(Hash) ? args.last : {}
|
15
15
|
@executor = Taskinator::Executor.new(@definition)
|
16
16
|
end
|
17
17
|
|
18
18
|
def option?(key, &block)
|
19
|
-
yield if
|
19
|
+
yield if builder_options.key?(key) && builder_options[key]
|
20
20
|
end
|
21
21
|
|
22
22
|
# defines a sub process of tasks which are executed sequentially
|
@@ -81,7 +81,7 @@ module Taskinator
|
|
81
81
|
|
82
82
|
# TODO: decide whether the sub process to dynamically receive arguments
|
83
83
|
|
84
|
-
sub_process = definition.create_sub_process(*@args)
|
84
|
+
sub_process = definition.create_sub_process(*@args, combine_options(options))
|
85
85
|
Builder.new(define_sub_process_task(@process, sub_process, options), definition, *@args)
|
86
86
|
end
|
87
87
|
|
@@ -89,19 +89,19 @@ module Taskinator
|
|
89
89
|
|
90
90
|
def define_step_task(process, method, args, options={})
|
91
91
|
define_task(process) {
|
92
|
-
Task.define_step_task(process, method, args, options)
|
92
|
+
Task.define_step_task(process, method, args, combine_options(options))
|
93
93
|
}
|
94
94
|
end
|
95
95
|
|
96
96
|
def define_job_task(process, job, args, options={})
|
97
97
|
define_task(process) {
|
98
|
-
Task.define_job_task(process, job, args, options)
|
98
|
+
Task.define_job_task(process, job, args, combine_options(options))
|
99
99
|
}
|
100
100
|
end
|
101
101
|
|
102
102
|
def define_sub_process_task(process, sub_process, options={})
|
103
103
|
define_task(process) {
|
104
|
-
Task.define_sub_process_task(process, sub_process, options)
|
104
|
+
Task.define_sub_process_task(process, sub_process, combine_options(options))
|
105
105
|
}
|
106
106
|
sub_process
|
107
107
|
end
|
@@ -110,6 +110,11 @@ module Taskinator
|
|
110
110
|
process.tasks << task = yield
|
111
111
|
task
|
112
112
|
end
|
113
|
+
|
114
|
+
def combine_options(options={})
|
115
|
+
builder_options.merge(options)
|
116
|
+
end
|
117
|
+
|
113
118
|
end
|
114
119
|
end
|
115
120
|
end
|
@@ -33,42 +33,49 @@ module Taskinator
|
|
33
33
|
Process.define_sequential_process_for(definition, options)
|
34
34
|
}
|
35
35
|
|
36
|
-
|
36
|
+
# called from respective "create_process" methods
|
37
|
+
# parameters can contain options as the last parameter
|
38
|
+
define_singleton_method :_create_process_ do |subprocess, *args|
|
39
|
+
begin
|
37
40
|
|
38
|
-
|
41
|
+
# TODO: better validation of arguments
|
39
42
|
|
40
|
-
|
43
|
+
# FIXME: arg_list should only contain an array of symbols
|
41
44
|
|
42
|
-
|
45
|
+
raise ArgumentError, "wrong number of arguments (#{args.length} for #{arg_list.length})" if args.length < arg_list.length
|
43
46
|
|
44
|
-
|
47
|
+
options = (args.last.is_a?(Hash) ? args.last : {})
|
48
|
+
process = factory.call(self, options)
|
45
49
|
|
46
|
-
|
50
|
+
# this may take long... up to users definition
|
51
|
+
Taskinator.instrumenter.instrument('taskinator.process.created', :uuid => process.uuid) do
|
52
|
+
Builder.new(process, self, *args).instance_eval(&block)
|
53
|
+
end
|
47
54
|
|
48
|
-
|
49
|
-
|
50
|
-
Builder.new(process, self, *args).instance_eval(&block)
|
51
|
-
end
|
55
|
+
# only save "root processes"
|
56
|
+
unless subprocess
|
52
57
|
|
53
|
-
|
54
|
-
|
58
|
+
# instrument separately
|
59
|
+
Taskinator.instrumenter.instrument('taskinator.process.saved', :uuid => process.uuid) do
|
55
60
|
|
56
|
-
|
57
|
-
|
61
|
+
# this will visit "sub processes" and persist them too
|
62
|
+
process.save
|
58
63
|
|
59
|
-
|
60
|
-
|
64
|
+
# add it to the list of "root processes"
|
65
|
+
Persistence.add_process_to_list(process)
|
61
66
|
|
62
|
-
|
63
|
-
Persistence.add_process_to_list(process)
|
67
|
+
end
|
64
68
|
|
65
69
|
end
|
66
70
|
|
67
|
-
|
68
|
-
|
69
|
-
# this is the "root" process
|
70
|
-
process
|
71
|
+
# this is the "root" process
|
72
|
+
process
|
71
73
|
|
74
|
+
rescue => e
|
75
|
+
Taskinator.logger.error(e)
|
76
|
+
Taskinator.logger.debug(e.backtrace)
|
77
|
+
raise e
|
78
|
+
end
|
72
79
|
end
|
73
80
|
end
|
74
81
|
|
@@ -80,25 +87,26 @@ module Taskinator
|
|
80
87
|
#
|
81
88
|
def create_process(*args)
|
82
89
|
assert_valid_process_module
|
83
|
-
_create_process_(*args
|
90
|
+
_create_process_(false, *args)
|
84
91
|
end
|
85
92
|
|
86
93
|
#
|
87
|
-
# returns
|
88
|
-
#
|
89
|
-
#
|
94
|
+
# returns the process uuid of the process to be created
|
95
|
+
# the process can be retrieved using this uuid by using
|
96
|
+
# Taskinator::Process.fetch(uuid)
|
90
97
|
#
|
91
98
|
def create_process_remotely(*args)
|
92
99
|
assert_valid_process_module
|
93
100
|
uuid = SecureRandom.uuid
|
101
|
+
|
94
102
|
Taskinator.queue.enqueue_create_process(self, uuid, args)
|
95
103
|
|
96
|
-
|
104
|
+
return uuid
|
97
105
|
end
|
98
106
|
|
99
107
|
def create_sub_process(*args)
|
100
108
|
assert_valid_process_module
|
101
|
-
_create_process_(*args
|
109
|
+
_create_process_(true, *args)
|
102
110
|
end
|
103
111
|
|
104
112
|
private
|
data/lib/taskinator/executor.rb
CHANGED
@@ -13,16 +13,16 @@ module Taskinator
|
|
13
13
|
eigen.send(:include, definition)
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
|
16
|
+
def process_uuid
|
17
|
+
task.process_uuid if task
|
18
18
|
end
|
19
19
|
|
20
20
|
def uuid
|
21
|
-
task.uuid
|
21
|
+
task.uuid if task
|
22
22
|
end
|
23
23
|
|
24
24
|
def options
|
25
|
-
task.options
|
25
|
+
task.options if task
|
26
26
|
end
|
27
27
|
|
28
28
|
end
|
@@ -1,22 +1,17 @@
|
|
1
1
|
module Taskinator
|
2
2
|
class JobWorker
|
3
|
+
attr_reader :uuid
|
4
|
+
|
3
5
|
def initialize(uuid)
|
4
6
|
@uuid = uuid
|
5
7
|
end
|
6
8
|
|
7
|
-
# NB: must be provided a block for the
|
9
|
+
# NB: must be provided a block for the implementation of the job execution
|
8
10
|
def perform(&block)
|
9
11
|
task = Taskinator::Task.fetch(@uuid)
|
10
12
|
return if task.paused? || task.cancelled?
|
11
|
-
|
12
|
-
|
13
|
-
task.perform(&block)
|
14
|
-
task.complete!
|
15
|
-
rescue => e
|
16
|
-
Taskinator.logger.error(e)
|
17
|
-
task.fail!(e)
|
18
|
-
raise e
|
19
|
-
end
|
13
|
+
task.start!
|
14
|
+
task.perform(&block)
|
20
15
|
end
|
21
16
|
end
|
22
17
|
end
|
data/lib/taskinator/logger.rb
CHANGED
@@ -40,10 +40,10 @@ module Taskinator
|
|
40
40
|
# querying for the status of an instance
|
41
41
|
def state_for(uuid)
|
42
42
|
key = key_for(uuid)
|
43
|
-
Taskinator.redis do |conn|
|
44
|
-
|
45
|
-
state.to_sym
|
43
|
+
state = Taskinator.redis do |conn|
|
44
|
+
conn.hget(key, :state) || 'initial'
|
46
45
|
end
|
46
|
+
state.to_sym
|
47
47
|
end
|
48
48
|
|
49
49
|
# fetches the instance for given identifier
|
@@ -67,7 +67,7 @@ module Taskinator
|
|
67
67
|
conn.multi do
|
68
68
|
visitor = RedisSerializationVisitor.new(conn, self).visit
|
69
69
|
conn.hmset(
|
70
|
-
|
70
|
+
Taskinator::Process.key_for(uuid),
|
71
71
|
:tasks_count, visitor.task_count,
|
72
72
|
:tasks_failed, 0,
|
73
73
|
:tasks_completed, 0,
|
@@ -78,19 +78,23 @@ module Taskinator
|
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
-
#
|
81
|
+
# the persistence key
|
82
82
|
def key
|
83
83
|
@key ||= self.class.key_for(self.uuid)
|
84
84
|
end
|
85
85
|
|
86
|
-
#
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
conn.hget(self.key, :root_key)
|
86
|
+
# the root process uuid associated with this process or task
|
87
|
+
def process_uuid
|
88
|
+
@process_uuid ||= Taskinator.redis do |conn|
|
89
|
+
conn.hget(self.key, :process_uuid)
|
91
90
|
end
|
92
91
|
end
|
93
92
|
|
93
|
+
# the root process persistence key associated with this process or task
|
94
|
+
def process_key
|
95
|
+
@process_key ||= Taskinator::Process.key_for(process_uuid)
|
96
|
+
end
|
97
|
+
|
94
98
|
# retrieves the workflow state
|
95
99
|
# this method is called from the workflow gem
|
96
100
|
def load_workflow_state
|
@@ -135,9 +139,10 @@ module Taskinator
|
|
135
139
|
|
136
140
|
def tasks_count
|
137
141
|
@tasks_count ||= begin
|
138
|
-
Taskinator.redis do |conn|
|
139
|
-
conn.hget
|
140
|
-
end
|
142
|
+
count = Taskinator.redis do |conn|
|
143
|
+
conn.hget self.process_key, :tasks_count
|
144
|
+
end
|
145
|
+
count.to_i
|
141
146
|
end
|
142
147
|
end
|
143
148
|
|
@@ -148,14 +153,15 @@ module Taskinator
|
|
148
153
|
).each do |status|
|
149
154
|
|
150
155
|
define_method "count_#{status}" do
|
151
|
-
Taskinator.redis do |conn|
|
152
|
-
conn.hget
|
153
|
-
end
|
156
|
+
count = Taskinator.redis do |conn|
|
157
|
+
conn.hget self.process_key, status
|
158
|
+
end
|
159
|
+
count.to_i
|
154
160
|
end
|
155
161
|
|
156
162
|
define_method "incr_#{status}" do
|
157
163
|
Taskinator.redis do |conn|
|
158
|
-
conn.hincrby
|
164
|
+
conn.hincrby self.process_key, status, 1
|
159
165
|
end
|
160
166
|
end
|
161
167
|
|
@@ -165,6 +171,46 @@ module Taskinator
|
|
165
171
|
|
166
172
|
end
|
167
173
|
|
174
|
+
# retrieves the process options of the root process
|
175
|
+
# this is so that meta data of the process can be maintained
|
176
|
+
# and accessible to instrumentation subscribers
|
177
|
+
def process_options
|
178
|
+
@process_options ||= begin
|
179
|
+
yaml = Taskinator.redis do |conn|
|
180
|
+
conn.hget(self.process_key, :options)
|
181
|
+
end
|
182
|
+
yaml ? Taskinator::Persistence.deserialize(yaml) : {}
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# prepairs the meta data for instrumentation events
|
187
|
+
def instrumentation_payload(additional={})
|
188
|
+
|
189
|
+
# need to cache here, since this method hits redis, so can't be part of multi statement following
|
190
|
+
process_key = self.process_key
|
191
|
+
|
192
|
+
tasks_count, completed_count, cancelled_count, failed_count = Taskinator.redis do |conn|
|
193
|
+
conn.hmget process_key, :tasks_count, :completed, :cancelled, :failed
|
194
|
+
end
|
195
|
+
|
196
|
+
tasks_count = tasks_count.to_f
|
197
|
+
completed_percent = tasks_count > 0 ? (completed_count.to_i / tasks_count) * 100.0 : 0.0
|
198
|
+
cancelled_percent = tasks_count > 0 ? (cancelled_count.to_i / tasks_count) * 100.0 : 0.0
|
199
|
+
failed_percent = tasks_count > 0 ? (failed_count.to_i / tasks_count) * 100.0 : 0.0
|
200
|
+
|
201
|
+
return {
|
202
|
+
:type => self.class.name,
|
203
|
+
:process_uuid => process_uuid,
|
204
|
+
:process_options => process_options,
|
205
|
+
:uuid => uuid,
|
206
|
+
:percentage_failed => failed_percent,
|
207
|
+
:percentage_cancelled => cancelled_percent,
|
208
|
+
:percentage_completed => completed_percent,
|
209
|
+
:tasks_count => tasks_count
|
210
|
+
}.merge(additional)
|
211
|
+
|
212
|
+
end
|
213
|
+
|
168
214
|
end
|
169
215
|
|
170
216
|
class RedisSerializationVisitor < Visitor::Base
|
@@ -181,7 +227,7 @@ module Taskinator
|
|
181
227
|
@conn = conn
|
182
228
|
@instance = instance
|
183
229
|
@key = instance.key
|
184
|
-
@
|
230
|
+
@root = base_visitor.instance
|
185
231
|
@base_visitor = base_visitor
|
186
232
|
@task_count = 0
|
187
233
|
end
|
@@ -195,8 +241,8 @@ module Taskinator
|
|
195
241
|
|
196
242
|
@instance.accept(self)
|
197
243
|
|
198
|
-
# add the root key, for easy access later!
|
199
|
-
@hmset += [:
|
244
|
+
# add the process uuid and root key, for easy access later!
|
245
|
+
@hmset += [:process_uuid, @root.uuid]
|
200
246
|
|
201
247
|
# NB: splat args
|
202
248
|
@conn.hmset(*@hmset)
|
@@ -359,13 +405,11 @@ module Taskinator
|
|
359
405
|
# arbitrary instance to perform it's work
|
360
406
|
#
|
361
407
|
def lazy_instance_for(base, uuid)
|
362
|
-
Taskinator.redis do |conn|
|
363
|
-
|
364
|
-
root_key = conn.hget(base.key_for(uuid), :root_key)
|
365
|
-
|
366
|
-
klass = Kernel.const_get(type)
|
367
|
-
LazyLoader.new(klass, uuid, root_key, @instance_cache)
|
408
|
+
type, process_uuid = Taskinator.redis do |conn|
|
409
|
+
conn.hmget(base.key_for(uuid), :type, :process_uuid)
|
368
410
|
end
|
411
|
+
klass = Kernel.const_get(type)
|
412
|
+
LazyLoader.new(klass, uuid, process_uuid, @instance_cache)
|
369
413
|
end
|
370
414
|
end
|
371
415
|
|
@@ -380,29 +424,23 @@ module Taskinator
|
|
380
424
|
# E.g. this is useful for tasks which refer to their parent processes
|
381
425
|
#
|
382
426
|
|
383
|
-
def initialize(type, uuid,
|
427
|
+
def initialize(type, uuid, process_uuid, instance_cache={})
|
384
428
|
@type = type
|
385
429
|
@uuid = uuid
|
386
|
-
@
|
430
|
+
@process_uuid = process_uuid
|
387
431
|
@instance_cache = instance_cache
|
388
432
|
end
|
389
433
|
|
390
434
|
# shadows the real methods, but will be the same!
|
435
|
+
attr_reader :process_uuid
|
391
436
|
attr_reader :uuid
|
392
|
-
attr_reader :root_key
|
393
|
-
|
394
|
-
# attempts to reload the actual process
|
395
|
-
def reload
|
396
|
-
@instance = nil
|
397
|
-
__getobj__
|
398
|
-
@instance ? true : false
|
399
|
-
end
|
400
437
|
|
401
438
|
def __getobj__
|
402
439
|
# only fetch the object as needed
|
403
440
|
# and memoize for subsequent calls
|
404
441
|
@instance ||= @type.fetch(@uuid, @instance_cache)
|
405
442
|
end
|
443
|
+
|
406
444
|
end
|
407
445
|
|
408
446
|
class << self
|