abid 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 22747c6ec011be62806ac2b1e0793b964e4c524b
4
- data.tar.gz: f0273c75da4be50a6147142c4cdcdf87b4b9ae04
3
+ metadata.gz: 7c41573b12be68e4e74a00c7d8014e7f2d3cc435
4
+ data.tar.gz: b9e43e1b4d742c798972984090eab802245db56f
5
5
  SHA512:
6
- metadata.gz: 289fba1f7416f23f89c3ab4e985516f9ffd605b8809695adbd2191a9d2141a7e6a0dd523a70dcf60b381b5cb28cc9b7450796cc18539ff125a39d40befaa9237
7
- data.tar.gz: a965a6f57ec1052befe48240a7fc108be79a0c3e3fa6d183a70cf652bd6c869da39118e3f3a620a9446ad1eaa9e47e258a23700d1b4bd9d86b98e2db87a7ad5e
6
+ metadata.gz: 8ea210978f2e500611a2ccee925413d8e1e85dcb54cc770ca626622ca588c52650324925c00aa5a47178e732cdf0adaa88fe0a7c79436fd399785d888426ff38
7
+ data.tar.gz: f5fd045370053a9fd27e88d007a071bb888f4b658082ed331d1b81aff6ee303fa040705908f64be6d3af21b3ea2f2dfd9ee80dff2597e4c13d3084cc97a20cca
data/.gitignore CHANGED
@@ -8,3 +8,4 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  *.db
11
+ /sample/out/
data/lib/abid.rb CHANGED
@@ -13,13 +13,13 @@ require 'sqlite3'
13
13
  require 'sequel'
14
14
 
15
15
  require 'abid/rake_extensions'
16
- require 'abid/concurrent_extention'
17
16
  require 'abid/version'
18
17
  require 'abid/abid_module'
19
18
  require 'abid/waiter'
20
19
  require 'abid/worker'
21
20
  require 'abid/params_parser'
22
21
  require 'abid/play'
22
+ require 'abid/session'
23
23
  require 'abid/state'
24
24
  require 'abid/task'
25
25
  require 'abid/task_manager'
data/lib/abid/play.rb CHANGED
@@ -25,12 +25,7 @@ module Abid
25
25
  end
26
26
 
27
27
  def hooks
28
- @hooks ||= {
29
- setup: [],
30
- before: [],
31
- after: [],
32
- around: []
33
- }
28
+ @hooks ||= Hash.new { |h, k| h[k] = [] }
34
29
  end
35
30
 
36
31
  def set(name, value = nil, &block)
@@ -65,10 +60,6 @@ module Abid
65
60
  hooks[:after] << block
66
61
  end
67
62
 
68
- def around(&block)
69
- hooks[:around] << block
70
- end
71
-
72
63
  def method_added(name)
73
64
  params_spec.delete(name) # undef param
74
65
  end
@@ -9,6 +9,16 @@ module Abid
9
9
  :default
10
10
  end
11
11
 
12
+ def session
13
+ @session ||= Session.new(self).tap do |session|
14
+ session.add_observer do |_, _, reason|
15
+ if session.successed? || session.failed?
16
+ call_hooks(:after_invoke, reason)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
12
22
  def state
13
23
  State.find(self)
14
24
  end
@@ -17,102 +27,98 @@ module Abid
17
27
  name
18
28
  end
19
29
 
30
+ def concerned?
31
+ true
32
+ end
33
+
34
+ def top_level?
35
+ application.top_level_tasks.any? { |t| application[t] == self }
36
+ end
37
+
38
+ def hooks
39
+ @hooks ||= Hash.new { |h, k| h[k] = [] }
40
+ end
41
+
42
+ def call_hooks(tag, *args)
43
+ hooks[tag].each { |h| h.call(*args) }
44
+ end
45
+
20
46
  def async_invoke(*args)
21
47
  task_args = Rake::TaskArguments.new(arg_names, args)
22
48
  async_invoke_with_call_chain(task_args, Rake::InvocationChain::EMPTY)
23
49
  end
24
50
 
25
51
  def async_invoke_with_call_chain(task_args, invocation_chain)
26
- state.reload
27
-
28
- new_chain = Rake::InvocationChain.append(self, invocation_chain)
52
+ session.enter do
53
+ session.capture_exception do
54
+ new_chain = Rake::InvocationChain.append(self, invocation_chain)
29
55
 
30
- state.only_once do
31
- if !application.options.repair && state.successed?
32
- # skip if successed
33
- state.ivar.try_set(false)
34
- elsif !application.options.repair && state.failed? && !invocation_chain.empty?
35
- # fail if not top level
36
- fail "#{name} -- task has been failed" rescue state.ivar.try_fail($ERROR_INFO)
37
- else
38
- async_invoke_with_prerequisites(task_args, new_chain)
39
- end
40
- end
41
- state.ivar
42
- ensure
43
- state.ivar.try_fail($ERROR_INFO) if $ERROR_INFO
44
- end
56
+ unless concerned?
57
+ session.skip
58
+ break
59
+ end
45
60
 
46
- def async_invoke_with_prerequisites(task_args, invocation_chain)
47
- application.trace "** Invoke #{name_with_params}" if application.options.trace
61
+ call_hooks(:before_invoke)
48
62
 
49
- volatiles, non_volatiles = prerequisite_tasks.partition(&:volatile?)
63
+ async_invoke_prerequisites(task_args, new_chain)
50
64
 
51
- async_invoke_tasks(non_volatiles, task_args, invocation_chain) do |updated|
52
- if state.successed? && !updated
53
- application.trace "** Skip #{name_with_params}" if application.options.trace
54
- state.ivar.try_set(false)
55
- else
56
- async_invoke_tasks(volatiles, task_args, invocation_chain) do
57
- async_execute_with_session(task_args)
58
- end
65
+ async_execute_after_prerequisites(task_args)
59
66
  end
60
67
  end
61
68
  end
62
69
 
63
- def async_invoke_tasks(tasks, task_args, invocation_chain, &block)
64
- ivars = tasks.map do |t|
70
+ def async_invoke_prerequisites(task_args, invocation_chain)
71
+ prerequisite_tasks.each do |t|
65
72
  args = task_args.new_scope(t.arg_names)
66
73
  t.async_invoke_with_call_chain(args, invocation_chain)
67
74
  end
75
+ end
68
76
 
69
- if ivars.empty?
70
- block.call(false)
77
+ def async_execute_after_prerequisites(task_args)
78
+ if prerequisite_tasks.empty?
79
+ async_execute(task_args)
71
80
  else
72
- counter = Concurrent::DependencyCounter.new(ivars.size) do
73
- begin
74
- if ivars.any?(&:rejected?)
75
- state.ivar.try_fail(ivars.find(&:rejected?).reason)
76
- else
77
- updated = ivars.map(&:value).any?
78
- block.call(updated)
79
- end
80
- rescue Exception => err
81
- state.ivar.try_fail(err)
81
+ counter = Concurrent::DependencyCounter.new(prerequisite_tasks.size) do
82
+ session.capture_exception do
83
+ async_execute(task_args)
82
84
  end
83
85
  end
84
- ivars.each { |i| i.add_observer counter }
86
+ prerequisite_tasks.each { |t| t.session.add_observer counter }
85
87
  end
86
88
  end
87
89
 
88
- def async_execute_with_session(task_args)
89
- async_execute_in_worker do
90
- begin
91
- state.session do
92
- begin
93
- execute(task_args) if needed?
94
- finished = true
95
- ensure
96
- fail "#{name} -- thread killed" if $ERROR_INFO.nil? && !finished
97
- end
98
- end
90
+ def async_execute(task_args)
91
+ failed_task = prerequisite_tasks.find do |t|
92
+ t.session.failed? || t.session.canceled?
93
+ end
94
+ if failed_task
95
+ session.cancel(failed_task.session.error)
96
+ return
97
+ end
98
+
99
+ async_post(worker) do
100
+ if !needed?
101
+ session.skip
102
+ elsif session.lock
103
+ call_hooks(:before_execute)
104
+
105
+ execute(task_args)
99
106
 
100
- state.ivar.try_set(true)
101
- rescue AbidErrorTaskAlreadyRunning
102
- async_wait_complete
107
+ session.success
108
+ else
109
+ async_wait_external
103
110
  end
104
111
  end
105
112
  end
106
113
 
107
- def async_wait_complete
114
+ def async_wait_external
108
115
  unless application.options.wait_external_task
109
- err = RuntimeError.new("task #{name_with_params} already running")
110
- return state.ivar.try_fail(err)
116
+ fail "task #{name_with_params} already running"
111
117
  end
112
118
 
113
119
  application.trace "** Wait #{name_with_params}" if application.options.trace
114
120
 
115
- async_execute_in_worker(:waiter) do
121
+ async_post(:waiter) do
116
122
  interval = application.options.wait_external_task_interval || 10
117
123
  timeout = application.options.wait_external_task_timeout || 3600
118
124
  timeout_tm = Time.now.to_f + timeout
@@ -120,11 +126,10 @@ module Abid
120
126
  loop do
121
127
  state.reload
122
128
  if !state.running?
123
- state.ivar.try_set(true)
129
+ session.success
124
130
  break
125
131
  elsif Time.now.to_f >= timeout_tm
126
- fail "#{name} -- timeout exceeded" rescue state.ivar.try_fail($ERROR_INFO)
127
- break
132
+ fail "#{name} -- timeout exceeded"
128
133
  else
129
134
  sleep interval
130
135
  end
@@ -132,12 +137,15 @@ module Abid
132
137
  end
133
138
  end
134
139
 
135
- def async_execute_in_worker(worker = nil, &block)
136
- application.worker[worker || self.worker].post do
137
- begin
138
- block.call
139
- rescue Exception => err
140
- state.ivar.try_fail(err)
140
+ def async_post(worker_name, &block)
141
+ application.worker[worker_name].post do
142
+ session.capture_exception do
143
+ begin
144
+ block.call
145
+ finished = true
146
+ ensure
147
+ fail 'thread killed' if $ERROR_INFO.nil? && !finished
148
+ end
141
149
  end
142
150
  end
143
151
  end
@@ -0,0 +1,92 @@
1
+ module Abid
2
+ class Session
3
+ extend MonitorMixin
4
+
5
+ %w(successed skipped failed canceled).each do |result|
6
+ define_method(:"#{result}?") { @result == result.to_sym }
7
+ end
8
+ attr_reader :error
9
+
10
+ def initialize(task)
11
+ @task = task
12
+ @state = task.state
13
+
14
+ @entered = false
15
+ @locked = false
16
+ @result = nil
17
+ @error = nil
18
+ @ivar = Concurrent::IVar.new
19
+
20
+ @on_success = []
21
+ @on_fail = []
22
+ end
23
+
24
+ def synchronize(&block)
25
+ self.class.synchronize(&block)
26
+ end
27
+
28
+ def enter(&block)
29
+ synchronize do
30
+ return @ivar if @entered
31
+ @entered = true
32
+ end
33
+ block.call
34
+ @ivar
35
+ end
36
+
37
+ def capture_exception(&block)
38
+ block.call
39
+ rescue Exception => e
40
+ self.fail(e)
41
+ end
42
+
43
+ def add_observer(*args, &block)
44
+ @ivar.add_observer(*args, &block)
45
+ end
46
+
47
+ def lock
48
+ synchronize do
49
+ @state.start unless @locked
50
+ @locked = true
51
+ true
52
+ end
53
+ rescue AbidErrorTaskAlreadyRunning
54
+ false
55
+ end
56
+
57
+ def unlock(error = nil)
58
+ synchronize do
59
+ @state.finish(error) if @locked
60
+ @locked = false
61
+ end
62
+ end
63
+
64
+ def success
65
+ unlock
66
+ @result = :successed
67
+ @ivar.try_set(true)
68
+ end
69
+
70
+ def skip
71
+ unlock
72
+ @result = :skipped
73
+ @ivar.try_set(false)
74
+ end
75
+
76
+ def fail(error)
77
+ @result = :failed
78
+ @error = error
79
+ unlock(error)
80
+ @ivar.fail(error) rescue Concurrent::MultipleAssignmentError
81
+ rescue Exception => e
82
+ @ivar.fail(e) rescue Concurrent::MultipleAssignmentError
83
+ end
84
+
85
+ def cancel(error)
86
+ unlock(error)
87
+ @result = :canceled
88
+ @error = error
89
+ @ivar.fail(error) rescue Concurrent::MultipleAssignmentError
90
+ end
91
+ end
92
+ end
data/lib/abid/state.rb CHANGED
@@ -56,24 +56,14 @@ module Abid
56
56
  end
57
57
 
58
58
  def_delegators 'self.class', :serialize, :deserialize
59
- attr_reader :ivar
60
59
 
61
60
  def initialize(task)
62
61
  @task = task
63
62
  @record = nil
64
- @ivar = Concurrent::IVar.new
65
- @already_invoked = false
63
+ @started = false
66
64
  reload
67
65
  end
68
66
 
69
- def only_once(&block)
70
- self.class.synchronize do
71
- return if @already_invoked
72
- @already_invoked = true
73
- end
74
- block.call
75
- end
76
-
77
67
  def database
78
68
  Rake.application.database
79
69
  end
@@ -155,14 +145,7 @@ module Abid
155
145
  end
156
146
  end
157
147
 
158
- def session(&block)
159
- started = start_session
160
- block.call
161
- ensure
162
- close_session($ERROR_INFO) if started
163
- end
164
-
165
- def start_session
148
+ def start
166
149
  return true if disabled? || preview?
167
150
 
168
151
  database.transaction do
@@ -189,13 +172,15 @@ module Abid
189
172
  @record = { id: id, **new_state }
190
173
  end
191
174
 
175
+ @started = true
192
176
  true
193
177
  end
194
178
  end
195
179
 
196
- def close_session(error = nil)
180
+ def finish(error = nil)
197
181
  return if disabled? || preview?
198
182
  return unless @record
183
+ return unless @started
199
184
  state = error ? FAILED : SUCCESSED
200
185
  dataset.where(id: @record[:id]).update(state: state, end_time: Time.now)
201
186
  reload
data/lib/abid/task.rb CHANGED
@@ -39,8 +39,10 @@ module Abid
39
39
  @prerequisites = []
40
40
  @params = sorted_params
41
41
  @play = play_class.new(t)
42
+ call_play_hooks(:setup)
43
+ bind_play_hooks(:before, :before_execute)
44
+ bind_play_hooks(:after, :after_invoke)
42
45
  end
43
- play_class.hooks[:setup].each { |blk| t.play.instance_eval(&blk) }
44
46
  end
45
47
  end
46
48
 
@@ -97,22 +99,32 @@ module Abid
97
99
  application.trace "** Execute #{name_with_params}"
98
100
  end
99
101
 
100
- play_class.hooks[:before].each { |blk| play.instance_eval(&blk) }
102
+ play.run
103
+ end
104
+
105
+ def concerned?
106
+ state.reload
101
107
 
102
- call_around_hooks(play_class.hooks[:around]) { play.run }
108
+ if !application.options.repair && state.failed? && !top_level?
109
+ fail "#{name} -- task has been failed"
110
+ end
103
111
 
104
- play_class.hooks[:after].each { |blk| play.instance_eval(&blk) }
112
+ application.options.repair || !state.successed?
105
113
  end
106
114
 
107
- def call_around_hooks(hooks, &body)
108
- if hooks.empty?
109
- body.call
110
- else
111
- h, *rest = hooks
112
- play.instance_exec(-> { call_around_hooks(rest, &body) }, &h)
113
- end
115
+ def needed?
116
+ !state.successed? || prerequisite_tasks.any? { |t| t.session.successed? }
117
+ end
118
+
119
+ def bind_play_hooks(tag, to = nil)
120
+ to ||= tag
121
+ hooks[to] = [proc { |*args| call_play_hooks(tag, *args) }]
122
+ end
123
+
124
+ def call_play_hooks(tag, *args)
125
+ return unless bound?
126
+ play_class.hooks[tag].each { |blk| play.instance_exec(*args, &blk) }
114
127
  end
115
- private :call_around_hooks
116
128
 
117
129
  class <<self
118
130
  def define_play(*args, &block) # :nodoc:
data/lib/abid/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Abid
2
- VERSION = "0.2.3"
2
+ VERSION = "0.2.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: abid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hikaru Ojima
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-03-23 00:00:00.000000000 Z
11
+ date: 2016-03-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -159,13 +159,12 @@ files:
159
159
  - lib/abid.rb
160
160
  - lib/abid/abid_module.rb
161
161
  - lib/abid/application.rb
162
- - lib/abid/concurrent_extention.rb
163
- - lib/abid/concurrent_extention/ivar.rb
164
162
  - lib/abid/dsl_definition.rb
165
163
  - lib/abid/params_parser.rb
166
164
  - lib/abid/play.rb
167
165
  - lib/abid/rake_extensions.rb
168
166
  - lib/abid/rake_extensions/task.rb
167
+ - lib/abid/session.rb
169
168
  - lib/abid/state.rb
170
169
  - lib/abid/task.rb
171
170
  - lib/abid/task_manager.rb
@@ -1,6 +0,0 @@
1
- module Abid
2
- module ConcurrentExtention
3
- require 'abid/concurrent_extention/ivar'
4
- Concurrent::IVar.include IVar
5
- end
6
- end
@@ -1,12 +0,0 @@
1
- module Abid
2
- module ConcurrentExtention
3
- module IVar
4
- def try_fail(reason = StandardError.new)
5
- self.fail(reason)
6
- true
7
- rescue Concurrent::MultipleAssignmentError
8
- false
9
- end
10
- end
11
- end
12
- end