asynchronic 2.0.1 → 3.0.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: 1e125dac6480974894d48275d0015bb85410a9f4
4
- data.tar.gz: 07b4801fd659a5c0735ccac5dc24c5340363afa8
3
+ metadata.gz: fe064d93526974fae713afcd2d5fc4730cb65b94
4
+ data.tar.gz: f6ca2831a8d78323370116397d1cbb9d48c66837
5
5
  SHA512:
6
- metadata.gz: d68006d635184823ac8bcdc4669690b4778b295b4eb98c5b8b4375c0284be30db220ee87bf3f6f7fc932365adb26a3196116b6549ef3432fa2391ec1395f7363
7
- data.tar.gz: 630f880110f71041ab2bc18f5ad5258298b8f3d18560315569aa18ed8459986af20c3768cc3dc77992c82db3d2dce496125ad4931902cddd6ad11d4aaa8fe09e
6
+ metadata.gz: a6668033166027a2d54aca7b094f8f90642f4b180f01299e99099a62b47f3dffd871799773248c3ad0bb3a4127885029234cda953265782926b685a5596743b3
7
+ data.tar.gz: 86da5ba9d7207fae1d6f01f77f433f8ed7e3b6d6e64e3bec177755088ee0c844f5c8a768f942c905ce730d9ea1d6dfcf5caee4db1a83b20bbf4a7727a721ed04
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ['lib']
20
20
 
21
21
  spec.add_dependency 'ost', '~> 1.0'
22
+ spec.add_dependency 'broadcaster', '~> 1.0'
22
23
  spec.add_dependency 'class_config', '~> 0.0'
23
24
  spec.add_dependency 'transparent_proxy', '~> 0.0'
24
25
  spec.add_dependency 'multi_require', '~> 1.0'
@@ -27,6 +28,7 @@ Gem::Specification.new do |spec|
27
28
  spec.add_development_dependency 'rake', '~> 11.0'
28
29
  spec.add_development_dependency 'minitest', '~> 5.0', '< 5.11'
29
30
  spec.add_development_dependency 'minitest-great_expectations', '~> 0.0'
31
+ spec.add_development_dependency 'minitest-stub_any_instance', '~> 1.0'
30
32
  spec.add_development_dependency 'minitest-colorin', '~> 0.1'
31
33
  spec.add_development_dependency 'minitest-line', '~> 0.6'
32
34
  spec.add_development_dependency 'simplecov', '~> 0.12'
@@ -2,6 +2,7 @@ require 'forwardable'
2
2
  require 'securerandom'
3
3
  require 'ost'
4
4
  require 'redic'
5
+ require 'broadcaster'
5
6
  require 'class_config'
6
7
  require 'transparent_proxy'
7
8
  require 'logger'
@@ -18,6 +19,7 @@ module Asynchronic
18
19
  attr_config :default_queue, :asynchronic
19
20
  attr_config :queue_engine, QueueEngine::InMemory.new
20
21
  attr_config :data_store, DataStore::InMemory.new
22
+ attr_config :notifier, Notifier::InMemory.new
21
23
  attr_config :logger, Logger.new($stdout)
22
24
  attr_config :retry_timeout, 30
23
25
  attr_config :garbage_collector_timeout, 30
@@ -26,7 +28,7 @@ module Asynchronic
26
28
  attr_config :connection_name, "HOST=#{Socket.gethostname},PID=#{::Process.pid}"
27
29
 
28
30
  def self.environment
29
- Environment.new queue_engine, data_store
31
+ Environment.new queue_engine, data_store, notifier
30
32
  end
31
33
 
32
34
  def self.[](pid)
@@ -1,12 +1,12 @@
1
1
  module Asynchronic
2
2
  class Environment
3
3
 
4
- attr_reader :queue_engine
5
- attr_reader :data_store
4
+ attr_reader :queue_engine, :data_store, :notifier
6
5
 
7
- def initialize(queue_engine, data_store)
6
+ def initialize(queue_engine, data_store, notifier)
8
7
  @queue_engine = queue_engine
9
8
  @data_store = data_store
9
+ @notifier = notifier
10
10
  end
11
11
 
12
12
  def queue(name)
@@ -18,6 +18,8 @@ module Asynchronic
18
18
  while @running
19
19
  processes = environment.processes
20
20
 
21
+ processes.each(&:abort_if_dead)
22
+
21
23
  conditions.each do |name, condition|
22
24
  Asynchronic.logger.info('Asynchronic') { "Running GC - #{name}" }
23
25
  begin
@@ -0,0 +1,30 @@
1
+ module Asynchronic
2
+ module Notifier
3
+ class Broadcaster
4
+
5
+ def initialize(options={})
6
+ options[:logger] ||= Asynchronic.logger
7
+ @broadcaster = ::Broadcaster.new options
8
+ end
9
+
10
+ def publish(pid, event, data=nil)
11
+ @broadcaster.publish DataStore::Key[pid][event], data
12
+ end
13
+
14
+ def subscribe(pid, event, &block)
15
+ @broadcaster.subscribe DataStore::Key[pid][event] do |data|
16
+ block.call data
17
+ end
18
+ end
19
+
20
+ def unsubscribe(subscription_id)
21
+ @broadcaster.unsubscribe subscription_id
22
+ end
23
+
24
+ def unsubscribe_all
25
+ @broadcaster.unsubscribe_all
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ module Asynchronic
2
+ module Notifier
3
+ class InMemory
4
+
5
+ def publish(pid, event, data=nil)
6
+ subscriptions[DataStore::Key[pid][event]].each_value do |block|
7
+ block.call data
8
+ end
9
+ end
10
+
11
+ def subscribe(pid, event, &block)
12
+ SecureRandom.uuid.tap do |subscription_id|
13
+ subscriptions[DataStore::Key[pid][event]][subscription_id] = block
14
+ end
15
+ end
16
+
17
+ def unsubscribe(subscription_id)
18
+ subscriptions.each_value { |s| s.delete subscription_id }
19
+ end
20
+
21
+ def unsubscribe_all
22
+ subscriptions.clear
23
+ end
24
+
25
+ private
26
+
27
+ def subscriptions
28
+ @subscriptions ||= Hash.new { |h,k| h[k] = {} }
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -14,6 +14,7 @@ module Asynchronic
14
14
  ATTRIBUTE_NAMES = [:type, :name, :queue, :status, :dependencies, :data, :result, :error, :connection_name] | TIME_TRACKING_MAP.values.uniq
15
15
 
16
16
  CANCELED_ERROR_MESSAGE = 'Canceled'
17
+ DEAD_ERROR_MESSAGE = 'Process connection broken'
17
18
 
18
19
  attr_reader :id
19
20
 
@@ -51,6 +52,10 @@ module Asynchronic
51
52
  (running? && !connected?) || processes.any?(&:dead?)
52
53
  end
53
54
 
55
+ def abort_if_dead
56
+ abort! DEAD_ERROR_MESSAGE if dead?
57
+ end
58
+
54
59
  def destroy
55
60
  data_store.delete_cascade
56
61
  end
@@ -190,8 +195,12 @@ module Asynchronic
190
195
 
191
196
  def status=(status)
192
197
  Asynchronic.logger.info('Asynchronic') { "#{status.to_s.capitalize} #{type} (#{id})" }
198
+
193
199
  data_store[:status] = status
194
200
  data_store[TIME_TRACKING_MAP[status]] = Time.now if TIME_TRACKING_MAP.key? status
201
+
202
+ environment.notifier.publish id, :status_changed, status
203
+ environment.notifier.publish id, :finalized if finalized?
195
204
  end
196
205
 
197
206
  STATUSES.each do |status|
@@ -1,3 +1,3 @@
1
1
  module Asynchronic
2
- VERSION = '2.0.1'
2
+ VERSION = '3.0.0'
3
3
  end
@@ -26,7 +26,6 @@ module LazyValueExamples
26
26
  it 'Transparent proxy' do
27
27
  value = lazy_value :key
28
28
  data_store[:key] = 1
29
- value.must_be_instance_of Fixnum
30
29
  value.must_equal 1
31
30
  end
32
31
 
@@ -326,7 +326,7 @@ class NestedJobWithErrorInChildJob < Asynchronic::Job
326
326
  end
327
327
 
328
328
 
329
- class AbortQueuedAfertErrorJob < Asynchronic::Job
329
+ class AbortQueuedAfterErrorJob < Asynchronic::Job
330
330
  def call
331
331
  async Child_1
332
332
  async Child_2
@@ -3,6 +3,7 @@ require 'asynchronic'
3
3
  require 'minitest/autorun'
4
4
  require 'minitest/colorin'
5
5
  require 'minitest/great_expectations'
6
+ require 'minitest/stub_any_instance'
6
7
  require 'jobs'
7
8
  require 'expectations'
8
9
  require 'timeout'
@@ -1,12 +1,13 @@
1
1
  module LifeCycleExamples
2
2
 
3
- let(:env) { Asynchronic::Environment.new queue_engine, data_store }
3
+ let(:env) { Asynchronic::Environment.new queue_engine, data_store, notifier }
4
4
 
5
5
  let(:queue) { env.default_queue }
6
6
 
7
7
  after do
8
8
  data_store.clear
9
9
  queue_engine.clear
10
+ notifier.unsubscribe_all
10
11
  end
11
12
 
12
13
  def create(type, params={})
@@ -17,10 +18,41 @@ module LifeCycleExamples
17
18
 
18
19
  def execute(queue)
19
20
  process = env.load_process(queue.pop)
21
+
22
+ events = []
23
+ status_changed_id = notifier.subscribe(process.id, :status_changed) { |status| events << status }
24
+
25
+ is_finalized = false
26
+ finalized_id = notifier.subscribe(process.id, :finalized) { is_finalized = true }
27
+
20
28
  process.execute
29
+
21
30
  process.must_have_connection_name
22
31
  process.wont_be :dead?
23
32
  process.send(:connected?).must_be_true
33
+
34
+ with_retries do
35
+ events.last.must_equal process.status
36
+ process.finalized?.must_equal is_finalized
37
+ end
38
+
39
+ notifier.unsubscribe status_changed_id
40
+ notifier.unsubscribe finalized_id
41
+
42
+ status = process.status
43
+ process.abort_if_dead
44
+ process.status.must_equal status
45
+ end
46
+
47
+ def with_retries(&block)
48
+ Timeout.timeout(3) do
49
+ begin
50
+ block.call
51
+ rescue Minitest::Assertion
52
+ sleep 0.001
53
+ retry
54
+ end
55
+ end
24
56
  end
25
57
 
26
58
  it 'Basic' do
@@ -481,78 +513,78 @@ module LifeCycleExamples
481
513
  process.real_error.must_equal "Error in parent"
482
514
  end
483
515
 
484
- it 'Abort queued afert error' do
485
- process = create AbortQueuedAfertErrorJob
516
+ it 'Abort queued After error' do
517
+ process = create AbortQueuedAfterErrorJob
486
518
 
487
519
  process.enqueue
488
520
 
489
521
  execute queue
490
522
 
491
- process.full_status.must_equal 'AbortQueuedAfertErrorJob' => :waiting,
492
- 'AbortQueuedAfertErrorJob::Child_1' => :queued,
493
- 'AbortQueuedAfertErrorJob::Child_2' => :queued,
494
- 'AbortQueuedAfertErrorJob::Child_3' => :queued,
495
- 'AbortQueuedAfertErrorJob::Child_4' => :queued
523
+ process.full_status.must_equal 'AbortQueuedAfterErrorJob' => :waiting,
524
+ 'AbortQueuedAfterErrorJob::Child_1' => :queued,
525
+ 'AbortQueuedAfterErrorJob::Child_2' => :queued,
526
+ 'AbortQueuedAfterErrorJob::Child_3' => :queued,
527
+ 'AbortQueuedAfterErrorJob::Child_4' => :queued
496
528
 
497
529
  execute queue
498
530
 
499
- process.full_status.must_equal 'AbortQueuedAfertErrorJob' => :waiting,
500
- 'AbortQueuedAfertErrorJob::Child_1' => :waiting,
531
+ process.full_status.must_equal 'AbortQueuedAfterErrorJob' => :waiting,
532
+ 'AbortQueuedAfterErrorJob::Child_1' => :waiting,
501
533
  'Child_1_1' => :queued,
502
534
  'Child_1_2' => :queued,
503
- 'AbortQueuedAfertErrorJob::Child_2' => :queued,
504
- 'AbortQueuedAfertErrorJob::Child_3' => :queued,
505
- 'AbortQueuedAfertErrorJob::Child_4' => :queued
535
+ 'AbortQueuedAfterErrorJob::Child_2' => :queued,
536
+ 'AbortQueuedAfterErrorJob::Child_3' => :queued,
537
+ 'AbortQueuedAfterErrorJob::Child_4' => :queued
506
538
 
507
539
  execute queue
508
540
 
509
- process.full_status.must_equal 'AbortQueuedAfertErrorJob' => :waiting,
510
- 'AbortQueuedAfertErrorJob::Child_1' => :waiting,
541
+ process.full_status.must_equal 'AbortQueuedAfterErrorJob' => :waiting,
542
+ 'AbortQueuedAfterErrorJob::Child_1' => :waiting,
511
543
  'Child_1_1' => :queued,
512
544
  'Child_1_2' => :queued,
513
- 'AbortQueuedAfertErrorJob::Child_2' => :completed,
514
- 'AbortQueuedAfertErrorJob::Child_3' => :queued,
515
- 'AbortQueuedAfertErrorJob::Child_4' => :queued
545
+ 'AbortQueuedAfterErrorJob::Child_2' => :completed,
546
+ 'AbortQueuedAfterErrorJob::Child_3' => :queued,
547
+ 'AbortQueuedAfterErrorJob::Child_4' => :queued
516
548
 
517
549
  execute queue
518
550
 
519
- process.full_status.must_equal 'AbortQueuedAfertErrorJob' => :aborted,
520
- 'AbortQueuedAfertErrorJob::Child_1' => :waiting,
551
+ process.full_status.must_equal 'AbortQueuedAfterErrorJob' => :aborted,
552
+ 'AbortQueuedAfterErrorJob::Child_1' => :waiting,
521
553
  'Child_1_1' => :queued,
522
554
  'Child_1_2' => :queued,
523
- 'AbortQueuedAfertErrorJob::Child_2' => :completed,
524
- 'AbortQueuedAfertErrorJob::Child_3' => :aborted,
525
- 'AbortQueuedAfertErrorJob::Child_4' => :queued
555
+ 'AbortQueuedAfterErrorJob::Child_2' => :completed,
556
+ 'AbortQueuedAfterErrorJob::Child_3' => :aborted,
557
+ 'AbortQueuedAfterErrorJob::Child_4' => :queued
526
558
 
527
559
  execute queue
528
560
 
529
- process.full_status.must_equal 'AbortQueuedAfertErrorJob' => :aborted,
530
- 'AbortQueuedAfertErrorJob::Child_1' => :waiting,
561
+ process.full_status.must_equal 'AbortQueuedAfterErrorJob' => :aborted,
562
+ 'AbortQueuedAfterErrorJob::Child_1' => :waiting,
531
563
  'Child_1_1' => :queued,
532
564
  'Child_1_2' => :queued,
533
- 'AbortQueuedAfertErrorJob::Child_2' => :completed,
534
- 'AbortQueuedAfertErrorJob::Child_3' => :aborted,
535
- 'AbortQueuedAfertErrorJob::Child_4' => :aborted
565
+ 'AbortQueuedAfterErrorJob::Child_2' => :completed,
566
+ 'AbortQueuedAfterErrorJob::Child_3' => :aborted,
567
+ 'AbortQueuedAfterErrorJob::Child_4' => :aborted
536
568
 
537
569
  execute queue
538
570
 
539
- process.full_status.must_equal 'AbortQueuedAfertErrorJob' => :aborted,
540
- 'AbortQueuedAfertErrorJob::Child_1' => :aborted,
571
+ process.full_status.must_equal 'AbortQueuedAfterErrorJob' => :aborted,
572
+ 'AbortQueuedAfterErrorJob::Child_1' => :aborted,
541
573
  'Child_1_1' => :aborted,
542
574
  'Child_1_2' => :queued,
543
- 'AbortQueuedAfertErrorJob::Child_2' => :completed,
544
- 'AbortQueuedAfertErrorJob::Child_3' => :aborted,
545
- 'AbortQueuedAfertErrorJob::Child_4' => :aborted
575
+ 'AbortQueuedAfterErrorJob::Child_2' => :completed,
576
+ 'AbortQueuedAfterErrorJob::Child_3' => :aborted,
577
+ 'AbortQueuedAfterErrorJob::Child_4' => :aborted
546
578
 
547
579
  execute queue
548
580
 
549
- process.full_status.must_equal 'AbortQueuedAfertErrorJob' => :aborted,
550
- 'AbortQueuedAfertErrorJob::Child_1' => :aborted,
581
+ process.full_status.must_equal 'AbortQueuedAfterErrorJob' => :aborted,
582
+ 'AbortQueuedAfterErrorJob::Child_1' => :aborted,
551
583
  'Child_1_1' => :aborted,
552
584
  'Child_1_2' => :aborted,
553
- 'AbortQueuedAfertErrorJob::Child_2' => :completed,
554
- 'AbortQueuedAfertErrorJob::Child_3' => :aborted,
555
- 'AbortQueuedAfertErrorJob::Child_4' => :aborted
585
+ 'AbortQueuedAfterErrorJob::Child_2' => :completed,
586
+ 'AbortQueuedAfterErrorJob::Child_3' => :aborted,
587
+ 'AbortQueuedAfterErrorJob::Child_4' => :aborted
556
588
 
557
589
  process.real_error.must_equal 'Forced error'
558
590
  end
@@ -617,36 +649,44 @@ module LifeCycleExamples
617
649
  process_2.enqueue
618
650
  execute queue
619
651
 
652
+ process_3 = create BasicJob
653
+
620
654
  pid_1 = process_1.id
621
655
  pid_2 = process_2.id
656
+ pid_3 = process_3.id
622
657
 
623
658
  process_1.must_be_completed
624
659
  process_2.must_be_waiting
660
+ process_3.must_be_pending
625
661
 
626
662
  data_store.keys.select { |k| k.start_with? pid_1 }.count.must_equal 53
627
663
  data_store.keys.select { |k| k.start_with? pid_2 }.count.must_equal 38
664
+ data_store.keys.select { |k| k.start_with? pid_3 }.count.must_equal 7
628
665
 
629
666
  gc = Asynchronic::GarbageCollector.new env, 0.001
630
667
 
631
- gc.add_condition('Completed', &:completed?)
668
+ gc.add_condition('Finalized', &:finalized?)
632
669
  gc.add_condition('Waiting', &:waiting?)
633
670
  gc.add_condition('Exception') { raise 'Invalid condition' }
634
671
 
635
- gc.conditions_names.must_equal ['Completed', 'Waiting', 'Exception']
672
+ gc.conditions_names.must_equal ['Finalized', 'Waiting', 'Exception']
636
673
 
637
674
  gc.remove_condition 'Waiting'
638
675
 
639
- gc.conditions_names.must_equal ['Completed', 'Exception']
676
+ gc.conditions_names.must_equal ['Finalized', 'Exception']
640
677
 
641
678
  Thread.new do
642
679
  sleep 0.01
643
680
  gc.stop
644
681
  end
645
682
 
646
- gc.start
683
+ Asynchronic::Process.stub_any_instance(:dead?, -> { id == pid_3 }) do
684
+ gc.start
685
+ end
647
686
 
648
687
  data_store.keys.select { |k| k.start_with? pid_1 }.count.must_equal 0
649
688
  data_store.keys.select { |k| k.start_with? pid_2 }.count.must_equal 38
689
+ data_store.keys.select { |k| k.start_with? pid_3 }.count.must_equal 0
650
690
  end
651
691
 
652
692
  it 'Before finalize hook when completed' do
@@ -5,6 +5,7 @@ describe Asynchronic::Process, 'Life cycle - InMemory' do
5
5
 
6
6
  let(:queue_engine) { Asynchronic::QueueEngine::InMemory.new }
7
7
  let(:data_store) { Asynchronic::DataStore::InMemory.new }
8
+ let(:notifier) { Asynchronic::Notifier::InMemory.new }
8
9
 
9
10
  include LifeCycleExamples
10
11
 
@@ -5,6 +5,7 @@ describe Asynchronic::Process, 'Life cycle - Redis' do
5
5
 
6
6
  let(:queue_engine) { Asynchronic::QueueEngine::Ost.new }
7
7
  let(:data_store) { Asynchronic::DataStore::Redis.new :asynchronic_test }
8
+ let(:notifier) { Asynchronic::Notifier::Broadcaster.new }
8
9
 
9
10
  include LifeCycleExamples
10
11
 
@@ -5,6 +5,7 @@ describe Asynchronic::Worker, 'InMemory' do
5
5
 
6
6
  let(:queue_engine) { Asynchronic::QueueEngine::InMemory.new }
7
7
  let(:data_store) { Asynchronic::DataStore::InMemory.new }
8
+ let(:notifier) { Asynchronic::Notifier::InMemory.new }
8
9
 
9
10
  include WorkerExamples
10
11
 
@@ -5,6 +5,7 @@ describe Asynchronic::Worker, 'Redis' do
5
5
 
6
6
  let(:queue_engine) { Asynchronic::QueueEngine::Ost.new }
7
7
  let(:data_store) { Asynchronic::DataStore::Redis.new :asynchronic_test}
8
+ let(:notifier) { Asynchronic::Notifier::Broadcaster.new }
8
9
 
9
10
  after do
10
11
  data_store.clear
@@ -1,6 +1,6 @@
1
1
  module WorkerExamples
2
2
 
3
- let(:env) { Asynchronic::Environment.new queue_engine, data_store }
3
+ let(:env) { Asynchronic::Environment.new queue_engine, data_store, notifier }
4
4
  let(:queue_name) { :test_worker }
5
5
  let(:queue) { env.queue queue_name }
6
6
 
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: 2.0.1
4
+ version: 3.0.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: 2019-06-20 00:00:00.000000000 Z
11
+ date: 2019-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ost
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: broadcaster
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: class_config
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -128,6 +142,20 @@ dependencies:
128
142
  - - "~>"
129
143
  - !ruby/object:Gem::Version
130
144
  version: '0.0'
145
+ - !ruby/object:Gem::Dependency
146
+ name: minitest-stub_any_instance
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '1.0'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - "~>"
157
+ - !ruby/object:Gem::Version
158
+ version: '1.0'
131
159
  - !ruby/object:Gem::Dependency
132
160
  name: minitest-colorin
133
161
  requirement: !ruby/object:Gem::Requirement
@@ -229,6 +257,8 @@ files:
229
257
  - lib/asynchronic/error.rb
230
258
  - lib/asynchronic/garbage_collector.rb
231
259
  - lib/asynchronic/job.rb
260
+ - lib/asynchronic/notifier/broadcaster.rb
261
+ - lib/asynchronic/notifier/in_memory.rb
232
262
  - lib/asynchronic/process.rb
233
263
  - lib/asynchronic/queue_engine/in_memory.rb
234
264
  - lib/asynchronic/queue_engine/ost.rb