abid 0.1.1

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.
@@ -0,0 +1,30 @@
1
+ module Abid
2
+ class Task < Rake::Task
3
+ extend Forwardable
4
+
5
+ attr_accessor :play_class
6
+ attr_accessor :play
7
+
8
+ def_delegators :play, :params, :worker, :volatile?
9
+
10
+ def initialize(task_name, app)
11
+ super(task_name, app)
12
+ @actions << proc { |t| t.play.invoke }
13
+ @actions.freeze
14
+ end
15
+
16
+ def prerequisite_tasks
17
+ fail 'no play is bound yet' if @play.nil?
18
+
19
+ play.prerequisites.map do |pre, params|
20
+ application[pre, @scope, **params]
21
+ end
22
+ end
23
+
24
+ class <<self
25
+ def define_play(*args, &block) # :nodoc:
26
+ Rake.application.define_play(self, *args, &block)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,65 @@
1
+ module Abid
2
+ module TaskManager
3
+ def initialize
4
+ super
5
+ @plays = {}
6
+ end
7
+
8
+ def define_play(task_class, play_name, extends: nil, &block)
9
+ task = define_task(task_class, play_name)
10
+
11
+ klass = lookup_play_class(extends)
12
+ task.play_class = Class.new(klass, &block).tap { |c| c.task = task }
13
+ task
14
+ end
15
+
16
+ def [](task_name, scopes = nil, **params)
17
+ task = super(task_name, scopes)
18
+
19
+ if task.respond_to? :play_class
20
+ intern_play(task, **params)
21
+ else
22
+ task
23
+ end
24
+ end
25
+
26
+ def intern_play(task, **params)
27
+ play = task.play_class.new(**params)
28
+
29
+ return @plays[play] if @plays.include?(play)
30
+
31
+ play.setup
32
+ @plays[play] = task.dup.tap { |t| t.play = play }
33
+ end
34
+
35
+ def default_play_class(&block)
36
+ if block_given?
37
+ @default_play_class = Class.new(Abid::Play, &block)
38
+ else
39
+ @default_play_class ||= Abid::Play
40
+ end
41
+ end
42
+
43
+ def lookup_play_class(task_name, scope = nil)
44
+ if task_name.nil?
45
+ default_play_class
46
+ else
47
+ task_name = task_name.to_s
48
+ t = lookup(task_name, scope)
49
+ if t.respond_to? :play_class
50
+ t.play_class
51
+ elsif t.nil?
52
+ fail "play #{task_name} not found"
53
+ else
54
+ fail "task #{task_name} has no play class"
55
+ end
56
+ end
57
+ end
58
+
59
+ class << self
60
+ def record_task_metadata # :nodoc:
61
+ Rake::TaskManager.record_task_metadata
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,3 @@
1
+ module Abid
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,110 @@
1
+ module Abid
2
+ # non-block waiter
3
+ class Waiter
4
+ Entry = Struct.new(:ivar, :start_time, :next_time,
5
+ :interval, :timeout, :block)
6
+
7
+ def initialize
8
+ @cv = ConditionVariable.new
9
+ @mutex = Mutex.new
10
+ @queue = MultiRBTree.new
11
+ @thread = nil
12
+ @error = nil
13
+ end
14
+
15
+ def wait(interval: 5, timeout: 60, &block)
16
+ run_thread
17
+
18
+ ivar = Concurrent::IVar.new
19
+ now = Time.now.to_f
20
+ next_time = now + interval
21
+ push(Entry.new(ivar, now, next_time, interval, timeout, block))
22
+ ivar
23
+ end
24
+
25
+ def shutdown(error = nil)
26
+ error ||= RuntimeError.new('waiter is shutting down')
27
+ @mutex.synchronize do
28
+ @error = error
29
+ @queue.each { |_, e| e.ivar.fail(error) }
30
+ @queue.clear
31
+ end
32
+ end
33
+
34
+ def empty?
35
+ @queue.empty?
36
+ end
37
+
38
+ def alive?
39
+ @thread.alive?
40
+ end
41
+
42
+ private
43
+
44
+ def push(entry)
45
+ @mutex.synchronize do
46
+ fail @error if @error
47
+
48
+ @queue[entry.next_time] = entry
49
+ @cv.signal
50
+ end
51
+ end
52
+
53
+ def shift
54
+ _, e = @mutex.synchronize do
55
+ @cv.wait(@mutex) while @queue.empty?
56
+ @queue.shift
57
+ end
58
+ e
59
+ end
60
+
61
+ def sleep_until_next_time(entry)
62
+ sleep_time = entry.next_time - Time.now.to_f
63
+ return true if sleep_time <= 0
64
+
65
+ @mutex.synchronize { @cv.wait(@mutex, sleep_time) }
66
+
67
+ entry.next_time <= Time.now.to_f
68
+ end
69
+
70
+ def proc_entry(entry)
71
+ unless sleep_until_next_time(entry)
72
+ # failed to wait. retry.
73
+ push(entry)
74
+ return
75
+ end
76
+
77
+ return if entry.ivar.complete? # canceled
78
+
79
+ now = Time.now.to_f
80
+ elapsed = now - entry.start_time
81
+ ret = entry.block.call(elapsed)
82
+ if ret
83
+ entry.ivar.try_set(ret)
84
+ elsif entry.timeout > 0 && entry.timeout < elapsed
85
+ fail 'timeout exceeded'
86
+ else
87
+ entry.next_time = now + entry.interval
88
+ push(entry)
89
+ end
90
+ rescue Exception => err
91
+ begin
92
+ entry.ivar.fail(err)
93
+ rescue Concurrent::MultipleAssignmentError
94
+ nil
95
+ end
96
+ end
97
+
98
+ def run_thread
99
+ return if @thread
100
+
101
+ @thread = Thread.new do
102
+ begin
103
+ proc_entry(shift) while @error.nil?
104
+ ensure
105
+ shutdown($ERROR_INFO) if $ERROR_INFO
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,39 @@
1
+ module Abid
2
+ class Worker
3
+ def initialize(application)
4
+ @application = application
5
+ @pools = {}
6
+
7
+ default_thread_num = @application.options.thread_pool_size || \
8
+ Rake.suggested_thread_count - 1
9
+ @pools[:default] = Concurrent::FixedThreadPool.new(
10
+ default_thread_num,
11
+ idletime: FIXNUM_MAX
12
+ )
13
+
14
+ @pools[:waiter] = Concurrent::SimpleExecutorService.new
15
+ end
16
+
17
+ def define(name, thread_count)
18
+ name = name.to_sym
19
+ fail "worker #{name} already defined" if @pools.include?(name)
20
+ @pools[name] = Concurrent::FixedThreadPool.new(
21
+ thread_count,
22
+ idletime: FIXNUM_MAX
23
+ )
24
+ end
25
+
26
+ def [](name)
27
+ name = (name || :default).to_sym
28
+ fail "worker #{name} is not defined" unless @pools.include?(name)
29
+ @pools[name]
30
+ end
31
+
32
+ def shutdown
33
+ @pools.each do |_, pool|
34
+ pool.shutdown
35
+ pool.wait_for_termination
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,15 @@
1
+ Sequel.migration do
2
+ change do
3
+ create_table(:states) do
4
+ primary_key :id
5
+ String :digest, null: false
6
+ String :name, null: false
7
+ String :params, null: false
8
+ Integer :state
9
+ Time :start_time
10
+ Time :end_time
11
+
12
+ index :digest
13
+ end
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,183 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: abid
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Hikaru Ojima
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-02-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: concurrent-ruby-ext
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: inifile
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sequel
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: sqlite3
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rbtree
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Abid is a simple Workflow Engine based on Rake.
126
+ email:
127
+ - amijo4rihaku@gmail.com
128
+ executables:
129
+ - abid
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".gitignore"
134
+ - ".travis.yml"
135
+ - CODE_OF_CONDUCT.md
136
+ - Gemfile
137
+ - LICENSE.txt
138
+ - README.md
139
+ - Rakefile
140
+ - abid.gemspec
141
+ - bin/console
142
+ - bin/setup
143
+ - exe/abid
144
+ - lib/Abidfile.rb
145
+ - lib/abid.rb
146
+ - lib/abid/application.rb
147
+ - lib/abid/dsl_definition.rb
148
+ - lib/abid/params_parser.rb
149
+ - lib/abid/play.rb
150
+ - lib/abid/rake_extensions.rb
151
+ - lib/abid/rake_extensions/task.rb
152
+ - lib/abid/state.rb
153
+ - lib/abid/task.rb
154
+ - lib/abid/task_manager.rb
155
+ - lib/abid/version.rb
156
+ - lib/abid/waiter.rb
157
+ - lib/abid/worker.rb
158
+ - migrations/01_create_state_table.rb
159
+ homepage: https://github.com/ojima-h/abid
160
+ licenses:
161
+ - MIT
162
+ metadata: {}
163
+ post_install_message:
164
+ rdoc_options: []
165
+ require_paths:
166
+ - lib
167
+ required_ruby_version: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ required_rubygems_version: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: '0'
177
+ requirements: []
178
+ rubyforge_project:
179
+ rubygems_version: 2.5.2
180
+ signing_key:
181
+ specification_version: 4
182
+ summary: Abid is a simple Workflow Engine based on Rake.
183
+ test_files: []