active_projection 0.1.0 → 0.2.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: d9052c28e84c5b64ab1b4350b291e02077f824ec
4
- data.tar.gz: a7ad85d0ff185230ba7d350efa4a123143e60499
3
+ metadata.gz: a021d20d944d3f69ff88671afb2b3dd63ad306b0
4
+ data.tar.gz: 648e52cba7a201f5bc37036c28ffedc742fa26bc
5
5
  SHA512:
6
- metadata.gz: b617e60a34666ba1fb02b110113c6d94a7b72c7f91d1c2a64d4272e44e7eec28894c4a4234491638b4babccae0cf1600a22089ce8630f7c9d3e33471c2662467
7
- data.tar.gz: 1abea3c7eb6b8921ecbf7a4c3896642dd0ac55301439dd09b5013a51c4a12f9c8713b912f36004ac15d6aad45dff4751b48f4c4dec7eb4d6f39be76d747fd867
6
+ metadata.gz: 16138af067df4265c38f11c20e6d7594893181c2e854079c52babeda32f0f3d3e70f3b3770e6eb281c713e13c80dba5dc1092657bf41279956dd4bcf369a3406
7
+ data.tar.gz: 9d6b556fb2014e0a26ecd8232fa710041c35a91362ba77bbc089c1cb3f8867e2d4194111b6b9f6dc598fec924f2464095577080fa46860f392d1261edb559199
@@ -1,8 +1,8 @@
1
1
  module ActiveProjection
2
2
  class ProjectionRepository
3
3
 
4
- def self.all
5
- Projection.all
4
+ def self.last_ids
5
+ Projection.all.to_a.map { |p| p.last_id }
6
6
  end
7
7
 
8
8
  def self.get_last_id(id)
@@ -1,20 +1,42 @@
1
1
  module ActiveProjection
2
2
  module Autoload
3
+ include ActiveEvent::Support::Autoload
4
+ private
5
+ def self.dir_names
6
+ %W(app/models)
7
+ end
8
+
9
+ def self.reload
10
+ ActiveEvent::Support::Autoloader.reload_from pdirs
11
+ super
12
+ end
13
+
3
14
  def self.worker_config=(config)
4
- dirs = []
5
- projections_dir = "#{config[:path]}**/*.rb"
15
+ set_pdirs config
16
+ ActiveEvent::Support::Autoloader.load_from pdirs
17
+ end
18
+
19
+ def self.watchable_dirs
20
+ watchable_dirs = super
21
+ watchable_dirs['app/projections'] = [:rb]
22
+ watchable_dirs
23
+ end
24
+
25
+ private
26
+ def self.set_pdirs(config)
27
+ @pdirs = []
28
+ projections_dir = "#{config[:path]}/app/projections/**/*.rb"
6
29
  if config[:count] == 1
7
- dirs << projections_dir
30
+ @pdirs << projections_dir
8
31
  else
9
32
  Dir[*projections_dir].each_with_index.map { |item, i| i % config[:count] == config[:number] ? item : nil }.compact.each do |dir|
10
- dirs << dir
33
+ @pdirs << dir
11
34
  end
12
35
  end
13
- ActiveEvent::Support::Autoloader.load_from dirs
14
36
  end
15
37
 
16
- def self.app_path=(path)
17
- ActiveEvent::Support::Autoloader.load_from "#{path}/models/**/*.rb"
38
+ def self.pdirs
39
+ @pdirs ||= []
18
40
  end
19
41
  end
20
42
  end
@@ -5,28 +5,71 @@ module ActiveProjection
5
5
  include Singleton
6
6
 
7
7
  def self.start(options)
8
- instance.start options
8
+ instance.options = options
9
+ instance.start
9
10
  end
10
11
 
11
- def start(options)
12
- self.options = options
12
+ def start
13
13
  event_connection.start
14
- begin
15
- event_channel.queue('', auto_delete: true).bind(event_exchange).subscribe do |delivery_info, properties, body|
16
- puts "Received #{properties.type} with #{body}"
17
- ProjectionTypeRegistry.process(properties.headers.deep_symbolize_keys, Object.const_get(properties.type).new((JSON.parse body).deep_symbolize_keys))
18
- end
19
- rescue Interrupt => _
20
- event_channel.close
21
- event_connection.close
22
- end
23
- last_ids = ProjectionRepository.all.to_a.map { |p| p.last_id }
24
- request_events_after last_ids.min || 0
14
+ listen_for_events
15
+ request_missing_events
25
16
  event_channel.work_pool.join
26
17
  end
27
18
 
28
- def request_events_after(id)
29
- resend_exchange.publish id.to_s, routing_key: 'resend'
19
+ def listen_for_events
20
+ subscribe_to event_queue do |delivery_info, properties, body|
21
+ event_received properties, body
22
+ end
23
+ end
24
+
25
+ def request_missing_events
26
+ listen_for_replayed_events
27
+ send_request_for min_last_id
28
+ end
29
+
30
+ def listen_for_replayed_events
31
+ subscribe_to replay_queue do |delivery_info, properties, body|
32
+ event_received properties, body unless replay_done? body
33
+ end
34
+ end
35
+
36
+ def send_request_for(id)
37
+ resend_request_exchange.publish id.to_s, routing_key: 'resend_request'
38
+ end
39
+
40
+ def replay_done?(body)
41
+ if 'replay_done' == body
42
+ puts 'Projections should be up to date now'
43
+ replay_queue.unbind(resend_exchange)
44
+ return true
45
+ end
46
+ false
47
+ end
48
+
49
+ def event_received(properties, body)
50
+ RELOADER.execute_if_updated
51
+ puts "Received #{properties.type} with #{body}"
52
+ ProjectionTypeRegistry.process properties.headers.deep_symbolize_keys, build_event(properties.type, JSON.parse(body))
53
+ end
54
+
55
+ def build_event(type, data)
56
+ Object.const_get(type).new(data.deep_symbolize_keys)
57
+ end
58
+
59
+ def replay_queue
60
+ @replay_queue ||= event_channel.queue('', auto_delete: true).bind(resend_exchange)
61
+ end
62
+
63
+ def event_queue
64
+ @event_queue ||= event_channel.queue('', auto_delete: true).bind(event_exchange)
65
+ end
66
+
67
+ def min_last_id
68
+ ProjectionRepository.last_ids.min || 0
69
+ end
70
+
71
+ def subscribe_to(queue, &block)
72
+ queue.subscribe(&block)
30
73
  end
31
74
 
32
75
  def event_connection
@@ -42,14 +85,17 @@ module ActiveProjection
42
85
  end
43
86
 
44
87
  def resend_exchange
45
- @resend_exchange ||= event_channel.direct "resend_#{options[:event_exchange]}"
88
+ @resend_exchange ||= event_channel.fanout "resend_#{options[:event_exchange]}"
89
+ end
90
+
91
+ def resend_request_exchange
92
+ @resend_request_exchange ||= event_channel.direct "resend_request_#{options[:event_exchange]}"
46
93
  end
47
94
 
48
95
  def options
49
96
  @options
50
97
  end
51
98
 
52
- private
53
99
  attr_writer :options
54
100
  end
55
101
  end
@@ -20,7 +20,7 @@ module ActiveProjection
20
20
  end
21
21
 
22
22
  def evaluate(headers)
23
- return false unless ProjectionRepository.solid? projection_id #projection is broken and shouldn't process any incoming event
23
+ return false unless ProjectionRepository.solid? projection_id || headers[:replayed]# process only replayed events if projection is broken
24
24
  last_id = ProjectionRepository.get_last_id projection_id
25
25
  case
26
26
  when last_id + 1 == headers[:store_id] #process incoming event
@@ -1,7 +1,7 @@
1
1
  module ActiveProjection
2
2
  # Returns the version of the currently loaded ActiveProjection as a Gem::Version
3
3
  def self.version
4
- Gem::Version.new '0.1.0'
4
+ Gem::Version.new '0.2.0'
5
5
  end
6
6
 
7
7
  module VERSION #:nodoc:
@@ -4,7 +4,7 @@ require_relative '../support/active_record'
4
4
  describe ActiveProjection::ProjectionRepository do
5
5
  before :all do
6
6
  5.times do |i|
7
- FactoryGirl.create :projection, id: i, class_name: "TestProjection#{i}"
7
+ FactoryGirl.create :projection, id: i, class_name: "TestProjection#{i}", last_id: 5 - i
8
8
  end
9
9
  end
10
10
  describe 'create_or_get' do
@@ -24,4 +24,7 @@ describe ActiveProjection::ProjectionRepository do
24
24
  expect(ActiveProjection::Projection.where(id:0).first.solid).to be_false
25
25
  end
26
26
  end
27
+ it 'returns array of last ids' do
28
+ expect(ActiveProjection::ProjectionRepository.last_ids).to eq [5,4,3,2,1]
29
+ end
27
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_projection
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Reischuck
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-09-11 00:00:00.000000000 Z
11
+ date: 2013-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active_event
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.1.0
19
+ version: 0.2.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.1.0
26
+ version: 0.2.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activerecord
29
29
  requirement: !ruby/object:Gem::Requirement