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 +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
|