active_projection 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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