akasha 0.4.0.pre.200 → 0.4.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
  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