active_event 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: 5a686659ed279d8bc3e3547139ea2b01c637b8d4
4
- data.tar.gz: c61ec7d584bf564fb12bb5250af1298dfd40efc6
3
+ metadata.gz: f2879ba83c33e9ab5c2a5db8263e01e1cc00f983
4
+ data.tar.gz: d160e8c142951bc87a2a816406ab30bbf6a08b8b
5
5
  SHA512:
6
- metadata.gz: 624483b1eb07a2a56fa84baa1306d1d5a3e591b055afd059efae69f1fcf6df930754dd419cbc74c84ad1fc4efbd8e3968b05bd0d1c0ca58873e8970b79993ec8
7
- data.tar.gz: 0035b8d841c4862928e9022c0ec448fa25cd380aa1b37bd25e19131dee5cea4e83f554e64ddae866c4b64cddefb950d507738a5eff5ae80490abf727a824405c
6
+ metadata.gz: a4f62dfaedef9fe9c2838b9f4035f093a3ac68df9319e6e3e2e9d7b6fbd6f5d6c3db5c83dbbe234e906e338b4e2f4fd56cfc39e7adbc6551b0da0410b972cc1e
7
+ data.tar.gz: 21a407982c30b6bf8140fbb682a47201c45568e5d3ce80a8f052b5106bcb0200ba1f160e7ce032910f488b4beaa9dda2bcedfd3f4ba194b620ac934fc6862709
@@ -1,11 +1,9 @@
1
1
  module ActiveEvent
2
2
  module Autoload
3
- def self.app_path=(path)
4
- dirs = []
5
- dirs << "#{path}/commands/**/*.rb"
6
- dirs << "#{path}/validations/**/*.rb"
7
- dirs << "#{path}/events/**/*.rb"
8
- ActiveEvent::Support::Autoloader.load_from dirs
3
+ include ActiveEvent::Support::Autoload
4
+ private
5
+ def self.dir_names
6
+ %W(app/commands app/validations app/events)
9
7
  end
10
8
  end
11
9
  end
@@ -20,9 +20,13 @@ module ActiveEvent
20
20
  include ActiveModel::Validations
21
21
 
22
22
  def is_valid_do(&block)
23
- valid = valid?
24
- block.call() if valid
25
- valid
23
+ if valid?
24
+ block.call
25
+ else
26
+ false
27
+ end
28
+ rescue
29
+ false
26
30
  end
27
31
  end
28
32
  end
@@ -34,7 +34,7 @@ module ActiveEvent
34
34
  base.server_uri = 'druby://127.0.0.1:8787'
35
35
  end
36
36
 
37
- def set_config(protocol: 'druby', host: 'localhost', port: 8787)
37
+ def set_config(protocol = 'druby', host = 'localhost', port = 8787)
38
38
  self.server_uri = "#{protocol}://#{host}:#{port}"
39
39
  end
40
40
  end
@@ -12,31 +12,37 @@ module ActiveEvent
12
12
  end
13
13
 
14
14
  def self.start(options)
15
- instance.start options
15
+ instance.options = options
16
+ instance.start
16
17
  end
17
18
 
18
- def start(options)
19
- self.options = options
19
+ def start
20
20
  event_connection.start
21
21
  listen_for_resend_requests
22
22
  end
23
23
 
24
- def self.resend_events_after(id)
25
- events = EventRepository.after_id(id).to_a
26
- events.each do |e|
27
- event = EventType.create_instance(e.event, e.data.deep_symbolize_keys)
28
- event.add_store_infos store_id: e.id
29
- self.publish event
24
+ def resend_events_after(id)
25
+ if @replay_server_thread.nil? || !@replay_server_thread.alive?
26
+ @replay_server_thread = Thread.new do
27
+ Thread.current.priority = -10
28
+ ReplayServer.start options, id
29
+ end
30
+ else
31
+ ReplayServer.update id
30
32
  end
31
33
  end
32
34
 
33
35
  def listen_for_resend_requests
34
- event_channel.queue('', auto_delete: true).bind(resend_exchange, routing_key: 'resend').subscribe do |delivery_info, properties, id|
35
- puts "received resend request with id #{id}"
36
- self.class.resend_events_after id
36
+ resend_request_queue.subscribe do |delivery_info, properties, id|
37
+ resend_request_received id
37
38
  end
38
39
  end
39
40
 
41
+ def resend_request_received (id)
42
+ puts "received resend request with id #{id}"
43
+ resend_events_after id.to_i
44
+ end
45
+
40
46
  def event_connection
41
47
  @event_server ||= Bunny.new URI::Generic.build(options[:event_connection]).to_s
42
48
  end
@@ -49,15 +55,18 @@ module ActiveEvent
49
55
  @event_exchange ||= event_channel.fanout options[:event_exchange]
50
56
  end
51
57
 
52
- def resend_exchange
53
- @resend_exchange ||= event_channel.direct "resend_#{options[:event_exchange]}"
58
+ def resend_request_exchange
59
+ @resend_request_exchange ||= event_channel.direct "resend_request_#{options[:event_exchange]}"
60
+ end
61
+
62
+ def resend_request_queue
63
+ @resend_request_queue ||= event_channel.queue('', auto_delete: true).bind(resend_request_exchange, routing_key: 'resend_request')
54
64
  end
55
65
 
56
66
  def options
57
67
  @options
58
68
  end
59
69
 
60
- private
61
70
  attr_writer :options
62
71
  end
63
72
  end
@@ -0,0 +1,56 @@
1
+ require 'reloader/sse'
2
+ require 'bunny'
3
+ module ActiveEvent
4
+ module EventSourceServer
5
+ def subscribe_to(queue, &block)
6
+ queue.subscribe(block: true, &block)
7
+ end
8
+
9
+ def event_queue
10
+ @event_queue ||= event_channel.queue('', auto_delete: true).bind(event_exchange)
11
+ end
12
+
13
+ def event_connection
14
+ @event_server ||= Bunny.new URI::Generic.build(options[:event_connection]).to_s
15
+ end
16
+
17
+ def event_channel
18
+ @event_channel ||= event_connection.create_channel
19
+ end
20
+
21
+ def event_exchange
22
+ @event_exchange ||= event_channel.fanout options[:event_exchange]
23
+ end
24
+
25
+ def default_options
26
+ {
27
+ event_connection: {
28
+ scheme: 'amqp',
29
+ userinfo: nil,
30
+ host: '127.0.0.1',
31
+ port: 9797,
32
+ },
33
+ event_exchange: 'events'
34
+ }
35
+ end
36
+
37
+ def parse_options(args)
38
+ options = default_options
39
+ options.merge! YAML.load_file(config_file)[env].deep_symbolize_keys! unless config_file.blank?
40
+ end
41
+
42
+ def config_file
43
+ File.expand_path('config/disco.yml', Rails.root)
44
+ end
45
+
46
+ def options
47
+ @options ||= parse_options(ARGV)
48
+ end
49
+
50
+ def env
51
+ @env = ENV['PROJECTION_ENV'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
52
+ end
53
+
54
+ attr_writer :options
55
+ end
56
+ end
@@ -0,0 +1,94 @@
1
+ require 'singleton'
2
+ require 'bunny'
3
+ require 'thread'
4
+ module ActiveEvent
5
+ class ReplayServer
6
+ include Singleton
7
+
8
+ def self.start(options, id)
9
+ instance.options = options
10
+ instance.start id
11
+ end
12
+
13
+ def self.update(id)
14
+ instance.queue << id
15
+ end
16
+
17
+ def start(id)
18
+ event_connection.start
19
+ @last_id = id
20
+ start_republishing
21
+ send_done_message
22
+ end
23
+
24
+ def queue
25
+ @queue ||= Queue.new
26
+ end
27
+
28
+ def send_done_message
29
+ resend_exchange.publish 'replay_done'
30
+ end
31
+
32
+ def start_republishing
33
+ loop do
34
+ @events = EventRepository.after_id(@last_id).to_a
35
+ return if @events.empty?
36
+ republish_events
37
+ end
38
+ end
39
+
40
+ def republish_events
41
+ while has_next_event?
42
+ return if new_id?
43
+ republish next_event
44
+ Thread.pass
45
+ end
46
+ end
47
+
48
+ def new_id?
49
+ unless queue.empty?
50
+ new_id = queue.pop
51
+ if new_id < @last_id
52
+ @last_id = new_id
53
+ return true
54
+ end
55
+ end
56
+ false
57
+ end
58
+
59
+ def republish(e)
60
+ type = e.event
61
+ body = e.data.to_json
62
+ resend_exchange.publish body, {type: type, headers: {store_id: e.id, replayed: true}}
63
+ puts "Republished #{type} with #{body}"
64
+ end
65
+
66
+ def next_event
67
+ e = @events.shift
68
+ @last_id = e.id
69
+ e
70
+ end
71
+
72
+ def has_next_event?
73
+ @events.length > 0
74
+ end
75
+
76
+ def event_connection
77
+ @event_server ||= Bunny.new URI::Generic.build(options[:event_connection]).to_s
78
+ end
79
+
80
+ def event_channel
81
+ @event_channel ||= event_connection.create_channel
82
+ end
83
+
84
+ def resend_exchange
85
+ @resend_exchange ||= event_channel.fanout "resend_#{options[:event_exchange]}"
86
+ end
87
+
88
+ def options
89
+ @options
90
+ end
91
+
92
+ attr_writer :options
93
+ end
94
+ end
@@ -21,7 +21,7 @@ module ActiveEvent::Support
21
21
  def attributes(*args)
22
22
  super
23
23
  args.each do |attr|
24
- define_method "#{attr}=", -> (value) { attributes[attr] = value }
24
+ define_method "#{attr}=", lambda { |value| attributes[attr] = value }
25
25
  end
26
26
  end
27
27
  end
@@ -0,0 +1,44 @@
1
+ module ActiveEvent::Support
2
+ module Autoload
3
+ extend ActiveSupport::Concern
4
+ module ClassMethods
5
+ def app_path=(path)
6
+ set_dirs path
7
+ Autoloader.load_from dirs
8
+ end
9
+
10
+ def reload_module(module_name)
11
+ path = [parent.name, module_name.to_s].join('::').underscore
12
+ Autoloader.reload module_name, path
13
+ end
14
+
15
+ def reload
16
+ Autoloader.reload_from dirs
17
+ end
18
+
19
+ def watchable_dirs
20
+ watchable_dirs = {}
21
+ dir_names.each do |dir_name|
22
+ watchable_dirs[dir_name] = [:rb]
23
+ end
24
+ watchable_dirs
25
+ end
26
+
27
+ private
28
+
29
+ def dir_names
30
+ []
31
+ end
32
+
33
+ def set_dirs(path)
34
+ @dirs = dir_names.map do |dir_name|
35
+ "#{path}/#{dir_name}/**/*.rb"
36
+ end
37
+ end
38
+
39
+ def dirs
40
+ @dirs ||= ''
41
+ end
42
+ end
43
+ end
44
+ end
@@ -5,5 +5,34 @@ module ActiveEvent::Support
5
5
  require file
6
6
  end
7
7
  end
8
+
9
+ def self.reload_from(dirs)
10
+ Dir[*dirs].each do |path|
11
+ reload get_module_name(path), path
12
+ end
13
+ end
14
+
15
+ def self.reload(name, path)
16
+ const_name, namespace_name = name.to_s.split('::').reverse
17
+ if namespace_name.nil?
18
+ Object.send(:remove_const, const_name) if Object.const_defined?(const_name)
19
+ else
20
+ namespace = const_get(namespace_name)
21
+ namespace.send(:remove_const, const_name) if namespace.const_defined?(const_name)
22
+ end
23
+ $".delete_if { |s| s.include?(path) }
24
+ require path
25
+ end
26
+
27
+ private
28
+ def self.get_module_name(path)
29
+ segments = path.split('/')
30
+ seg = if 1 == (segments.length - 2) - (segments.index('app') || segments.index('domain')) #no namespace
31
+ segments.last.split('.').first
32
+ else
33
+ [segments[-2], segments.last.split('.').first].join('/')
34
+ end
35
+ seg.camelcase.to_sym
36
+ end
8
37
  end
9
38
  end
@@ -1,7 +1,7 @@
1
1
  module ActiveEvent
2
2
  # Returns the version of the currently loaded ActiveEvent 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:
data/lib/active_event.rb CHANGED
@@ -10,6 +10,7 @@ module ActiveEvent
10
10
  autoload :Domain
11
11
  autoload :EventServer
12
12
  autoload :EventType
13
+ autoload :ReplayServer
13
14
  autoload :Validations
14
15
  autoload :ValidationsRegistry
15
16
 
@@ -18,6 +19,7 @@ module ActiveEvent
18
19
 
19
20
  autoload :AttrInitializer
20
21
  autoload :AttrSetter
22
+ autoload :Autoload
21
23
  autoload :Autoloader
22
24
  end
23
25
 
@@ -6,15 +6,17 @@ describe ActiveEvent::EventServer do
6
6
  @server = ActiveEvent::EventServer.instance
7
7
  @event = TestEvent.new
8
8
  end
9
- it 'resends requests' do
10
- allow(@event).to receive(:event)
11
- allow(@event).to receive(:id)
12
- allow(@event).to receive(:data).and_return({})
13
- expect(ActiveEvent::EventType).to receive(:create_instance).twice.and_return(Object)
14
- expect(Object).to receive(:add_store_infos).twice
15
- expect(ActiveEvent::EventRepository).to receive(:after_id).and_return([@event, @event])
16
- expect(@server.class).to receive(:publish).twice
17
- @server.class.resend_events_after 1
9
+ describe 'resend_events_after' do
10
+ it 'starts the replay server if its not running' do
11
+ expect(ActiveEvent::ReplayServer).to receive(:start)
12
+ @server.resend_events_after(1).join
13
+ end
14
+
15
+ it 'updates the replay server if its running' do
16
+ @server.instance_variable_set(:@replay_server_thread, Thread.new {sleep 1})
17
+ expect(ActiveEvent::ReplayServer).to receive(:update)
18
+ @server.resend_events_after 1
19
+ end
18
20
  end
19
21
 
20
22
  it 'publishes an event' do
@@ -0,0 +1,66 @@
1
+ require_relative '../spec_helper'
2
+ describe ActiveEvent::ReplayServer do
3
+ class TestEvent
4
+ end
5
+ before :all do
6
+ @server = ActiveEvent::ReplayServer.instance
7
+ @event = TestEvent.new
8
+ end
9
+
10
+ it 'republishes an event' do
11
+ allow(@server).to receive(:resend_exchange).and_return(Object)
12
+ expect(@server.resend_exchange).to receive(:publish).with("{\"bla\":\"Test2\"}", {:type => "TestEvent", :headers => {store_id: 0, replayed: true}})
13
+ expect(@event).to receive(:event).and_return(@event.class.name)
14
+ expect(@event).to receive(:data).and_return(bla: 'Test2')
15
+ expect(@event).to receive(:id).and_return(0)
16
+ @server.republish(@event)
17
+ end
18
+
19
+ it 'starts and stop republishing events' do
20
+ expect(ActiveEvent::EventRepository).to receive(:after_id).and_return([1, 2, 3, 4], [])
21
+ expect(@server).to receive(:republish_events).once
22
+ @server.start_republishing
23
+ end
24
+
25
+ it 'republish all found events' do
26
+ @server.instance_variable_set(:@events, [1, 2, 3, 4])
27
+ expect(Thread).to receive(:pass).exactly(4).times
28
+ expect(@server).to receive(:next_event).exactly(4).times { @server.instance_variable_get(:@events).shift }
29
+ expect(@server).to receive(:republish).exactly(4).times
30
+ @server.republish_events
31
+ end
32
+
33
+ describe 'new_id?' do
34
+ before :each do
35
+ @server.instance_variable_set(:@last_id, 4)
36
+ end
37
+
38
+ it 'overrides id if smaller' do
39
+ @server.queue << 1
40
+ expect(@server.new_id?).to be_true
41
+ expect(@server.instance_variable_get(:@last_id)).to eq 1
42
+ end
43
+
44
+ it 'does nothing if id is greater' do
45
+ @server.queue << 5
46
+ expect(@server.new_id?).to be_false
47
+ expect(@server.instance_variable_get(:@last_id)).not_to eq 5
48
+ end
49
+
50
+ it 'does nothing if queue is empty' do
51
+ @server.queue.clear
52
+ expect(@server.new_id?).to be_false
53
+ end
54
+ end
55
+
56
+ it 'can update start id while running' do
57
+ expect(ActiveEvent::EventRepository).to receive(:after_id).with(1).and_return([2, 3, 4], [])
58
+ expect(ActiveEvent::EventRepository).to receive(:after_id).with(2).and_return([3, 4])
59
+ expect(@server).to receive(:next_event).exactly(3).times { @server.instance_variable_get(:@events).shift }
60
+ expect(@server).to receive(:republish).exactly(3).times
61
+ expect(Thread).to receive(:pass).exactly(3).times
62
+ @server.instance_variable_set(:@last_id, 2)
63
+ @server.queue << 1
64
+ @server.start_republishing
65
+ end
66
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_event
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: activerecord
@@ -147,9 +147,12 @@ files:
147
147
  - lib/active_event/command.rb
148
148
  - lib/active_event/domain.rb
149
149
  - lib/active_event/event_server.rb
150
+ - lib/active_event/event_source_server.rb
150
151
  - lib/active_event/event_type.rb
152
+ - lib/active_event/replay_server.rb
151
153
  - lib/active_event/support/attr_initializer.rb
152
154
  - lib/active_event/support/attr_setter.rb
155
+ - lib/active_event/support/autoload.rb
153
156
  - lib/active_event/support/autoloader.rb
154
157
  - lib/active_event/validations.rb
155
158
  - lib/active_event/validations_registry.rb
@@ -162,6 +165,7 @@ files:
162
165
  - spec/lib/domain_spec.rb
163
166
  - spec/lib/event_server_spec.rb
164
167
  - spec/lib/event_type_spec.rb
168
+ - spec/lib/replay_server_spec.rb
165
169
  - spec/lib/support/attr_initializer_spec.rb
166
170
  - spec/lib/support/attr_setter_spec.rb
167
171
  - spec/models/event_spec.rb
@@ -197,6 +201,7 @@ test_files:
197
201
  - spec/lib/domain_spec.rb
198
202
  - spec/lib/event_server_spec.rb
199
203
  - spec/lib/event_type_spec.rb
204
+ - spec/lib/replay_server_spec.rb
200
205
  - spec/lib/support/attr_initializer_spec.rb
201
206
  - spec/lib/support/attr_setter_spec.rb
202
207
  - spec/models/event_spec.rb