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 +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +4 -1
- data/Gemfile.lock +1 -1
- data/lib/akasha.rb +1 -1
- data/lib/akasha/async_event_router.rb +8 -5
- data/lib/akasha/checkpoint/{http_event_store_checkpoint.rb → metadata_checkpoint.rb} +4 -4
- data/lib/akasha/exceptions.rb +9 -1
- data/lib/akasha/storage/http_event_store/projection_manager.rb +0 -2
- data/lib/akasha/storage/http_event_store/stream.rb +2 -2
- data/lib/akasha/storage/memory_event_store.rb +15 -5
- data/lib/akasha/storage/memory_event_store/stream.rb +25 -7
- data/lib/akasha/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 705a0bd652b156fe253d9084255e16f31e691ecb72a1feb0db5a258c138f2ee0
|
4
|
+
data.tar.gz: 6913586f6b2fbf5e23fe61a67007d570cdcc1aaafa896a1dbc9364e9d7126088
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5656d456264ae24606d1040333d5eaae48bb2b74543e04c6c59bb893ab65f9515c53f892d0ca6cd3cb67e6543c1d3fd4fbce3e80672e36822da4015616fb384e
|
7
|
+
data.tar.gz: 192e285039e9f84ea10356e43e000cbb716230b1cd0a9b6feeb21a27f0495533f274507ff23d6ab5e92920eadde0dbaf402de499d60cd96a337d5eb1ff47118c
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## Version 0.4.0
|
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)
|
data/Gemfile.lock
CHANGED
data/lib/akasha.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require_relative 'event_router_base'
|
2
|
-
require_relative '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::
|
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
|
4
|
-
class
|
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::
|
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::
|
38
|
+
rescue Akasha::HttpClientError => e
|
39
39
|
return 0 if e.status_code == 404
|
40
40
|
raise
|
41
41
|
end
|
data/lib/akasha/exceptions.rb
CHANGED
@@ -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
|
-
##
|
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
|
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
|
-
|
16
|
-
|
17
|
-
|
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
|
-
@
|
39
|
-
|
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
|
-
|
17
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
|
data/lib/akasha/version.rb
CHANGED
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
|
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/
|
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:
|
265
|
+
version: '0'
|
266
266
|
requirements: []
|
267
267
|
rubyforge_project:
|
268
268
|
rubygems_version: 2.7.7
|