abid 0.3.0.pre.alpha.3 → 0.3.0.pre.alpha.4
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.
- checksums.yaml +4 -4
- data/README.md +3 -3
- data/abid.gemspec +1 -2
- data/exe/abidsc +1 -1
- data/lib/abid.rb +3 -30
- data/lib/abid/application.rb +83 -13
- data/lib/abid/cli/assume.rb +7 -8
- data/lib/abid/cli/list.rb +2 -2
- data/lib/abid/cli/migrate.rb +1 -1
- data/lib/abid/cli/revoke.rb +9 -10
- data/lib/abid/config.rb +2 -0
- data/lib/abid/dsl/abid_job.rb +58 -0
- data/lib/abid/dsl/actions.rb +36 -0
- data/lib/abid/dsl/job.rb +58 -0
- data/lib/abid/dsl/job_manager.rb +53 -0
- data/lib/abid/dsl/mixin.rb +52 -0
- data/lib/abid/dsl/params_spec.rb +64 -0
- data/lib/abid/dsl/play.rb +35 -0
- data/lib/abid/dsl/play_core.rb +354 -0
- data/lib/abid/dsl/rake_job.rb +41 -0
- data/lib/abid/dsl/syntax.rb +34 -0
- data/lib/abid/dsl/task.rb +53 -0
- data/lib/abid/engine.rb +36 -6
- data/lib/abid/engine/executor.rb +30 -48
- data/lib/abid/engine/process.rb +102 -68
- data/lib/abid/engine/process_manager.rb +72 -28
- data/lib/abid/engine/scheduler.rb +24 -30
- data/lib/abid/engine/waiter.rb +20 -30
- data/lib/abid/engine/worker_manager.rb +26 -60
- data/lib/abid/environment.rb +12 -27
- data/lib/abid/error.rb +2 -0
- data/lib/abid/params_format.rb +29 -12
- data/lib/abid/rake_extensions.rb +11 -3
- data/lib/abid/state_manager.rb +40 -0
- data/lib/abid/state_manager/state.rb +52 -114
- data/lib/abid/state_manager/state_service.rb +88 -0
- data/lib/abid/status.rb +63 -0
- data/lib/abid/version.rb +1 -1
- metadata +19 -32
- data/lib/Abidfile.rb +0 -1
- data/lib/abid/dsl_definition.rb +0 -29
- data/lib/abid/job.rb +0 -67
- data/lib/abid/job_manager.rb +0 -22
- data/lib/abid/mixin_task.rb +0 -29
- data/lib/abid/params_parser.rb +0 -50
- data/lib/abid/play.rb +0 -66
- data/lib/abid/play_core.rb +0 -53
- data/lib/abid/rake_extensions/task.rb +0 -41
- data/lib/abid/state_manager/database.rb +0 -40
- data/lib/abid/state_manager/state_proxy.rb +0 -65
- data/lib/abid/task.rb +0 -123
- data/lib/abid/task_manager.rb +0 -61
@@ -1,55 +1,99 @@
|
|
1
|
-
require '
|
1
|
+
require 'concurrent/atomic/atomic_reference'
|
2
2
|
|
3
3
|
module Abid
|
4
|
-
|
4
|
+
class Engine
|
5
|
+
# ProcessManager is a processes repositry and tracks each process progress.
|
5
6
|
class ProcessManager
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
@
|
11
|
-
@
|
7
|
+
def initialize(engine)
|
8
|
+
@engine = engine
|
9
|
+
@all = {}.compare_by_identity
|
10
|
+
@actives = {}.compare_by_identity
|
11
|
+
@top_levels = {}.compare_by_identity
|
12
|
+
@summary = Hash.new { |h, k| h[k] = 0 }
|
13
|
+
@errors = []
|
12
14
|
@mon = Monitor.new
|
15
|
+
@status = Concurrent::AtomicReference.new(:running)
|
13
16
|
end
|
17
|
+
attr_reader :summary, :errors
|
18
|
+
|
19
|
+
def [](job)
|
20
|
+
return @all[job] if @all.include?(job)
|
14
21
|
|
15
|
-
|
16
|
-
|
17
|
-
|
22
|
+
@mon.synchronize do
|
23
|
+
@all[job] ||= Process.new(@engine, job).tap do |process|
|
24
|
+
process.on_update { update(process) }
|
25
|
+
end
|
26
|
+
end
|
18
27
|
end
|
19
28
|
|
20
|
-
#
|
21
|
-
# @param
|
29
|
+
# @param job [DSL::Job]
|
30
|
+
# @param args [Array<Object>]
|
31
|
+
# @return [Process]
|
32
|
+
def invoke(job, args)
|
33
|
+
raise Error, 'ProcessManager is not running now' unless running?
|
34
|
+
|
35
|
+
process = self[job]
|
36
|
+
@top_levels[process] = process
|
37
|
+
Scheduler.invoke(process, *args)
|
38
|
+
process.tap(&:wait)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Update active processes list
|
22
42
|
def update(process)
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
43
|
+
update_actives(process)
|
44
|
+
update_summary(process)
|
45
|
+
end
|
46
|
+
|
47
|
+
def shutdown
|
48
|
+
return unless @status.compare_and_set(:running, :shuttingdown)
|
49
|
+
actives.each(&:wait)
|
50
|
+
@status.set(:shutdown)
|
29
51
|
end
|
30
52
|
|
31
53
|
# Kill all active processes
|
32
54
|
# @param error [Exception] error reason
|
33
55
|
def kill(error)
|
34
|
-
|
56
|
+
return if shutdown?
|
57
|
+
@status.set(:shutdown)
|
58
|
+
@errors << error
|
59
|
+
actives.each { |process| process.quit(error) }
|
60
|
+
end
|
61
|
+
|
62
|
+
def actives
|
63
|
+
@actives.values
|
35
64
|
end
|
36
65
|
|
37
66
|
def active?(process)
|
38
|
-
@
|
67
|
+
@actives.include?(process)
|
39
68
|
end
|
40
69
|
|
41
|
-
|
70
|
+
def root?(process)
|
71
|
+
@top_levels.include?(process)
|
72
|
+
end
|
42
73
|
|
43
|
-
|
44
|
-
|
74
|
+
%w(running shuttingdown shutdown).each do |meth|
|
75
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
76
|
+
def #{meth}?
|
77
|
+
@status.get == :#{meth}
|
78
|
+
end
|
79
|
+
RUBY
|
45
80
|
end
|
46
81
|
|
47
|
-
|
48
|
-
|
82
|
+
private
|
83
|
+
|
84
|
+
def update_actives(process)
|
85
|
+
if process.complete?
|
86
|
+
@actives.delete(process)
|
87
|
+
else
|
88
|
+
@actives[process] = process
|
89
|
+
end
|
49
90
|
end
|
50
91
|
|
51
|
-
def
|
52
|
-
|
92
|
+
def update_summary(process)
|
93
|
+
return unless process.complete?
|
94
|
+
return if process.job.dryrun?
|
95
|
+
@mon.synchronize { @summary[process.status] += 1 }
|
96
|
+
@errors << process.error if process.error
|
53
97
|
end
|
54
98
|
end
|
55
99
|
end
|
@@ -1,16 +1,16 @@
|
|
1
1
|
require 'concurrent/atomic/atomic_fixnum'
|
2
2
|
|
3
3
|
module Abid
|
4
|
-
|
4
|
+
class Engine
|
5
5
|
# Scheduler operates whole job flow execution.
|
6
6
|
class Scheduler
|
7
7
|
# @return [void]
|
8
|
-
def self.invoke(
|
9
|
-
task_args = Rake::TaskArguments.new(job.
|
8
|
+
def self.invoke(process, *args, invocation_chain: nil)
|
9
|
+
task_args = Rake::TaskArguments.new(process.job.arg_names, args)
|
10
10
|
invocation_chain ||= Rake::InvocationChain::EMPTY
|
11
11
|
|
12
|
-
detect_circular_dependency(
|
13
|
-
new(
|
12
|
+
detect_circular_dependency(process, invocation_chain)
|
13
|
+
new(process, task_args, invocation_chain).invoke
|
14
14
|
end
|
15
15
|
|
16
16
|
# @!visibility private
|
@@ -29,30 +29,30 @@ module Abid
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
def self.detect_circular_dependency(
|
33
|
-
# raise error if job
|
34
|
-
new_chain = Rake::InvocationChain.append(job
|
32
|
+
def self.detect_circular_dependency(process, chain)
|
33
|
+
# raise error if process.job is a member of the chain
|
34
|
+
new_chain = Rake::InvocationChain.append(process.job, chain)
|
35
35
|
|
36
|
-
|
37
|
-
detect_circular_dependency(
|
36
|
+
process.prerequisites.each do |preq_process|
|
37
|
+
detect_circular_dependency(preq_process, new_chain)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
def initialize(
|
42
|
-
@
|
41
|
+
def initialize(process, args, invocation_chain)
|
42
|
+
@process = process
|
43
43
|
@args = args
|
44
|
-
@chain = invocation_chain.conj(@job
|
45
|
-
@executor = Executor.new(
|
44
|
+
@chain = invocation_chain.conj(@process.job)
|
45
|
+
@executor = Executor.new(process, args)
|
46
46
|
end
|
47
47
|
|
48
48
|
def invoke
|
49
49
|
return unless @executor.prepare
|
50
50
|
|
51
|
-
trace_invoke
|
51
|
+
@process.job.trace_invoke
|
52
52
|
attach_chain
|
53
53
|
invoke_prerequisites
|
54
54
|
after_prerequisites do
|
55
|
-
@
|
55
|
+
@process.capture_exception do
|
56
56
|
@executor.start
|
57
57
|
end
|
58
58
|
end
|
@@ -60,15 +60,9 @@ module Abid
|
|
60
60
|
|
61
61
|
private
|
62
62
|
|
63
|
-
def trace_invoke
|
64
|
-
return unless @job.env.options.trace
|
65
|
-
@job.env.application.trace \
|
66
|
-
"** Invoke #{@job.task.name} #{@job.task.format_trace_flags}"
|
67
|
-
end
|
68
|
-
|
69
63
|
def attach_chain
|
70
|
-
@
|
71
|
-
error = @
|
64
|
+
@process.on_complete do
|
65
|
+
error = @process.error
|
72
66
|
next if error.nil?
|
73
67
|
next if @chain.nil?
|
74
68
|
|
@@ -79,16 +73,16 @@ module Abid
|
|
79
73
|
end
|
80
74
|
|
81
75
|
def invoke_prerequisites
|
82
|
-
@
|
83
|
-
preq_args = @args.new_scope(@job.
|
84
|
-
Scheduler.new(
|
76
|
+
@process.prerequisites.each do |preq|
|
77
|
+
preq_args = @args.new_scope(@process.job.arg_names)
|
78
|
+
Scheduler.new(preq, preq_args, @chain).invoke
|
85
79
|
end
|
86
80
|
end
|
87
81
|
|
88
82
|
def after_prerequisites(&block)
|
89
|
-
counter = DependencyCounter.new(@
|
90
|
-
@
|
91
|
-
|
83
|
+
counter = DependencyCounter.new(@process.prerequisites.size, &block)
|
84
|
+
@process.prerequisites.each do |preq|
|
85
|
+
preq.on_complete { counter.update }
|
92
86
|
end
|
93
87
|
end
|
94
88
|
end
|
data/lib/abid/engine/waiter.rb
CHANGED
@@ -1,51 +1,50 @@
|
|
1
|
+
require 'concurrent/utility/monotonic_time'
|
2
|
+
|
1
3
|
module Abid
|
2
|
-
|
3
|
-
# Waits for a
|
4
|
-
# and completes the
|
4
|
+
class Engine
|
5
|
+
# Waits for a process to be finished which is running in external
|
6
|
+
# application, and completes the process in its own application.
|
5
7
|
#
|
6
|
-
# Waiter.new(
|
8
|
+
# Waiter.new(process).wait
|
7
9
|
#
|
8
|
-
# The `
|
9
|
-
# finished the
|
10
|
+
# The `process` result gets :successed or :failed when external application
|
11
|
+
# finished the process execution.
|
10
12
|
class Waiter
|
11
13
|
DEFAULT_WAIT_INTERVAL = 10
|
12
14
|
DEFAULT_WAIT_TIMEOUT = 3600
|
13
15
|
|
14
|
-
def initialize(
|
15
|
-
@
|
16
|
-
@
|
16
|
+
def initialize(process)
|
17
|
+
@process = process
|
18
|
+
@job = process.job
|
17
19
|
@wait_limit = Concurrent.monotonic_time + wait_timeout
|
18
20
|
end
|
19
21
|
|
20
22
|
def wait
|
21
|
-
unless @job.
|
22
|
-
@process.finish(AlreadyRunningError.new('
|
23
|
+
unless @job.options.wait_external_task
|
24
|
+
@process.finish(AlreadyRunningError.new('process already running'))
|
23
25
|
return
|
24
26
|
end
|
25
27
|
|
28
|
+
@process.logger.info('waiting')
|
26
29
|
wait_iter
|
27
30
|
end
|
28
31
|
|
29
32
|
private
|
30
33
|
|
31
34
|
def wait_interval
|
32
|
-
@job.
|
33
|
-
DEFAULT_WAIT_INTERVAL
|
35
|
+
@job.options.wait_external_task_interval || DEFAULT_WAIT_INTERVAL
|
34
36
|
end
|
35
37
|
|
36
38
|
def wait_timeout
|
37
|
-
@job.
|
38
|
-
DEFAULT_WAIT_TIMEOUT
|
39
|
+
@job.options.wait_external_task_timeout || DEFAULT_WAIT_TIMEOUT
|
39
40
|
end
|
40
41
|
|
41
42
|
def wait_iter
|
42
|
-
@
|
43
|
-
capture_exception do
|
44
|
-
state = @
|
43
|
+
@process.engine.worker_manager[:timer_set].post(wait_interval) do
|
44
|
+
@process.capture_exception do
|
45
|
+
state = @process.state_service.find
|
45
46
|
|
46
|
-
check_finished(state) ||
|
47
|
-
check_timeout ||
|
48
|
-
wait_iter
|
47
|
+
check_finished(state) || check_timeout || wait_iter
|
49
48
|
end
|
50
49
|
end
|
51
50
|
end
|
@@ -69,15 +68,6 @@ module Abid
|
|
69
68
|
@process.finish RuntimeError.new('timeout')
|
70
69
|
true
|
71
70
|
end
|
72
|
-
|
73
|
-
def capture_exception
|
74
|
-
yield
|
75
|
-
rescue StandardError, ScriptError => error
|
76
|
-
@process.quit(error)
|
77
|
-
rescue Exception => exception
|
78
|
-
# TODO: exit immediately when fatal error occurs.
|
79
|
-
@process.quit(exception)
|
80
|
-
end
|
81
71
|
end
|
82
72
|
end
|
83
73
|
end
|
@@ -1,10 +1,11 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
|
4
|
-
require 'concurrent/
|
1
|
+
require 'concurrent/configuration'
|
2
|
+
require 'concurrent/executor/cached_thread_pool'
|
3
|
+
require 'concurrent/executor/fixed_thread_pool'
|
4
|
+
require 'concurrent/executor/safe_task_executor'
|
5
|
+
require 'concurrent/executor/timer_set'
|
5
6
|
|
6
7
|
module Abid
|
7
|
-
|
8
|
+
class Engine
|
8
9
|
# WorkerManager manges thread pools definition, creation and termination.
|
9
10
|
#
|
10
11
|
# worker_manager = Abid.global.worker_manager
|
@@ -14,32 +15,21 @@ module Abid
|
|
14
15
|
# worker_manager[:main].post { :do_something }
|
15
16
|
#
|
16
17
|
# worker_manager.shutdown
|
17
|
-
#
|
18
18
|
class WorkerManager
|
19
19
|
def initialize(env)
|
20
20
|
@env = env
|
21
21
|
@workers = {}
|
22
|
-
@alive = true
|
23
|
-
@mon = Monitor.new
|
24
22
|
|
25
23
|
initialize_builtin_workers
|
26
24
|
end
|
27
25
|
|
28
26
|
# Define new worker.
|
29
|
-
#
|
30
|
-
# An actual worker is created when needed.
|
31
27
|
def define(name, num_threads)
|
32
|
-
@
|
33
|
-
|
34
|
-
|
35
|
-
if @workers.include?(name)
|
36
|
-
raise Error, "worker #{name} is already defined"
|
37
|
-
end
|
38
|
-
|
39
|
-
@workers[name] = Concurrent::Delay.new do
|
40
|
-
create_worker(num_threads: num_threads)
|
41
|
-
end
|
28
|
+
if @workers.include?(name)
|
29
|
+
raise Error, "worker #{name} is already defined"
|
42
30
|
end
|
31
|
+
|
32
|
+
@workers[name] = create_worker(num_threads: num_threads)
|
43
33
|
end
|
44
34
|
|
45
35
|
# Find or create worker
|
@@ -47,46 +37,35 @@ module Abid
|
|
47
37
|
# @param name [String, Symbol] worker name
|
48
38
|
# @return [Concurrent::ExecutorService]
|
49
39
|
def [](name)
|
50
|
-
@
|
51
|
-
|
52
|
-
|
53
|
-
unless @workers.include?(name)
|
54
|
-
raise Error, "worker #{name} is not defined"
|
55
|
-
end
|
56
|
-
|
57
|
-
@workers[name].value!
|
40
|
+
unless @workers.include?(name)
|
41
|
+
raise Error, "worker #{name} is not defined"
|
58
42
|
end
|
43
|
+
|
44
|
+
@workers[name]
|
59
45
|
end
|
60
46
|
|
61
47
|
def shutdown(timeout = nil)
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
each_active { |worker| worker.wait_for_termination(timeout) }
|
66
|
-
|
67
|
-
result = each_active.all?(&:shutdown?)
|
68
|
-
@alive = false if result
|
69
|
-
result
|
70
|
-
end
|
48
|
+
each_worker(&:shutdown)
|
49
|
+
each_worker { |worker| worker.wait_for_termination(timeout) }
|
50
|
+
each_worker.all?(&:shutdown?)
|
71
51
|
end
|
72
52
|
|
73
53
|
def kill
|
74
|
-
|
75
|
-
check_alive!
|
76
|
-
@alive = false
|
77
|
-
each_active(&:kill)
|
78
|
-
end
|
54
|
+
each_worker(&:kill)
|
79
55
|
true
|
80
56
|
end
|
81
57
|
|
58
|
+
def each_worker(&block)
|
59
|
+
@workers.values.each(&block)
|
60
|
+
end
|
61
|
+
|
82
62
|
private
|
83
63
|
|
84
64
|
def initialize_builtin_workers
|
85
|
-
@workers[:default] =
|
86
|
-
@workers[:waiter] = Concurrent
|
87
|
-
@workers[:timer_set] =
|
88
|
-
Concurrent::TimerSet.new(executor:
|
89
|
-
end
|
65
|
+
@workers[:default] = create_worker(num_threads: default_num_threads)
|
66
|
+
@workers[:waiter] = Concurrent.new_io_executor
|
67
|
+
@workers[:timer_set] =
|
68
|
+
Concurrent::TimerSet.new(executor: @workers[:waiter])
|
90
69
|
end
|
91
70
|
|
92
71
|
def create_worker(definition)
|
@@ -97,10 +76,6 @@ module Abid
|
|
97
76
|
end
|
98
77
|
end
|
99
78
|
|
100
|
-
def create_default_worker
|
101
|
-
create_worker(num_threads: default_num_threads)
|
102
|
-
end
|
103
|
-
|
104
79
|
def default_num_threads
|
105
80
|
if @env.options.always_multitask
|
106
81
|
@env.options.thread_pool_size ||
|
@@ -109,15 +84,6 @@ module Abid
|
|
109
84
|
1
|
110
85
|
end
|
111
86
|
end
|
112
|
-
|
113
|
-
def check_alive!
|
114
|
-
raise Error, 'already terminated' unless @alive
|
115
|
-
end
|
116
|
-
|
117
|
-
# Iterate on active workers
|
118
|
-
def each_active(&block)
|
119
|
-
@workers.values.select(&:fulfilled?).map(&:value).each(&block)
|
120
|
-
end
|
121
87
|
end
|
122
88
|
end
|
123
89
|
end
|