euston-daemons 1.0.4-java → 1.1.0-java

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.
Files changed (84) hide show
  1. data/Gemfile +3 -1
  2. data/Rakefile +2 -3
  3. data/euston-daemons.gemspec +61 -26
  4. data/lib/euston-daemons/command_processor_daemon/config/environment.rb +27 -18
  5. data/lib/euston-daemons/command_processor_daemon/lib/clients/command_handler.rb +37 -0
  6. data/lib/euston-daemons/command_processor_daemon/lib/command_handlers/retry_failed_message.rb +35 -0
  7. data/lib/euston-daemons/command_processor_daemon/lib/daemon.rb +11 -32
  8. data/lib/euston-daemons/command_processor_daemon/lib/mongo_models/failed_message.rb +34 -0
  9. data/lib/euston-daemons/command_processor_daemon/rake_task.rb +15 -13
  10. data/lib/euston-daemons/euston/daemon.rb +93 -0
  11. data/lib/euston-daemons/euston/daemon_client.rb +24 -0
  12. data/lib/euston-daemons/euston/daemon_component.rb +65 -0
  13. data/lib/euston-daemons/euston/daemon_environment.rb +54 -0
  14. data/lib/euston-daemons/event_processor_daemon/config/environment.rb +27 -16
  15. data/lib/euston-daemons/event_processor_daemon/lib/clients/event_handler.rb +42 -0
  16. data/lib/euston-daemons/event_processor_daemon/lib/daemon.rb +13 -60
  17. data/lib/euston-daemons/event_processor_daemon/lib/event_handlers/message_failure.rb +27 -0
  18. data/lib/euston-daemons/event_processor_daemon/rake_task.rb +18 -16
  19. data/lib/euston-daemons/message_buffer_daemon/config/environment.rb +39 -25
  20. data/lib/euston-daemons/message_buffer_daemon/lib/clients/command_buffer_cleanup.rb +9 -0
  21. data/lib/euston-daemons/message_buffer_daemon/lib/clients/command_buffer_publisher.rb +9 -0
  22. data/lib/euston-daemons/message_buffer_daemon/lib/clients/command_logger.rb +9 -0
  23. data/lib/euston-daemons/message_buffer_daemon/lib/clients/euston_exchange_accessors.rb +15 -0
  24. data/lib/euston-daemons/message_buffer_daemon/lib/clients/event_buffer_cleanup.rb +9 -0
  25. data/lib/euston-daemons/message_buffer_daemon/lib/clients/event_buffer_publisher.rb +9 -0
  26. data/lib/euston-daemons/message_buffer_daemon/lib/clients/event_logger.rb +9 -0
  27. data/lib/euston-daemons/message_buffer_daemon/lib/clients/event_store_dispatcher.rb +25 -0
  28. data/lib/euston-daemons/message_buffer_daemon/lib/clients/message_buffer_cleanup.rb +52 -0
  29. data/lib/euston-daemons/message_buffer_daemon/lib/clients/message_buffer_publisher.rb +37 -0
  30. data/lib/euston-daemons/message_buffer_daemon/lib/clients/message_logger.rb +45 -0
  31. data/lib/euston-daemons/message_buffer_daemon/lib/clients/mongo_model_accessors.rb +21 -0
  32. data/lib/euston-daemons/message_buffer_daemon/lib/daemon.rb +11 -42
  33. data/lib/euston-daemons/message_buffer_daemon/lib/mongo_models/command_buffer.rb +11 -0
  34. data/lib/euston-daemons/message_buffer_daemon/lib/mongo_models/command_log.rb +11 -0
  35. data/lib/euston-daemons/message_buffer_daemon/lib/mongo_models/event_buffer.rb +11 -0
  36. data/lib/euston-daemons/message_buffer_daemon/lib/mongo_models/event_log.rb +11 -0
  37. data/lib/euston-daemons/message_buffer_daemon/lib/mongo_models/message_buffer.rb +57 -0
  38. data/lib/euston-daemons/message_buffer_daemon/lib/{read_model → mongo_models}/message_log.rb +4 -11
  39. data/lib/euston-daemons/message_buffer_daemon/rake_task.rb +13 -11
  40. data/lib/euston-daemons/rake_task.rb +41 -65
  41. data/lib/euston-daemons/rake_tasks.rb +5 -5
  42. data/lib/euston-daemons/snapshot_daemon/lib/clients/snapshotter.rb +43 -0
  43. data/lib/euston-daemons/version.rb +1 -1
  44. data/lib/euston-daemons.rb +6 -1
  45. data/sample/Rakefile +63 -0
  46. data/sample/amqp_config.yml +14 -0
  47. data/sample/command_handlers.rb +17 -0
  48. data/sample/command_processor_daemon_config.yml +9 -0
  49. data/sample/event_handlers.rb +21 -0
  50. data/sample/event_processor_daemon_config.yml +8 -0
  51. data/sample/message_buffer_daemon_config.yml +8 -0
  52. data/sample/mongoid_config.yml +13 -0
  53. data/sample/pids/.placeholder +0 -0
  54. data/spec/daemons/command_buffer_publisher_spec.rb +110 -0
  55. data/spec/daemons/command_handler_spec.rb +48 -0
  56. data/spec/daemons/event_handler_spec.rb +55 -0
  57. data/spec/daemons/snapshot_client_spec.rb +98 -0
  58. data/spec/spec_helper.rb +77 -0
  59. data/spec/support/factories/commands.rb +16 -0
  60. data/spec/support/factories/commit.rb +7 -0
  61. data/spec/support/factories/event_message.rb +12 -0
  62. data/spec/support/factories/events.rb +8 -0
  63. data/spec/support/filters.rb +14 -0
  64. data/spec/support/sample_model/commands.rb +14 -0
  65. data/spec/support/sample_model/counter.rb +36 -0
  66. data/spec/support/sample_model/counter2.rb +46 -0
  67. data/spec/support/stub_retrying_subscription.rb +9 -0
  68. metadata +134 -67
  69. data/lib/euston-daemons/command_processor_daemon/lib/components/command_handler_component.rb +0 -56
  70. data/lib/euston-daemons/command_processor_daemon/lib/settings.rb +0 -22
  71. data/lib/euston-daemons/event_processor_daemon/lib/components/event_handler_component.rb +0 -58
  72. data/lib/euston-daemons/event_processor_daemon/lib/settings.rb +0 -26
  73. data/lib/euston-daemons/framework/basic_component.rb +0 -33
  74. data/lib/euston-daemons/framework/channel_thread.rb +0 -22
  75. data/lib/euston-daemons/framework/component_shutdown.rb +0 -22
  76. data/lib/euston-daemons/framework/daemon.rb +0 -27
  77. data/lib/euston-daemons/framework/handler_bindings_component.rb +0 -56
  78. data/lib/euston-daemons/framework/queue.rb +0 -71
  79. data/lib/euston-daemons/message_buffer_daemon/lib/components/buffer_component.rb +0 -73
  80. data/lib/euston-daemons/message_buffer_daemon/lib/components/event_store_component.rb +0 -52
  81. data/lib/euston-daemons/message_buffer_daemon/lib/message_logger.rb +0 -54
  82. data/lib/euston-daemons/message_buffer_daemon/lib/publisher.rb +0 -56
  83. data/lib/euston-daemons/message_buffer_daemon/lib/settings.rb +0 -14
  84. data/lib/euston-daemons/message_buffer_daemon/lib/subscriber.rb +0 -60
@@ -0,0 +1,110 @@
1
+ describe 'command buffer publisher client', :purge_event_store do
2
+ require 'euston-daemons/message_buffer_daemon/lib/clients/euston_exchange_accessors'
3
+ require 'euston-daemons/message_buffer_daemon/lib/clients/mongo_model_accessors'
4
+ require 'euston-daemons/message_buffer_daemon/lib/clients/message_buffer_publisher'
5
+ require 'euston-daemons/message_buffer_daemon/lib/clients/command_buffer_publisher'
6
+ require 'euston-daemons/message_buffer_daemon/lib/mongo_models/message_buffer'
7
+ require 'euston-daemons/message_buffer_daemon/lib/mongo_models/command_buffer'
8
+
9
+ let(:logger) { Euston::NullLogger.instance }
10
+ let(:channel) { double('channel').as_null_object }
11
+ let(:command) { Factory.build(:create_counter_command, :id => Uuid.generate).to_hash }
12
+ let(:exchange) { double('exchange').as_null_object }
13
+ let(:published) { [] }
14
+ let(:collection) { @event_store_database[buffer.name] }
15
+ let(:buffer) { Euston::MessageBufferDaemon::MongoModel::CommandBuffer.new @event_store_database }
16
+ let(:publisher) { Euston::MessageBufferDaemon::CommandBufferPublisher.new channel }
17
+
18
+ module Euston
19
+ class DaemonEnvironment
20
+ class << self
21
+ attr_accessor :event_store_mongodb
22
+ end
23
+ end
24
+ end
25
+
26
+ before do
27
+ Euston::DaemonEnvironment.event_store_mongodb = @event_store_database
28
+ channel.stub(:topic) { exchange }
29
+ exchange.stub(:name) { 'commands' }
30
+ exchange.stub(:publish) { |json, options| published << { :json => json, :options => options } }
31
+ end
32
+
33
+ context 'there are no commands in the buffer' do
34
+ describe 'command buffer size' do
35
+ subject { collection.count }
36
+ it { should == 0 }
37
+ end
38
+
39
+ context 'the publisher runs' do
40
+ before { publisher.run }
41
+
42
+ describe 'published commands' do
43
+ subject { published }
44
+ it { should be_empty }
45
+ end
46
+ end
47
+ end
48
+
49
+ context 'there is a due command' do
50
+
51
+ before do
52
+ buffer.buffer_new_message command
53
+ end
54
+
55
+ describe 'command buffer size' do
56
+ subject { collection.count }
57
+ it { should == 1 }
58
+ end
59
+
60
+ context 'the publisher runs' do
61
+ before { publisher.run }
62
+
63
+ describe 'published commands' do
64
+ subject { published }
65
+ it { should have(1).item }
66
+ end
67
+
68
+ describe 'published command' do
69
+ subject { published.first }
70
+ its([:json]) { should == command.to_json }
71
+ end
72
+
73
+ describe 'buffered command' do
74
+ subject { collection.find_one }
75
+ its(['next_attempt']) { should > Time.now.to_f + 2 }
76
+ end
77
+ end
78
+ end
79
+
80
+ context 'there is a command that is not yet due' do
81
+ before do
82
+ buffer.buffer_new_message command
83
+ collection.update({}, { '$set' => { 'next_attempt' => Time.now.to_f + 1000 } }, { :safe => true })
84
+ end
85
+
86
+ context 'the publisher runs' do
87
+ before { publisher.run }
88
+
89
+ describe 'published commands' do
90
+ subject { published }
91
+ it { should be_empty }
92
+ end
93
+ end
94
+ end
95
+
96
+ context 'a command is buffered for dispatch in the future' do
97
+ before do
98
+ buffer.buffer_new_message command, Time.now.to_f + 1000
99
+ end
100
+
101
+ context 'the publisher runs' do
102
+ before { publisher.run }
103
+
104
+ describe 'published commands' do
105
+ subject { published }
106
+ it { should be_empty }
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,48 @@
1
+ describe 'command handler client', :purge_event_store, :purge_rabbitmq do
2
+ require 'euston-daemons/command_processor_daemon/lib/clients/command_handler'
3
+
4
+ let(:logger) { Euston::NullLogger.instance }
5
+ let(:handlers) { [] }
6
+ let(:subscription) { StubRetryingSubscription.new }
7
+ let(:client) { Euston::CommandProcessorDaemon::CommandHandler.new @channel, handlers, logger }
8
+ let(:aggregate) { Euston::Daemons::SampleModel::Counter2.new }
9
+ let(:saved_aggregates) { [] }
10
+
11
+ before do
12
+ Euston::RabbitMq::RetryingSubscription.stub(:new) { subscription }
13
+ Euston::Repository.stub(:find) { aggregate }
14
+ Euston::Repository.stub(:save) { |aggregate| saved_aggregates << aggregate }
15
+ end
16
+
17
+ context 'a message is received' do
18
+ before do
19
+ client.run
20
+ command = Factory.build(:create_counter_command, :id => Uuid.generate).to_hash
21
+ subscription.stub_message_receipt command
22
+ end
23
+
24
+ context 'the message is not explicitly handled by a command handler class' do
25
+ subject { saved_aggregates }
26
+ it { should_not be_empty }
27
+ end
28
+
29
+ context 'the message is explicitly handled by a command handler class' do
30
+ class CreateCounter
31
+ include Euston::CommandHandler
32
+
33
+ class << self
34
+ attr_accessor :was_called
35
+ end
36
+
37
+ version 1 do |headers, command|
38
+ self.class.was_called = true
39
+ end
40
+ end
41
+
42
+ let(:handlers) { [ Euston::RabbitMq::HandlerReference.new(Object, CreateCounter, :CreateCounter) ] }
43
+
44
+ subject { CreateCounter.was_called }
45
+ it { should be_true }
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,55 @@
1
+ describe 'event handler client', :purge_event_store, :purge_rabbitmq do
2
+ require 'euston-daemons/event_processor_daemon/lib/clients/event_handler'
3
+
4
+ let(:logger) { Euston::NullLogger.instance }
5
+ let(:subscription) { StubRetryingSubscription.new }
6
+ let(:client) { Euston::EventProcessorDaemon::EventHandler.new @channel, reference, logger }
7
+ let(:aggregate) { Euston::Daemons::SampleModel::Counter2.new }
8
+ let(:saved_aggregates) { [] }
9
+
10
+ before do
11
+ Euston::RabbitMq::RetryingSubscription.stub(:new) { subscription }
12
+ Euston::Repository.stub(:find) { aggregate }
13
+ Euston::Repository.stub(:save) { |aggregate| saved_aggregates << aggregate }
14
+ end
15
+
16
+ context 'a message is received' do
17
+ before do
18
+ client.run
19
+
20
+ event = { :headers => { :id => Uuid.generate,
21
+ :type => :external_thing_happened,
22
+ :timestamp => Time.now.to_f,
23
+ :version => 1 },
24
+ :body => {} }
25
+
26
+ subscription.stub_message_receipt event
27
+ end
28
+
29
+ context 'the event handler is bound to an aggregate root' do
30
+ let(:reference) { Euston::RabbitMq::HandlerReference.new(Euston::Daemons::SampleModel, Euston::Daemons::SampleModel::Counter2, :Counter2) }
31
+
32
+ subject { saved_aggregates }
33
+ it { should_not be_empty }
34
+ end
35
+
36
+ context 'the message is explicitly handled by an event handler class' do
37
+ class ExternalThingHappenedListener
38
+ include Euston::EventHandler
39
+
40
+ class << self
41
+ attr_accessor :was_called
42
+ end
43
+
44
+ subscribes :external_thing_happened, do |headers, command|
45
+ self.class.was_called = true
46
+ end
47
+ end
48
+
49
+ let(:reference) { Euston::RabbitMq::HandlerReference.new(Object, ExternalThingHappenedListener, :ExternalThingHappenedListener) }
50
+
51
+ subject { ExternalThingHappenedListener.was_called }
52
+ it { should be_true }
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,98 @@
1
+ describe 'snapshot client', :purge_event_store, :euston_event_store do
2
+ require 'euston-daemons/snapshot_daemon/lib/clients/snapshotter'
3
+
4
+ let(:logger) { Euston::NullLogger.instance }
5
+ let(:threshold) { 2 }
6
+ let(:snapshotter) { Euston::SnapshotDaemon::Snapshotter.new @event_store, threshold, logger }
7
+ let(:commands) { [] }
8
+ let(:counter_id) { Uuid.generate }
9
+
10
+ def publish_commands_then_take_snapshot commands
11
+ commands.each { |c| publish_command c }
12
+ sleep 0.25 # to allow the async stream head update to finish
13
+ snapshotter.run
14
+ end
15
+
16
+ before { publish_commands_then_take_snapshot commands }
17
+
18
+ context 'there are no streams' do
19
+ describe 'snapshots collection size' do
20
+ subject { @event_store_database['snapshots'].count }
21
+ it { should == 0 }
22
+ end
23
+ end
24
+
25
+ context 'there is a stream that is too small to snapshot' do
26
+ let(:commands) { [ Factory.build(:create_counter_command) ] }
27
+
28
+ describe 'snapshots collection size' do
29
+ subject { @event_store_database['snapshots'].count }
30
+ it { should == 0 }
31
+ end
32
+ end
33
+
34
+ context 'there is a stream that is large enough to snapshot' do
35
+ let(:commands) { [ Factory.build(:create_counter_command, :id => counter_id),
36
+ Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 1),
37
+ Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 2) ] }
38
+
39
+ describe 'snapshots collection size' do
40
+ subject { @event_store_database['snapshots'].count }
41
+ it { should == 1 }
42
+ end
43
+
44
+ describe 'snapshot' do
45
+ subject { @event_store.get_snapshot counter_id }
46
+ its(:headers) { should == { :version => 1 } }
47
+ its(:payload) { should == { :count => 3 } }
48
+ end
49
+
50
+ describe 'reloading from the snapshot' do
51
+ subject { Euston::Repository.find Euston::Daemons::SampleModel::Counter, counter_id }
52
+ its(:count) { should == 3 }
53
+ its(:snapshot_loaded) { should == { :count => 3 }}
54
+ end
55
+ end
56
+
57
+ context 'multiple snapshots taken over time' do
58
+ # let(:logger) { Logger.new(STDOUT) }
59
+
60
+ let(:commands) { [ Factory.build(:create_counter_command, :id => counter_id),
61
+ Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 1),
62
+ Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 2) ] }
63
+ let(:commands2) { [ Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 3),
64
+ Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 5),
65
+ Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 8) ] }
66
+ let(:commands3) { [ Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 13),
67
+ Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 21),
68
+ Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 34) ] }
69
+
70
+ before do
71
+ publish_commands_then_take_snapshot commands2
72
+ publish_commands_then_take_snapshot commands3
73
+ end
74
+
75
+ describe 'snapshots collection size' do
76
+ subject { @event_store_database['snapshots'].count }
77
+ it { should == 3 }
78
+ end
79
+
80
+ describe 'first snapshot' do
81
+ subject { @event_store.get_snapshot counter_id, 3 }
82
+ its(:headers) { should == { :version => 1 } }
83
+ its(:payload) { should == { :count => 3 } }
84
+ end
85
+
86
+ describe 'second snapshot' do
87
+ subject { @event_store.get_snapshot counter_id, 6 }
88
+ its(:headers) { should == { :version => 1 } }
89
+ its(:payload) { should == { :count => 19 } }
90
+ end
91
+
92
+ describe 'third snapshot' do
93
+ subject { @event_store.get_snapshot counter_id }
94
+ its(:headers) { should == { :version => 1 } }
95
+ its(:payload) { should == { :count => 87 } }
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,77 @@
1
+ jruby = RUBY_PLATFORM.to_s == 'java'
2
+
3
+ require 'ap'
4
+ require 'rabbitmqadmin-cli'
5
+ require 'euston'
6
+ require 'euston-rabbitmq'
7
+ require 'euston-eventstore'
8
+ require 'euston-daemons'
9
+ require 'cranky'
10
+ require 'ffaker'
11
+ require 'mongo' unless jruby
12
+ require 'jmongo' if jruby
13
+ require 'safely'
14
+
15
+ specs_path = File.dirname __FILE__
16
+ require File.join specs_path, 'support', 'factories', 'event_message'
17
+ require File.join specs_path, 'support', 'factories', 'commit'
18
+ require File.join specs_path, 'support', 'factories', 'commands'
19
+ require File.join specs_path, 'support', 'filters'
20
+ require File.join specs_path, 'support', 'stub_retrying_subscription'
21
+ require File.join specs_path, 'support', 'sample_model', 'commands'
22
+ require File.join specs_path, 'support', 'sample_model', 'counter'
23
+ require File.join specs_path, 'support', 'sample_model', 'counter2'
24
+
25
+ Safely.configure do |config|
26
+ config.strategies = [ Safely::Strategy::Log ]
27
+ end
28
+
29
+ amqp_config = { :host => 'localhost', :vhost => 'euston-daemons-test', :user => 'euston-daemons-test-user', :pass => 'password' }
30
+
31
+ mongo_connection = Mongo::Connection.from_uri 'mongodb://0.0.0.0:27017/', :safe => true, :fsync => true, :journal => true
32
+ event_store_database = Mongo::DB.new 'euston-daemons-test-event-store', mongo_connection
33
+ read_model_database = Mongo::DB.new 'euston-daemons-test-read-model', mongo_connection
34
+
35
+ RSpec.configure do |config|
36
+ config.treat_symbols_as_metadata_keys_with_true_values = true
37
+
38
+ config.before(:each) do
39
+ @event_store_database = event_store_database
40
+ @read_model_database = read_model_database
41
+ end
42
+
43
+ config.before(:each, :euston_event_store) do
44
+ mongo_config = Euston::EventStore::Persistence::Mongodb::Config.instance
45
+ mongo_config.database = event_store_database.name
46
+
47
+ @persistence_factory = Euston::EventStore::Persistence::Mongodb::MongoPersistenceFactory.build
48
+ @persistence_factory.init
49
+
50
+ @event_store = Euston::EventStore::OptimisticEventStore.new @persistence_factory
51
+ Euston::Repository.event_store = @event_store
52
+
53
+ def publish_command command
54
+ hash = command.to_hash
55
+ command = { :headers => Euston::CommandHeaders.from_hash(hash[:headers]), :body => hash[:body] }
56
+ Euston::CommandBus.publish command[:headers], command[:body]
57
+ end
58
+ end
59
+
60
+ config.before(:each, :purge_event_store) do
61
+ purge_database event_store_database
62
+ end
63
+
64
+ config.before(:each, :purge_mongo) do
65
+ purge_database event_store_database
66
+ purge_database read_model_database
67
+ end
68
+
69
+ config.before(:each, :purge_rabbitmq) do
70
+ initialize_rabbitmq amqp_config
71
+ initialize_amqp amqp_config
72
+ end
73
+
74
+ config.before(:each, :purge_read_model) do
75
+ purge_database read_model_database
76
+ end
77
+ end
@@ -0,0 +1,16 @@
1
+ class Cranky::Factory
2
+ def create_counter_command
3
+ hash = define :class => Hash,
4
+ :id => Uuid.generate
5
+
6
+ Euston::Daemons::SampleModel::CreateCounter.new hash
7
+ end
8
+
9
+ def increment_counter_command
10
+ hash = define :class => Hash,
11
+ :counter_id => Uuid.generate,
12
+ :amount => 1 + rand(9)
13
+
14
+ Euston::Daemons::SampleModel::IncrementCounter.new hash
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ class Cranky::Factory
2
+ def commit
3
+ Euston::EventStore::Commit.new :stream_id => Uuid.generate,
4
+ :commit_id => Uuid.generate,
5
+ :events => (1..(rand(2) + 1)).map { Factory.build :event_message }
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ class Cranky::Factory
2
+ def event_message
3
+ headers = { :id => Euston.uuid.generate,
4
+ :type => Faker::Lorem.words(2).join('_'),
5
+ :version => 1,
6
+ :timestamp => Time.now.to_f }
7
+
8
+ body = { :number => rand(9) + 1 }
9
+
10
+ Euston::EventStore::EventMessage.new 'headers' => headers, 'body' => body
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ # class Cranky::Factory
2
+ # def empty_event
3
+ # { :headers => { :id => Uuid.generate, :version => 1 }, :body => { } }
4
+ # hash = define :class => Hash,
5
+ # :id => Uuid.generate,
6
+ # :type => F
7
+ # end
8
+ # end
@@ -0,0 +1,14 @@
1
+ def initialize_amqp config
2
+ AMQP.settings.merge! config
3
+ @channel = AMQP::Channel.new
4
+ end
5
+
6
+ def initialize_rabbitmq config
7
+ @rabbitmqadmin = RabbitMqAdminCli.new
8
+ @rabbitmqadmin.initialize_vhost config[:vhost]
9
+ @rabbitmqadmin.initialize_user config[:vhost], config[:user], config[:pass]
10
+ end
11
+
12
+ def purge_database database
13
+ database.collections.each { |collection| collection.remove unless collection.name.downcase =~ /^system/ }
14
+ end
@@ -0,0 +1,14 @@
1
+ module Euston
2
+ module Daemons
3
+ module SampleModel
4
+ class CreateCounter < Euston::Command
5
+ validates :id, :presence => true
6
+ end
7
+
8
+ class IncrementCounter < Euston::Command
9
+ validates :counter_id, :presence => true
10
+ validates :amount, :presence => true
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,36 @@
1
+ module Euston
2
+ module Daemons
3
+ module SampleModel
4
+ class Counter
5
+ include Euston::AggregateRoot
6
+
7
+ created_by :create_counter do |command|
8
+ apply_event :counter_created, 1, command
9
+ end
10
+
11
+ consumes :increment_counter, :id => :counter_id do |command|
12
+ apply_event :counter_incremented, 1, :count => @count + command.amount
13
+ end
14
+
15
+ applies :counter_created do |event|
16
+ @count = 0
17
+ end
18
+
19
+ applies :counter_incremented do |event|
20
+ @count = event.count
21
+ end
22
+
23
+ load_snapshot 1 do |snapshot|
24
+ @count = snapshot[:count]
25
+ @snapshot_loaded = snapshot
26
+ end
27
+
28
+ take_snapshot 1 do
29
+ { :count => @count }
30
+ end
31
+
32
+ attr_reader :count, :snapshot_loaded
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,46 @@
1
+ module Euston
2
+ module Daemons
3
+ module SampleModel
4
+ class Counter2
5
+ include Euston::AggregateRoot
6
+
7
+ created_by :create_counter do |command|
8
+ apply_event :counter_created, 1, command
9
+ end
10
+
11
+ consumes :increment_counter, :id => :counter_id do |command|
12
+ apply_event :counter_incremented, 1, :count => @count + command.amount
13
+ end
14
+
15
+ subscribes :external_thing_happened do |headers, event|
16
+ apply_event :noted_that_external_thing_happened, 1
17
+ end
18
+
19
+ applies :counter_created do |event|
20
+ @count = 0
21
+ @external_thing_happened = false
22
+ end
23
+
24
+ applies :counter_incremented do |event|
25
+ @count = event.count
26
+ end
27
+
28
+ applies :noted_that_external_thing_happened do |event|
29
+ @external_thing_happened = true
30
+ end
31
+
32
+ load_snapshot 1 do |snapshot|
33
+ @count = snapshot[:count]
34
+ @external_thing_happened = snapshot[:heard_about_external_thing]
35
+ @snapshot_loaded = snapshot
36
+ end
37
+
38
+ take_snapshot 1 do
39
+ { :count => @count, :heard_about_external_thing => @external_thing_happened }
40
+ end
41
+
42
+ attr_reader :count, :snapshot_loaded
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,9 @@
1
+ class StubRetryingSubscription
2
+ include Hollywood
3
+
4
+ def subscribe; end
5
+
6
+ def stub_message_receipt message
7
+ callback :message_received, message
8
+ end
9
+ end