abid 0.3.0.pre.alpha.3 → 0.3.0.pre.alpha.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|