asynchronic 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +2 -1
- data/asynchronic.gemspec +1 -0
- data/lib/asynchronic.rb +11 -6
- data/lib/asynchronic/data_store/in_memory.rb +7 -2
- data/lib/asynchronic/data_store/key.rb +4 -0
- data/lib/asynchronic/data_store/redis.rb +9 -4
- data/lib/asynchronic/data_store/scoped_store.rb +6 -2
- data/lib/asynchronic/garbage_collector.rb +61 -0
- data/lib/asynchronic/process.rb +14 -4
- data/lib/asynchronic/version.rb +1 -1
- data/spec/data_store/data_store_examples.rb +17 -0
- data/spec/data_store/key_spec.rb +12 -12
- data/spec/facade_spec.rb +4 -0
- data/spec/process/life_cycle_examples.rb +139 -47
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b2bd845501396b08b9d2948649a8792af6a966cb
|
4
|
+
data.tar.gz: 577a10429b1df9448d84394c85d5f38752f4380b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58b29093b0856f719a24efc276ab827bc83a492dfa3b781ed3ced23ab6d58e6f869989abd08c1bceb35d94712f060dec419f2d643ba1b83917b8eb0ce538feae
|
7
|
+
data.tar.gz: 7f7248fdc544ac0bd902311ab4893bc02f0545b689206f1061fab5f6e4e0d334dd36c842024fb7bf9c35c764e3d7527c122ddbf7fd9830f05fce3204676e561e
|
data/Rakefile
CHANGED
@@ -3,7 +3,8 @@ require 'rake/testtask'
|
|
3
3
|
|
4
4
|
Rake::TestTask.new(:spec) do |t|
|
5
5
|
t.libs << 'spec'
|
6
|
-
t.
|
6
|
+
t.libs << 'lib'
|
7
|
+
t.pattern = ENV['DIR'] ? File.join(ENV['DIR'], '**', '*_spec.rb') : 'spec/**/*_spec.rb'
|
7
8
|
t.verbose = false
|
8
9
|
t.warning = false
|
9
10
|
t.loader = nil if ENV['TEST']
|
data/asynchronic.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_dependency 'ost', '~> 0.1'
|
23
23
|
spec.add_dependency 'class_config', '~> 0.0'
|
24
24
|
spec.add_dependency 'transparent_proxy', '~> 0.0'
|
25
|
+
spec.add_dependency 'multi_require', '~> 1.0'
|
25
26
|
|
26
27
|
spec.add_development_dependency 'bundler', '~> 1.12'
|
27
28
|
spec.add_development_dependency 'rake', '~> 11.0'
|
data/lib/asynchronic.rb
CHANGED
@@ -5,8 +5,9 @@ require 'ost'
|
|
5
5
|
require 'class_config'
|
6
6
|
require 'transparent_proxy'
|
7
7
|
require 'logger'
|
8
|
+
require 'multi_require'
|
8
9
|
|
9
|
-
|
10
|
+
MultiRequire.require_relative_pattern 'asynchronic/**/*.rb'
|
10
11
|
|
11
12
|
module Asynchronic
|
12
13
|
|
@@ -16,9 +17,9 @@ module Asynchronic
|
|
16
17
|
attr_config :queue_engine, QueueEngine::InMemory.new
|
17
18
|
attr_config :data_store, DataStore::InMemory.new
|
18
19
|
attr_config :logger, Logger.new($stdout)
|
20
|
+
attr_config :retry_timeout, 30
|
21
|
+
attr_config :garbage_collector_timeout, 30
|
19
22
|
|
20
|
-
RETRY_TIMEOUT = 30
|
21
|
-
|
22
23
|
def self.environment
|
23
24
|
Environment.new queue_engine, data_store
|
24
25
|
end
|
@@ -31,12 +32,16 @@ module Asynchronic
|
|
31
32
|
environment.processes
|
32
33
|
end
|
33
34
|
|
34
|
-
def self.
|
35
|
+
def self.garbage_collector
|
36
|
+
@garbage_collector ||= GarbageCollector.new environment, garbage_collector_timeout
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.retry_execution(klass, message)
|
35
40
|
begin
|
36
41
|
result = yield
|
37
42
|
rescue Exception => ex
|
38
|
-
logger.error(
|
39
|
-
sleep
|
43
|
+
logger.error(klass) { "Retrying #{message}. ERROR: #{ex.message}" }
|
44
|
+
sleep retry_timeout
|
40
45
|
retry
|
41
46
|
end
|
42
47
|
result
|
@@ -23,12 +23,17 @@ module Asynchronic
|
|
23
23
|
@hash.delete key.to_s
|
24
24
|
end
|
25
25
|
|
26
|
+
def delete_cascade(key)
|
27
|
+
keys = self.keys.select { |k| k.sections.first == key }
|
28
|
+
keys.each { |k| delete k }
|
29
|
+
end
|
30
|
+
|
26
31
|
def keys
|
27
|
-
@hash.keys.map { |k| Key
|
32
|
+
@hash.keys.map { |k| Key[k] }
|
28
33
|
end
|
29
34
|
|
30
35
|
def synchronize(key, &block)
|
31
|
-
@keys_mutex[key].synchronize
|
36
|
+
@keys_mutex[key].synchronize(&block)
|
32
37
|
end
|
33
38
|
|
34
39
|
def connection_args
|
@@ -8,8 +8,8 @@ module Asynchronic
|
|
8
8
|
include Helper
|
9
9
|
|
10
10
|
def initialize(scope, *args)
|
11
|
-
@scope = Key
|
12
|
-
@connection = ::Redis.new
|
11
|
+
@scope = Key[scope]
|
12
|
+
@connection = ::Redis.new(*args)
|
13
13
|
end
|
14
14
|
|
15
15
|
def [](key)
|
@@ -28,8 +28,13 @@ module Asynchronic
|
|
28
28
|
@connection.del @scope[key]
|
29
29
|
end
|
30
30
|
|
31
|
+
def delete_cascade(key)
|
32
|
+
@connection.del @scope[key]
|
33
|
+
@connection.keys(@scope[key]['*']).each { |k| @connection.del k }
|
34
|
+
end
|
35
|
+
|
31
36
|
def keys
|
32
|
-
@connection.keys(@scope['*']).map { |k| Key
|
37
|
+
@connection.keys(@scope['*']).map { |k| Key[k].remove_first }
|
33
38
|
end
|
34
39
|
|
35
40
|
def synchronize(key)
|
@@ -46,7 +51,7 @@ module Asynchronic
|
|
46
51
|
end
|
47
52
|
|
48
53
|
def self.connect(*args)
|
49
|
-
new
|
54
|
+
new(*args)
|
50
55
|
end
|
51
56
|
|
52
57
|
end
|
@@ -9,7 +9,7 @@ module Asynchronic
|
|
9
9
|
|
10
10
|
def initialize(data_store, scope)
|
11
11
|
@data_store = data_store
|
12
|
-
@scope = Key
|
12
|
+
@scope = Key[scope]
|
13
13
|
end
|
14
14
|
|
15
15
|
def [](key)
|
@@ -24,10 +24,14 @@ module Asynchronic
|
|
24
24
|
@data_store.delete @scope[key]
|
25
25
|
end
|
26
26
|
|
27
|
+
def delete_cascade
|
28
|
+
@data_store.delete_cascade @scope
|
29
|
+
end
|
30
|
+
|
27
31
|
def keys
|
28
32
|
@data_store.keys.
|
29
33
|
select { |k| k.start_with? @scope[''] }.
|
30
|
-
map { |k| Key
|
34
|
+
map { |k| Key[k].remove_first @scope.sections.count }
|
31
35
|
end
|
32
36
|
|
33
37
|
def synchronize(key, &block)
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Asynchronic
|
2
|
+
class GarbageCollector
|
3
|
+
|
4
|
+
def initialize(environment, timeout)
|
5
|
+
@environment = environment
|
6
|
+
@timeout = timeout
|
7
|
+
@running = false
|
8
|
+
@conditions = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def start
|
12
|
+
Asynchronic.logger.info('Asynchronic') { 'Starting GC' }
|
13
|
+
|
14
|
+
Signal.trap('QUIT') { stop }
|
15
|
+
|
16
|
+
@running = true
|
17
|
+
|
18
|
+
while @running
|
19
|
+
processes = environment.processes
|
20
|
+
|
21
|
+
conditions.each do |name, condition|
|
22
|
+
Asynchronic.logger.info('Asynchronic') { "Running GC - #{name}" }
|
23
|
+
begin
|
24
|
+
processes.select(&condition).each(&:destroy)
|
25
|
+
rescue => ex
|
26
|
+
Asynchronic.logger.error('Asynchronic') { "#{ex.class}: #{ex.message}" }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
wait
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def stop
|
35
|
+
Asynchronic.logger.info('Asynchronic') { 'Stopping GC' }
|
36
|
+
@running = false
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_condition(name, &block)
|
40
|
+
conditions[name] = block
|
41
|
+
end
|
42
|
+
|
43
|
+
def remove_condition(name)
|
44
|
+
conditions.delete name
|
45
|
+
end
|
46
|
+
|
47
|
+
def conditions_names
|
48
|
+
conditions.keys
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
attr_reader :environment, :timeout, :conditions
|
54
|
+
|
55
|
+
def wait
|
56
|
+
Asynchronic.logger.info('Asynchronic') { 'Sleeping GC' }
|
57
|
+
sleep timeout
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
data/lib/asynchronic/process.rb
CHANGED
@@ -13,12 +13,14 @@ module Asynchronic
|
|
13
13
|
|
14
14
|
ATTRIBUTE_NAMES = [:type, :name, :queue, :status, :dependencies, :data, :result, :error] | TIME_TRACKING_MAP.values.uniq
|
15
15
|
|
16
|
+
CANCELED_ERROR_MESSAGE = 'Canceled'
|
17
|
+
|
16
18
|
attr_reader :id
|
17
19
|
|
18
20
|
def initialize(environment, id, &block)
|
19
21
|
@environment = environment
|
20
|
-
@id = DataStore::Key
|
21
|
-
instance_eval
|
22
|
+
@id = DataStore::Key[id]
|
23
|
+
instance_eval(&block) if block_given?
|
22
24
|
end
|
23
25
|
|
24
26
|
ATTRIBUTE_NAMES.each do |attribute|
|
@@ -41,6 +43,14 @@ module Asynchronic
|
|
41
43
|
completed? || aborted?
|
42
44
|
end
|
43
45
|
|
46
|
+
def cancel!
|
47
|
+
abort! CANCELED_ERROR_MESSAGE
|
48
|
+
end
|
49
|
+
|
50
|
+
def destroy
|
51
|
+
data_store.delete_cascade
|
52
|
+
end
|
53
|
+
|
44
54
|
def full_status
|
45
55
|
processes.each_with_object(name => status) do |process, hash|
|
46
56
|
hash.update(process.full_status)
|
@@ -60,7 +70,7 @@ module Asynchronic
|
|
60
70
|
end
|
61
71
|
|
62
72
|
def [](process_name)
|
63
|
-
processes.detect { |p| p.name == process_name }
|
73
|
+
processes.detect { |p| p.name == process_name.to_s }
|
64
74
|
end
|
65
75
|
|
66
76
|
def processes
|
@@ -131,7 +141,7 @@ module Asynchronic
|
|
131
141
|
|
132
142
|
new(environment, id) do
|
133
143
|
self.type = type
|
134
|
-
self.name = params.delete(:alias) || type
|
144
|
+
self.name = (params.delete(:alias) || type).to_s
|
135
145
|
self.queue = params.delete(:queue) || type.queue || parent_queue
|
136
146
|
self.dependencies = Array(params.delete(:dependencies)) | Array(params.delete(:dependency)) | infer_dependencies(params)
|
137
147
|
self.params = params
|
data/lib/asynchronic/version.rb
CHANGED
@@ -21,6 +21,23 @@ module DataStoreExamples
|
|
21
21
|
data_store[:key].must_be_nil
|
22
22
|
end
|
23
23
|
|
24
|
+
it 'Delete cascade' do
|
25
|
+
data_store[Key[:key_1]] = 1
|
26
|
+
data_store[Key[:key_1][:key_1_1]] = 2
|
27
|
+
data_store[Key[:key_1][:key_1_2]] = 3
|
28
|
+
data_store[Key[:key_2]] = 4
|
29
|
+
data_store[Key[:key_2][:key_2_1]] = 5
|
30
|
+
data_store[Key[:key_2][:key_2_2]] = 6
|
31
|
+
|
32
|
+
data_store.delete_cascade Key[:key_1]
|
33
|
+
|
34
|
+
data_store.keys.sort.must_equal [
|
35
|
+
Key[:key_2],
|
36
|
+
Key[:key_2][:key_2_1],
|
37
|
+
Key[:key_2][:key_2_2]
|
38
|
+
]
|
39
|
+
end
|
40
|
+
|
24
41
|
it 'Each' do
|
25
42
|
data_store[:a] = 1
|
26
43
|
data_store[:b] = 2
|
data/spec/data_store/key_spec.rb
CHANGED
@@ -5,54 +5,54 @@ describe Asynchronic::DataStore::Key do
|
|
5
5
|
Key = Asynchronic::DataStore::Key
|
6
6
|
|
7
7
|
it 'Return the namespace' do
|
8
|
-
key = Key
|
8
|
+
key = Key['foo']
|
9
9
|
key.must_equal 'foo'
|
10
10
|
end
|
11
11
|
|
12
12
|
it 'Prepend the namespace' do
|
13
|
-
key = Key
|
13
|
+
key = Key['foo']
|
14
14
|
key['bar'].must_equal 'foo|bar'
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'Work in more than one level' do
|
18
|
-
key_1 = Key
|
19
|
-
key_2 = Key
|
18
|
+
key_1 = Key['foo']
|
19
|
+
key_2 = Key[key_1['bar']]
|
20
20
|
key_2['baz'].must_equal 'foo|bar|baz'
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'Be chainable' do
|
24
|
-
key = Key
|
24
|
+
key = Key['foo']
|
25
25
|
key['bar']['baz'].must_equal 'foo|bar|baz'
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'Accept symbols' do
|
29
|
-
key = Key
|
29
|
+
key = Key[:foo]
|
30
30
|
key[:bar].must_equal 'foo|bar'
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'Accept numbers' do
|
34
|
-
key = Key
|
34
|
+
key = Key['foo']
|
35
35
|
key[3].must_equal 'foo|3'
|
36
36
|
end
|
37
37
|
|
38
38
|
it 'Split in sections' do
|
39
|
-
key = Key
|
39
|
+
key = Key[:foo][:bar][:buz]
|
40
40
|
key.sections.must_equal %w(foo bar buz)
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'Detect nested sections' do
|
44
|
-
Key
|
45
|
-
Key
|
44
|
+
Key[:foo].wont_be :nested?
|
45
|
+
Key[:foo][:bar].must_be :nested?
|
46
46
|
end
|
47
47
|
|
48
48
|
it 'Remove first sections' do
|
49
|
-
key = Key
|
49
|
+
key = Key[:foo][:bar][:buz]
|
50
50
|
key.remove_first.must_equal 'bar|buz'
|
51
51
|
key.remove_first(2).must_equal 'buz'
|
52
52
|
end
|
53
53
|
|
54
54
|
it 'Remove last sections' do
|
55
|
-
key = Key
|
55
|
+
key = Key[:foo][:bar][:buz]
|
56
56
|
key.remove_last.must_equal 'foo|bar'
|
57
57
|
key.remove_last(2).must_equal 'foo'
|
58
58
|
end
|
data/spec/facade_spec.rb
CHANGED
@@ -493,73 +493,165 @@ module LifeCycleExamples
|
|
493
493
|
|
494
494
|
execute queue
|
495
495
|
|
496
|
-
process.full_status.must_equal AbortQueuedAfertErrorJob
|
497
|
-
AbortQueuedAfertErrorJob::Child_1 => :queued,
|
498
|
-
AbortQueuedAfertErrorJob::Child_2 => :queued,
|
499
|
-
AbortQueuedAfertErrorJob::Child_3 => :queued,
|
500
|
-
AbortQueuedAfertErrorJob::Child_4 => :queued
|
496
|
+
process.full_status.must_equal 'AbortQueuedAfertErrorJob' => :waiting,
|
497
|
+
'AbortQueuedAfertErrorJob::Child_1' => :queued,
|
498
|
+
'AbortQueuedAfertErrorJob::Child_2' => :queued,
|
499
|
+
'AbortQueuedAfertErrorJob::Child_3' => :queued,
|
500
|
+
'AbortQueuedAfertErrorJob::Child_4' => :queued
|
501
501
|
|
502
502
|
execute queue
|
503
503
|
|
504
|
-
process.full_status.must_equal AbortQueuedAfertErrorJob
|
505
|
-
AbortQueuedAfertErrorJob::Child_1 => :waiting,
|
506
|
-
'Child_1_1'
|
507
|
-
'Child_1_2'
|
508
|
-
AbortQueuedAfertErrorJob::Child_2 => :queued,
|
509
|
-
AbortQueuedAfertErrorJob::Child_3 => :queued,
|
510
|
-
AbortQueuedAfertErrorJob::Child_4 => :queued
|
504
|
+
process.full_status.must_equal 'AbortQueuedAfertErrorJob' => :waiting,
|
505
|
+
'AbortQueuedAfertErrorJob::Child_1' => :waiting,
|
506
|
+
'Child_1_1' => :queued,
|
507
|
+
'Child_1_2' => :queued,
|
508
|
+
'AbortQueuedAfertErrorJob::Child_2' => :queued,
|
509
|
+
'AbortQueuedAfertErrorJob::Child_3' => :queued,
|
510
|
+
'AbortQueuedAfertErrorJob::Child_4' => :queued
|
511
511
|
|
512
512
|
execute queue
|
513
513
|
|
514
|
-
process.full_status.must_equal AbortQueuedAfertErrorJob
|
515
|
-
AbortQueuedAfertErrorJob::Child_1 => :waiting,
|
516
|
-
'Child_1_1'
|
517
|
-
'Child_1_2'
|
518
|
-
AbortQueuedAfertErrorJob::Child_2 => :completed,
|
519
|
-
AbortQueuedAfertErrorJob::Child_3 => :queued,
|
520
|
-
AbortQueuedAfertErrorJob::Child_4 => :queued
|
514
|
+
process.full_status.must_equal 'AbortQueuedAfertErrorJob' => :waiting,
|
515
|
+
'AbortQueuedAfertErrorJob::Child_1' => :waiting,
|
516
|
+
'Child_1_1' => :queued,
|
517
|
+
'Child_1_2' => :queued,
|
518
|
+
'AbortQueuedAfertErrorJob::Child_2' => :completed,
|
519
|
+
'AbortQueuedAfertErrorJob::Child_3' => :queued,
|
520
|
+
'AbortQueuedAfertErrorJob::Child_4' => :queued
|
521
521
|
|
522
522
|
execute queue
|
523
523
|
|
524
|
-
process.full_status.must_equal AbortQueuedAfertErrorJob
|
525
|
-
AbortQueuedAfertErrorJob::Child_1 => :waiting,
|
526
|
-
'Child_1_1'
|
527
|
-
'Child_1_2'
|
528
|
-
AbortQueuedAfertErrorJob::Child_2 => :completed,
|
529
|
-
AbortQueuedAfertErrorJob::Child_3 => :aborted,
|
530
|
-
AbortQueuedAfertErrorJob::Child_4 => :queued
|
524
|
+
process.full_status.must_equal 'AbortQueuedAfertErrorJob' => :aborted,
|
525
|
+
'AbortQueuedAfertErrorJob::Child_1' => :waiting,
|
526
|
+
'Child_1_1' => :queued,
|
527
|
+
'Child_1_2' => :queued,
|
528
|
+
'AbortQueuedAfertErrorJob::Child_2' => :completed,
|
529
|
+
'AbortQueuedAfertErrorJob::Child_3' => :aborted,
|
530
|
+
'AbortQueuedAfertErrorJob::Child_4' => :queued
|
531
531
|
|
532
532
|
execute queue
|
533
533
|
|
534
|
-
process.full_status.must_equal AbortQueuedAfertErrorJob
|
535
|
-
AbortQueuedAfertErrorJob::Child_1 => :waiting,
|
536
|
-
'Child_1_1'
|
537
|
-
'Child_1_2'
|
538
|
-
AbortQueuedAfertErrorJob::Child_2 => :completed,
|
539
|
-
AbortQueuedAfertErrorJob::Child_3 => :aborted,
|
540
|
-
AbortQueuedAfertErrorJob::Child_4 => :aborted
|
534
|
+
process.full_status.must_equal 'AbortQueuedAfertErrorJob' => :aborted,
|
535
|
+
'AbortQueuedAfertErrorJob::Child_1' => :waiting,
|
536
|
+
'Child_1_1' => :queued,
|
537
|
+
'Child_1_2' => :queued,
|
538
|
+
'AbortQueuedAfertErrorJob::Child_2' => :completed,
|
539
|
+
'AbortQueuedAfertErrorJob::Child_3' => :aborted,
|
540
|
+
'AbortQueuedAfertErrorJob::Child_4' => :aborted
|
541
541
|
|
542
542
|
execute queue
|
543
543
|
|
544
|
-
process.full_status.must_equal AbortQueuedAfertErrorJob
|
545
|
-
AbortQueuedAfertErrorJob::Child_1 => :aborted,
|
546
|
-
'Child_1_1'
|
547
|
-
'Child_1_2'
|
548
|
-
AbortQueuedAfertErrorJob::Child_2 => :completed,
|
549
|
-
AbortQueuedAfertErrorJob::Child_3 => :aborted,
|
550
|
-
AbortQueuedAfertErrorJob::Child_4 => :aborted
|
544
|
+
process.full_status.must_equal 'AbortQueuedAfertErrorJob' => :aborted,
|
545
|
+
'AbortQueuedAfertErrorJob::Child_1' => :aborted,
|
546
|
+
'Child_1_1' => :aborted,
|
547
|
+
'Child_1_2' => :queued,
|
548
|
+
'AbortQueuedAfertErrorJob::Child_2' => :completed,
|
549
|
+
'AbortQueuedAfertErrorJob::Child_3' => :aborted,
|
550
|
+
'AbortQueuedAfertErrorJob::Child_4' => :aborted
|
551
551
|
|
552
552
|
execute queue
|
553
553
|
|
554
|
-
process.full_status.must_equal AbortQueuedAfertErrorJob
|
555
|
-
AbortQueuedAfertErrorJob::Child_1 => :aborted,
|
556
|
-
'Child_1_1'
|
557
|
-
'Child_1_2'
|
558
|
-
AbortQueuedAfertErrorJob::Child_2 => :completed,
|
559
|
-
AbortQueuedAfertErrorJob::Child_3 => :aborted,
|
560
|
-
AbortQueuedAfertErrorJob::Child_4 => :aborted
|
554
|
+
process.full_status.must_equal 'AbortQueuedAfertErrorJob' => :aborted,
|
555
|
+
'AbortQueuedAfertErrorJob::Child_1' => :aborted,
|
556
|
+
'Child_1_1' => :aborted,
|
557
|
+
'Child_1_2' => :aborted,
|
558
|
+
'AbortQueuedAfertErrorJob::Child_2' => :completed,
|
559
|
+
'AbortQueuedAfertErrorJob::Child_3' => :aborted,
|
560
|
+
'AbortQueuedAfertErrorJob::Child_4' => :aborted
|
561
561
|
|
562
562
|
process.real_error.must_equal 'Forced error'
|
563
563
|
end
|
564
564
|
|
565
|
+
it 'Manual abort' do
|
566
|
+
process = create NestedJob, input: 10
|
567
|
+
|
568
|
+
process.enqueue
|
569
|
+
|
570
|
+
execute queue
|
571
|
+
|
572
|
+
process.full_status.must_equal 'NestedJob' => :waiting,
|
573
|
+
'NestedJob::Level1' => :queued
|
574
|
+
|
575
|
+
execute queue
|
576
|
+
|
577
|
+
process.full_status.must_equal 'NestedJob' => :waiting,
|
578
|
+
'NestedJob::Level1' => :waiting,
|
579
|
+
'NestedJob::Level1::Level2' => :queued
|
580
|
+
|
581
|
+
process.cancel!
|
582
|
+
|
583
|
+
process.real_error.must_equal Asynchronic::Process::CANCELED_ERROR_MESSAGE
|
584
|
+
|
585
|
+
process.full_status.must_equal 'NestedJob' => :aborted,
|
586
|
+
'NestedJob::Level1' => :waiting,
|
587
|
+
'NestedJob::Level1::Level2' => :queued
|
588
|
+
|
589
|
+
execute queue
|
590
|
+
|
591
|
+
process.full_status.must_equal 'NestedJob' => :aborted,
|
592
|
+
'NestedJob::Level1' => :aborted,
|
593
|
+
'NestedJob::Level1::Level2' => :aborted
|
594
|
+
end
|
595
|
+
|
596
|
+
it 'Remove process' do
|
597
|
+
process_1 = create AliasJob
|
598
|
+
process_2 = create AliasJob
|
599
|
+
|
600
|
+
process_1.enqueue
|
601
|
+
|
602
|
+
execute queue
|
603
|
+
|
604
|
+
pid_1 = process_1.id
|
605
|
+
pid_2 = process_2.id
|
606
|
+
|
607
|
+
data_store.keys.select { |k| k.start_with? pid_1 }.count.must_equal 37
|
608
|
+
data_store.keys.select { |k| k.start_with? pid_2 }.count.must_equal 7
|
609
|
+
|
610
|
+
process_1.destroy
|
611
|
+
|
612
|
+
data_store.keys.select { |k| k.start_with? pid_1 }.count.must_equal 0
|
613
|
+
data_store.keys.select { |k| k.start_with? pid_2 }.count.must_equal 7
|
614
|
+
end
|
615
|
+
|
616
|
+
it 'Garbage collector' do
|
617
|
+
process_1 = create AliasJob
|
618
|
+
process_1.enqueue
|
619
|
+
4.times { execute queue }
|
620
|
+
|
621
|
+
process_2 = create AliasJob
|
622
|
+
process_2.enqueue
|
623
|
+
execute queue
|
624
|
+
|
625
|
+
pid_1 = process_1.id
|
626
|
+
pid_2 = process_2.id
|
627
|
+
|
628
|
+
process_1.must_be_completed
|
629
|
+
process_2.must_be_waiting
|
630
|
+
|
631
|
+
data_store.keys.select { |k| k.start_with? pid_1 }.count.must_equal 49
|
632
|
+
data_store.keys.select { |k| k.start_with? pid_2 }.count.must_equal 37
|
633
|
+
|
634
|
+
gc = Asynchronic::GarbageCollector.new env, 0.001
|
635
|
+
|
636
|
+
gc.add_condition('Completed', &:completed?)
|
637
|
+
gc.add_condition('Waiting', &:waiting?)
|
638
|
+
gc.add_condition('Exception') { raise 'Invalid condition' }
|
639
|
+
|
640
|
+
gc.conditions_names.must_equal ['Completed', 'Waiting', 'Exception']
|
641
|
+
|
642
|
+
gc.remove_condition 'Waiting'
|
643
|
+
|
644
|
+
gc.conditions_names.must_equal ['Completed', 'Exception']
|
645
|
+
|
646
|
+
Thread.new do
|
647
|
+
sleep 0.01
|
648
|
+
gc.stop
|
649
|
+
end
|
650
|
+
|
651
|
+
gc.start
|
652
|
+
|
653
|
+
data_store.keys.select { |k| k.start_with? pid_1 }.count.must_equal 0
|
654
|
+
data_store.keys.select { |k| k.start_with? pid_2 }.count.must_equal 37
|
655
|
+
end
|
656
|
+
|
565
657
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: asynchronic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gabriel Naiman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-11-
|
11
|
+
date: 2018-11-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: multi_require
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: bundler
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -221,6 +235,7 @@ files:
|
|
221
235
|
- lib/asynchronic/data_store/scoped_store.rb
|
222
236
|
- lib/asynchronic/environment.rb
|
223
237
|
- lib/asynchronic/error.rb
|
238
|
+
- lib/asynchronic/garbage_collector.rb
|
224
239
|
- lib/asynchronic/job.rb
|
225
240
|
- lib/asynchronic/process.rb
|
226
241
|
- lib/asynchronic/queue_engine/in_memory.rb
|