asynchronic 1.4.0 → 1.5.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a1dfc813a24c2580723d255461a9a6b91376d562
4
- data.tar.gz: 793f9fd3f28c7fc712f98adeba227128b37644f9
3
+ metadata.gz: b2bd845501396b08b9d2948649a8792af6a966cb
4
+ data.tar.gz: 577a10429b1df9448d84394c85d5f38752f4380b
5
5
  SHA512:
6
- metadata.gz: 1a003d3fefe9a1a4f79535a6dc0e1639306f347672d75b1aef6e625c59da4aaeca68a98d0d8d73f02646d62bcef6ec431836531d7292bdb25c0d1bd4854a4ff9
7
- data.tar.gz: c2d6023bd1ea95d9b6147193bea9be6b36062c5bf774c08cd39e85029e4b5825067902553c14db0be6d05416e82b03ba4bea404376a62c64aad00fd0c0508caa
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.pattern = 'spec/**/*_spec.rb'
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
- Dir.glob(File.expand_path('asynchronic/**/*.rb', File.dirname(__FILE__))).sort.each { |f| require f }
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.retry_execution(a_class, message)
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(a_class) { "Retrying #{message}. ERROR: #{ex.message}" }
39
- sleep RETRY_TIMEOUT
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.new k }
32
+ @hash.keys.map { |k| Key[k] }
28
33
  end
29
34
 
30
35
  def synchronize(key, &block)
31
- @keys_mutex[key].synchronize &block
36
+ @keys_mutex[key].synchronize(&block)
32
37
  end
33
38
 
34
39
  def connection_args
@@ -3,6 +3,10 @@ module Asynchronic
3
3
  class Key < String
4
4
 
5
5
  SEPARATOR = '|'
6
+
7
+ def self.[](key)
8
+ new key
9
+ end
6
10
 
7
11
  def initialize(key)
8
12
  super key.to_s
@@ -8,8 +8,8 @@ module Asynchronic
8
8
  include Helper
9
9
 
10
10
  def initialize(scope, *args)
11
- @scope = Key.new scope
12
- @connection = ::Redis.new *args
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.new(k).remove_first }
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 *args
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.new scope
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.new(k).remove_first @scope.sections.count }
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
@@ -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.new id
21
- instance_eval &block if block_given?
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
@@ -1,3 +1,3 @@
1
1
  module Asynchronic
2
- VERSION = '1.4.0'
2
+ VERSION = '1.5.0'
3
3
  end
@@ -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
@@ -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.new 'foo'
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.new 'foo'
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.new 'foo'
19
- key_2 = Key.new key_1['bar']
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.new 'foo'
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.new :foo
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.new 'foo'
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.new(:foo)[:bar][:buz]
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.new(:foo).wont_be :nested?
45
- Key.new(:foo)[:bar].must_be :nested?
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.new(:foo)[:bar][:buz]
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.new(:foo)[:bar][:buz]
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
@@ -60,4 +60,8 @@ describe Asynchronic, 'Facade' do
60
60
  end
61
61
  end
62
62
 
63
+ it 'Garbage collector' do
64
+ Asynchronic.garbage_collector.must_be_instance_of Asynchronic::GarbageCollector
65
+ end
66
+
63
67
  end
@@ -493,73 +493,165 @@ module LifeCycleExamples
493
493
 
494
494
  execute queue
495
495
 
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
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 => :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
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 => :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
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 => :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
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 => :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
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 => :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
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 => :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
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.0
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-20 00:00:00.000000000 Z
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