akasha 0.4.0.pre.200 → 0.4.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
  SHA256:
3
- metadata.gz: 5188ceabcaec253c22b9e59ee21907a3288cb1105898d75a35afb2b365327f0a
4
- data.tar.gz: eb5b504cb7305e06c081f1c0370bbf94d1bf299b26f2e8ca403e4c68b1827e5d
3
+ metadata.gz: 705a0bd652b156fe253d9084255e16f31e691ecb72a1feb0db5a258c138f2ee0
4
+ data.tar.gz: 6913586f6b2fbf5e23fe61a67007d570cdcc1aaafa896a1dbc9364e9d7126088
5
5
  SHA512:
6
- metadata.gz: 0198526485615fab2f0397391d8a1ca84b621fbf7e32633952c761fe48095db7557d359d4bf8f20e27632dddac6be2a11e08e109e185ef063259d11ca6ae540f
7
- data.tar.gz: f29bae127e182faa83963e84bd653d70b4fb30a8a15053fc822895e19018f235cc7e2af1d3a2493d7ec78c826a6d647b58392ab4f686784319cdb6debd2e19f4
6
+ metadata.gz: 5656d456264ae24606d1040333d5eaae48bb2b74543e04c6c59bb893ab65f9515c53f892d0ca6cd3cb67e6543c1d3fd4fbce3e80672e36822da4015616fb384e
7
+ data.tar.gz: 192e285039e9f84ea10356e43e000cbb716230b1cd0a9b6feeb21a27f0495533f274507ff23d6ab5e92920eadde0dbaf402de499d60cd96a337d5eb1ff47118c
@@ -12,7 +12,7 @@ Metrics/ClassLength:
12
12
  Metrics/LineLength:
13
13
  Max: 120
14
14
  Metrics/MethodLength:
15
- Max: 15
15
+ Max: 20
16
16
  Rails/Output:
17
17
  Enabled: false
18
18
  Style/FormatStringToken:
@@ -1,6 +1,6 @@
1
1
  # Changelog
2
2
 
3
- ## Version 0.4.0.pre
3
+ ## Version 0.4.0
4
4
 
5
5
  * Support for optimistic concurrency for commands. Enabled by default, will raise `ConflictError` if the aggregate
6
6
  handling a command is modified by another process. Will internally retry the command up to 2 times before giving up.
@@ -20,6 +20,8 @@
20
20
 
21
21
  * Fixed issue for passsing Handlers to EventRouter via constructor, when they are not wrapped in array. [#15](https://github.com/bilus/akasha/pull/15)
22
22
 
23
+ * Make `AsyncEventRouter` compatible with `MemoryEventStore`. [#18](https://github.com/bilus/akasha/pull/18)
24
+
23
25
 
24
26
  ## Version 0.3.0
25
27
 
@@ -31,6 +33,7 @@
31
33
 
32
34
  * `Event#metadata` is no longer OpenStruct. [#10](https://github.com/bilus/akasha/pull/10)
33
35
 
36
+
34
37
  ## Version 0.2.0
35
38
 
36
39
  * Synchronous event listeners (see `examples/sinatra/app.rb`). [#4](https://github.com/bilus/akasha/pull/4)
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- akasha (0.4.0.pre)
4
+ akasha (0.4.0)
5
5
  corefines (~> 1.11)
6
6
  faraday (~> 0.15)
7
7
  faraday_middleware
@@ -9,4 +9,4 @@ require 'akasha/async_event_router'
9
9
  require 'akasha/repository'
10
10
  require 'akasha/storage/http_event_store'
11
11
  require 'akasha/storage/memory_event_store'
12
- require 'akasha/checkpoint/http_event_store_checkpoint'
12
+ require 'akasha/checkpoint/metadata_checkpoint'
@@ -1,5 +1,5 @@
1
1
  require_relative 'event_router_base'
2
- require_relative 'checkpoint/http_event_store_checkpoint'
2
+ require_relative 'checkpoint/metadata_checkpoint'
3
3
 
4
4
  module Akasha
5
5
  # Event router working that can run in the background, providing eventual
@@ -8,17 +8,17 @@ module Akasha
8
8
  DEFAULT_POLL_SECONDS = 2
9
9
  DEFAULT_PAGE_SIZE = 20
10
10
  DEFAULT_PROJECTION_STREAM = 'AsyncEventRouter'.freeze
11
- DEFAULT_CHECKPOINT_STRATEGY = Akasha::Checkpoint::HttpEventStoreCheckpoint
11
+ DEFAULT_CHECKPOINT_STRATEGY = Akasha::Checkpoint::MetadataCheckpoint
12
12
  STREAM_NAME_SEP = '-'.freeze
13
13
 
14
14
  def connect!(repository, projection_name: nil,
15
15
  checkpoint_strategy: DEFAULT_CHECKPOINT_STRATEGY,
16
16
  page_size: DEFAULT_PAGE_SIZE, poll: DEFAULT_POLL_SECONDS)
17
17
  projection_name = projection_name(repository) if projection_name.nil?
18
- projection_stream = repository.store.streams[projection_name]
19
- checkpoint = checkpoint_strategy.is_a?(Class) ? checkpoint_strategy.new(projection_stream) : checkpoint_strategy
20
18
  repository.merge_all_by_event(into: projection_name,
21
19
  only: registered_event_names)
20
+ projection_stream = repository.store.streams[projection_name]
21
+ checkpoint = checkpoint_strategy.is_a?(Class) ? checkpoint_strategy.new(projection_stream) : checkpoint_strategy
22
22
  Thread.new do
23
23
  run_forever(projection_stream, checkpoint, page_size, poll)
24
24
  end
@@ -30,7 +30,7 @@ module Akasha
30
30
  def run_forever(projection_stream, checkpoint, page_size, poll)
31
31
  position = checkpoint.latest
32
32
  loop do
33
- projection_stream.read_events(position, page_size, poll) do |events|
33
+ projection_stream.read_events(position, page_size, poll: poll) do |events|
34
34
  begin
35
35
  events.each do |event|
36
36
  route(event.name, event.metadata[:aggregate_id], **event.data)
@@ -42,6 +42,9 @@ module Akasha
42
42
  end
43
43
  end
44
44
  end
45
+ rescue RutimeError => e
46
+ puts e # TODO: Decide on a strategy.
47
+ raise
45
48
  end
46
49
 
47
50
  def projection_name(repository)
@@ -1,7 +1,7 @@
1
1
  module Akasha
2
2
  module Checkpoint
3
- # Stores stream position via HTTP Eventstore API.
4
- class HttpEventStoreCheckpoint
3
+ # Stores stream position in stream metadata.
4
+ class MetadataCheckpoint
5
5
  # Creates a new checkpoint, storing position in `stream` every `interval` events.
6
6
  # Use `interval` greater than zero for idempotent event listeners.
7
7
  def initialize(stream, interval: 1)
@@ -26,7 +26,7 @@ module Akasha
26
26
  @stream.metadata = @stream.metadata.merge(next_position: @next_position)
27
27
  end
28
28
  @next_position
29
- rescue Akasha::Storage::HttpEventStore::HttpClientError => e
29
+ rescue Akasha::HttpClientError => e
30
30
  raise if e.status_code != 404
31
31
  raise CheckpointStreamNotFoundError, "Stream cannot be checkpointed; it does not exist: #{@stream.name}"
32
32
  end
@@ -35,7 +35,7 @@ module Akasha
35
35
 
36
36
  def read_position
37
37
  @stream.metadata[:next_position]
38
- rescue Akasha::Storage::HttpEventStore::HttpClientError => e
38
+ rescue Akasha::HttpClientError => e
39
39
  return 0 if e.status_code == 404
40
40
  raise
41
41
  end
@@ -13,6 +13,14 @@ module Akasha
13
13
  # Type of the handler found for a command is not supported.
14
14
  UnsupportedHandlerError = Class.new(CommandRoutingError)
15
15
 
16
+ ## Event routing errors
17
+
18
+ # Base exception class for errors related to routing events.
19
+ EventRoutingError = Class.new(Error)
20
+
21
+ # Projection stream hasn't been set up yet.
22
+ MissingProjectionError = Class.new(EventRoutingError)
23
+
16
24
  ## Concurrency errors
17
25
 
18
26
  # Base exception class for concurrency-related errors.
@@ -29,7 +37,7 @@ module Akasha
29
37
  # Missing stream when saving checkpoint.
30
38
  CheckpointStreamNotFoundError = Class.new(Error)
31
39
 
32
- ## Storega errors
40
+ ## Storage errors
33
41
 
34
42
  # Base class for all storage backend errors.
35
43
  StorageError = Class.new(Error)
@@ -23,7 +23,6 @@ module Akasha
23
23
 
24
24
  private
25
25
 
26
- # rubocop:disable Metrics/MethodLength
27
26
  def projection_javascript(name, events, namespace)
28
27
  callback_fmt = if namespace.nil?
29
28
  <<~JS
@@ -59,7 +58,6 @@ module Akasha
59
58
  });
60
59
  JS
61
60
  end
62
- # rubocop:enable Metrics/MethodLength
63
61
 
64
62
  def attempt_create_projection(name, event_names, namespace)
65
63
  create_options = {
@@ -31,11 +31,11 @@ module Akasha
31
31
  # If block not given, reads `size` events from the position.
32
32
  # You can also turn on long-polling using `poll` and setting it to the number
33
33
  # of seconds to wait for.
34
- def read_events(start, page_size, poll = 0)
34
+ def read_events(start, page_size, poll: 0)
35
35
  if block_given?
36
36
  position = start
37
37
  loop do
38
- events = read_events(position, page_size, poll)
38
+ events = read_events(position, page_size, poll: poll)
39
39
  return if events.empty?
40
40
  yield(events)
41
41
  position += events.size
@@ -10,11 +10,19 @@ module Akasha
10
10
  attr_reader :streams
11
11
 
12
12
  def initialize
13
+ @monitor = Monitor.new
13
14
  store = self
14
15
  @streams = Hash.new do |streams, name|
15
- streams[name] = Stream.new do |new_events|
16
- store.update_projections(new_events)
17
- new_events
16
+ @monitor.synchronize do
17
+ # Double-checked-locking.
18
+ if streams.key?(name)
19
+ streams[name]
20
+ else
21
+ streams[name] = Stream.new do |new_events|
22
+ store.update_projections(new_events)
23
+ new_events
24
+ end
25
+ end
18
26
  end
19
27
  end
20
28
  @projections = []
@@ -35,8 +43,10 @@ module Akasha
35
43
  only.include?(event.name)
36
44
  end
37
45
  end
38
- @streams[into] = new_stream
39
- @projections << new_stream
46
+ @monitor.synchronize do
47
+ @streams[into] = new_stream
48
+ @projections << new_stream
49
+ end
40
50
  new_stream
41
51
  end
42
52
 
@@ -9,22 +9,40 @@ module Akasha
9
9
  def initialize(&before_write)
10
10
  @before_write = before_write || identity
11
11
  @events = []
12
+ @metadata = {}
13
+ @monitor = Monitor.new
12
14
  end
13
15
 
14
16
  # Appends events to the stream.
15
17
  def write_events(events, revision: nil)
16
- check_revision!(revision)
17
- @events += to_recorded_events(@events.size, @before_write.call(events))
18
+ @monitor.synchronize do
19
+ check_revision!(revision)
20
+ @events += to_recorded_events(@events.size, @before_write.call(events))
21
+ end
18
22
  end
19
23
 
20
24
  # Reads events from the stream starting from `start` inclusive.
21
25
  # If block given, reads all events from the start in pages of `page_size`.
22
26
  # If block not given, reads `page_size` events from the start.
23
- def read_events(start, page_size, &block)
24
- if block_given?
25
- @events.lazy.drop(start).each_slice(page_size, &block)
26
- else
27
- @events[start..start + page_size]
27
+ def read_events(start, page_size, **_options, &block)
28
+ @monitor.synchronize do
29
+ if block_given?
30
+ @events.drop(start).each_slice(page_size, &block)
31
+ else
32
+ @events[start..start + page_size]
33
+ end
34
+ end
35
+ end
36
+
37
+ def metadata
38
+ @monitor.synchronize do
39
+ @metadata
40
+ end
41
+ end
42
+
43
+ def metadata=(metadata)
44
+ @monitor.synchronize do
45
+ @metadata = metadata
28
46
  end
29
47
  end
30
48
 
@@ -1,3 +1,3 @@
1
1
  module Akasha
2
- VERSION = '0.4.0.pre'.freeze
2
+ VERSION = '0.4.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: akasha
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0.pre.200
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcin Bilski
@@ -225,7 +225,7 @@ files:
225
225
  - lib/akasha/aggregate/syntax_helpers.rb
226
226
  - lib/akasha/async_event_router.rb
227
227
  - lib/akasha/changeset.rb
228
- - lib/akasha/checkpoint/http_event_store_checkpoint.rb
228
+ - lib/akasha/checkpoint/metadata_checkpoint.rb
229
229
  - lib/akasha/command_router.rb
230
230
  - lib/akasha/command_router/optimistic_transactor.rb
231
231
  - lib/akasha/event.rb
@@ -260,9 +260,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
260
260
  version: '0'
261
261
  required_rubygems_version: !ruby/object:Gem::Requirement
262
262
  requirements:
263
- - - ">"
263
+ - - ">="
264
264
  - !ruby/object:Gem::Version
265
- version: 1.3.1
265
+ version: '0'
266
266
  requirements: []
267
267
  rubyforge_project:
268
268
  rubygems_version: 2.7.7