pg_eventstore 1.1.5 → 1.3.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/CHANGELOG.md +33 -0
- data/docs/configuration.md +1 -0
- data/docs/subscriptions.md +4 -2
- data/lib/pg_eventstore/config.rb +4 -0
- data/lib/pg_eventstore/subscriptions/queries/subscription_queries.rb +5 -2
- data/lib/pg_eventstore/subscriptions/queries/subscriptions_set_queries.rb +15 -0
- data/lib/pg_eventstore/subscriptions/subscription_runner.rb +9 -4
- data/lib/pg_eventstore/subscriptions/subscription_runner_commands/reset_position.rb +3 -1
- data/lib/pg_eventstore/subscriptions/subscription_runner_commands/restore.rb +8 -0
- data/lib/pg_eventstore/subscriptions/subscriptions_manager.rb +10 -4
- data/lib/pg_eventstore/version.rb +1 -1
- data/lib/pg_eventstore/web/application.rb +16 -0
- data/lib/pg_eventstore/web/paginator/event_types_collection.rb +2 -2
- data/lib/pg_eventstore/web/paginator/stream_contexts_collection.rb +5 -4
- data/lib/pg_eventstore/web/paginator/stream_names_collection.rb +2 -2
- data/lib/pg_eventstore/web/public/javascripts/pg_eventstore.js +11 -0
- data/lib/pg_eventstore/web/subscriptions/helpers.rb +15 -0
- data/lib/pg_eventstore/web/subscriptions/with_state/set_collection.rb +35 -0
- data/lib/pg_eventstore/web/subscriptions/with_state/subscriptions.rb +39 -0
- data/lib/pg_eventstore/web/subscriptions/with_state/subscriptions_set.rb +40 -0
- data/lib/pg_eventstore/web/views/subscriptions/index.erb +13 -1
- data/lib/pg_eventstore/web.rb +3 -0
- data/pg_eventstore.gemspec +1 -1
- data/sig/interfaces/failed_subscription_notifier.rbs +3 -0
- data/sig/pg_eventstore/config.rbs +2 -0
- data/sig/pg_eventstore/subscriptions/queries/subscription_queries.rbs +1 -1
- data/sig/pg_eventstore/subscriptions/queries/subscriptions_set_queries.rbs +2 -0
- data/sig/pg_eventstore/subscriptions/subscription_runner.rbs +5 -2
- data/sig/pg_eventstore/subscriptions/subscriptions_manager.rbs +5 -2
- data/sig/pg_eventstore/web/subscriptions/helpers.rbs +4 -0
- data/sig/pg_eventstore/web/subscriptions/with_state/set_collection.rbs +21 -0
- data/sig/pg_eventstore/web/subscriptions/with_state/subscriptions.rbs +23 -0
- data/sig/pg_eventstore/web/subscriptions/with_state/subscriptions_set.rbs +23 -0
- metadata +19 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8691b2cf8e831e31da17b71fc06078a25d73ae1e7e1a0b9da629a481a4947842
|
|
4
|
+
data.tar.gz: 9022a6bdac6ef9aadc7338b54fe5a9fea76cdcb5ea7f2a7dc78fdcd98b2f469b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0efd8f80acbee784665bfc455239ea02b336335e2d6f36341ea65d86f973b126794f306373b66b6383cd74ba12b8566b2544bda9ebf5efc9d7d1d3611c6276e3
|
|
7
|
+
data.tar.gz: 31c54e37a0fae15add5af3c03ff8c4a6db41812feb8012bca2f242d245da863c4c99b78465eb39684bdf4259d8eff675493cc690c54a31e49fc15b06e941c42c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.3.0]
|
|
4
|
+
- Add ability to filter subscriptions by state in admin UI
|
|
5
|
+
- Reset error-related subscription's attributes on subscription restore
|
|
6
|
+
- Reset total processed events number when user changes subscription's position
|
|
7
|
+
- Allow to search event type, stream context and stream name by substring in web UI
|
|
8
|
+
- Relax sinatra version requirement to v3+
|
|
9
|
+
|
|
10
|
+
## [1.2.0]
|
|
11
|
+
- Implement `failed_subscription_notifier` subscription hook.
|
|
12
|
+
|
|
13
|
+
Now you are able to define a function that is called when subscription fails and no longer can be automatically restarted because it hit max number of retries. You can define the hook globally in the config and per subscription. Examples:
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
PgEventstore.configure do |config|
|
|
17
|
+
config.failed_subscription_notifier = proc { |sub, error| puts "Subscription: #{sub.inspect}, error: #{error.inspect}" }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
subscriptions_manager = PgEventstore.subscriptions_manager(subscription_set: 'MyApp')
|
|
21
|
+
# Overrides config.failed_subscription_notifier function
|
|
22
|
+
subscriptions_manager.subscribe(
|
|
23
|
+
'My Subscription 1',
|
|
24
|
+
handler: Handler.new('My Subscription 1'),
|
|
25
|
+
options: { filter: { event_types: ['Foo'] } },
|
|
26
|
+
failed_subscription_notifier: proc { |_subscription, err| p err }
|
|
27
|
+
)
|
|
28
|
+
# Uses config.failed_subscription_notifier function
|
|
29
|
+
subscriptions_manager.subscribe(
|
|
30
|
+
'My Subscription 2',
|
|
31
|
+
handler: Handler.new('My Subscription 2'),
|
|
32
|
+
options: { filter: { event_types: ['Bar'] } }
|
|
33
|
+
)
|
|
34
|
+
```
|
|
35
|
+
|
|
3
36
|
## [1.1.5]
|
|
4
37
|
- Review the way to handle SubscriptionAlreadyLockedError error. This removes noise when attempting to lock an already locked subscription.
|
|
5
38
|
|
data/docs/configuration.md
CHANGED
|
@@ -16,6 +16,7 @@ Configuration options:
|
|
|
16
16
|
| subscriptions_set_max_retries | Integer | `10` | Max number of retries for failed subscription sets. |
|
|
17
17
|
| subscriptions_set_retries_interval | Integer | `1` | Interval in seconds between retries of failed subscription sets. |
|
|
18
18
|
| subscription_restart_terminator | `#call` | `nil` | A callable object that accepts `PgEventstore::Subscription` object to determine whether restarts should be stopped(true - stops restarts, false - continues restarts). |
|
|
19
|
+
| failed_subscription_notifier | `#call` | `nil` | A callable object which is invoked with `PgEventstore::Subscription` instance and error instance after the related subscription died due to error and no longer can be automatically restarted due to max retries number reached. You can use this hook to send a notification about failed subscription. |
|
|
19
20
|
|
|
20
21
|
## Multiple configurations
|
|
21
22
|
|
data/docs/subscriptions.md
CHANGED
|
@@ -151,7 +151,7 @@ You will then see the output of your subscription handlers. To gracefully stop t
|
|
|
151
151
|
|
|
152
152
|
## Overriding Subscription config values
|
|
153
153
|
|
|
154
|
-
You can override `subscription_pull_interval`, `subscription_max_retries`, `subscription_retries_interval` and `
|
|
154
|
+
You can override `subscription_pull_interval`, `subscription_max_retries`, `subscription_retries_interval`, `subscription_restart_terminator` and `failed_subscription_notifier` config values (see [**Configuration**](configuration.md) chapter for details) for the specific subscription by providing the corresponding arguments. Example:
|
|
155
155
|
|
|
156
156
|
```ruby
|
|
157
157
|
subscriptions_manager.subscribe(
|
|
@@ -164,7 +164,9 @@ subscriptions_manager.subscribe(
|
|
|
164
164
|
# overrides config.subscription_retries_interval
|
|
165
165
|
retries_interval: 2,
|
|
166
166
|
# overrides config.subscription_restart_terminator
|
|
167
|
-
restart_terminator: proc { |subscription| subscription.last_error['class'] == 'NoMethodError' },
|
|
167
|
+
restart_terminator: proc { |subscription| subscription.last_error['class'] == 'NoMethodError' },
|
|
168
|
+
# overrides config.failed_subscription_notifier
|
|
169
|
+
failed_subscription_notifier: proc { |_subscription, err| p err }
|
|
168
170
|
)
|
|
169
171
|
```
|
|
170
172
|
|
data/lib/pg_eventstore/config.rb
CHANGED
|
@@ -48,6 +48,10 @@ module PgEventstore
|
|
|
48
48
|
# @!attribute subscriptions_set_retries_interval
|
|
49
49
|
# @return [Integer] interval in seconds between retries of failed SubscriptionsSet
|
|
50
50
|
option(:subscriptions_set_retries_interval) { 1 }
|
|
51
|
+
# @!attribute failed_subscription_notifier
|
|
52
|
+
# @return [#call, nil] provide callable object that accepts Subscription instance and error. It is useful when you
|
|
53
|
+
# want to be get notified when your Subscription fails and no longer can be restarted
|
|
54
|
+
option(:failed_subscription_notifier)
|
|
51
55
|
|
|
52
56
|
# @param name [Symbol] config's name. Its value matches the appropriate key in PgEventstore.config hash
|
|
53
57
|
def initialize(name:, **options)
|
|
@@ -45,10 +45,13 @@ module PgEventstore
|
|
|
45
45
|
pg_result.map(&method(:deserialize))
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
# @param state [String, nil]
|
|
48
49
|
# @return [Array<String>]
|
|
49
|
-
def set_collection
|
|
50
|
+
def set_collection(state = nil)
|
|
51
|
+
builder = SQLBuilder.new.from('subscriptions').select('set').group('set').order('set ASC')
|
|
52
|
+
builder.where('state = ?', state) if state
|
|
50
53
|
connection.with do |conn|
|
|
51
|
-
conn.
|
|
54
|
+
conn.exec_params(*builder.to_exec_params)
|
|
52
55
|
end.map { |attrs| attrs['set'] }
|
|
53
56
|
end
|
|
54
57
|
|
|
@@ -27,6 +27,21 @@ module PgEventstore
|
|
|
27
27
|
pg_result.to_a.map(&method(:deserialize))
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
# @param name [String, nil]
|
|
31
|
+
# @param state [String]
|
|
32
|
+
# @return [Array<Hash>]
|
|
33
|
+
def find_all_by_subscription_state(name:, state:)
|
|
34
|
+
builder = SQLBuilder.new.select('subscriptions_set.*').from('subscriptions_set')
|
|
35
|
+
builder.join('JOIN subscriptions ON subscriptions.locked_by = subscriptions_set.id')
|
|
36
|
+
builder.order('subscriptions_set.name ASC, subscriptions_set.id ASC')
|
|
37
|
+
builder.where('subscriptions_set.name = ? and subscriptions.state = ?', name, state)
|
|
38
|
+
builder.group('subscriptions_set.id')
|
|
39
|
+
pg_result = connection.with do |conn|
|
|
40
|
+
conn.exec_params(*builder.to_exec_params)
|
|
41
|
+
end
|
|
42
|
+
pg_result.to_a.map(&method(:deserialize))
|
|
43
|
+
end
|
|
44
|
+
|
|
30
45
|
# @return [Array<String>]
|
|
31
46
|
def set_names
|
|
32
47
|
builder = SQLBuilder.new.select('name').from('subscriptions_set').group('name').order('name ASC')
|
|
@@ -29,11 +29,14 @@ module PgEventstore
|
|
|
29
29
|
# @param events_processor [PgEventstore::EventsProcessor]
|
|
30
30
|
# @param subscription [PgEventstore::Subscription]
|
|
31
31
|
# @param restart_terminator [#call, nil]
|
|
32
|
-
|
|
32
|
+
# @param failed_subscription_notifier [#call, nil]
|
|
33
|
+
def initialize(stats:, events_processor:, subscription:, restart_terminator: nil,
|
|
34
|
+
failed_subscription_notifier: nil)
|
|
33
35
|
@stats = stats
|
|
34
36
|
@events_processor = events_processor
|
|
35
37
|
@subscription = subscription
|
|
36
38
|
@restart_terminator = restart_terminator
|
|
39
|
+
@failed_subscription_notifier = failed_subscription_notifier
|
|
37
40
|
|
|
38
41
|
attach_callbacks
|
|
39
42
|
end
|
|
@@ -119,11 +122,13 @@ module PgEventstore
|
|
|
119
122
|
@subscription.update(last_chunk_fed_at: Time.now.utc, last_chunk_greatest_position: global_position)
|
|
120
123
|
end
|
|
121
124
|
|
|
122
|
-
# @param
|
|
125
|
+
# @param error [StandardError]
|
|
123
126
|
# @return [void]
|
|
124
|
-
def restart_subscription(
|
|
127
|
+
def restart_subscription(error)
|
|
125
128
|
return if @restart_terminator&.call(@subscription.dup)
|
|
126
|
-
|
|
129
|
+
if @subscription.restart_count >= @subscription.max_restarts_number
|
|
130
|
+
return @failed_subscription_notifier&.call(@subscription.dup, error)
|
|
131
|
+
end
|
|
127
132
|
|
|
128
133
|
Thread.new do
|
|
129
134
|
sleep @subscription.time_between_restarts
|
|
@@ -17,7 +17,9 @@ module PgEventstore
|
|
|
17
17
|
def exec_cmd(subscription_runner)
|
|
18
18
|
subscription_runner.within_state(:stopped) do
|
|
19
19
|
subscription_runner.clear_chunk
|
|
20
|
-
subscription_runner.subscription.update(
|
|
20
|
+
subscription_runner.subscription.update(
|
|
21
|
+
last_chunk_greatest_position: nil, current_position: data['position'], total_processed_events: 0
|
|
22
|
+
)
|
|
21
23
|
end
|
|
22
24
|
end
|
|
23
25
|
end
|
|
@@ -7,6 +7,14 @@ module PgEventstore
|
|
|
7
7
|
# @param subscription_runner [PgEventstore::SubscriptionRunner]
|
|
8
8
|
# @return [void]
|
|
9
9
|
def exec_cmd(subscription_runner)
|
|
10
|
+
subscription_runner.within_state(:dead) do
|
|
11
|
+
subscription_runner.subscription.update(
|
|
12
|
+
restart_count: 0,
|
|
13
|
+
last_restarted_at: nil,
|
|
14
|
+
last_error: nil,
|
|
15
|
+
last_error_occurred_at: nil
|
|
16
|
+
)
|
|
17
|
+
end
|
|
10
18
|
subscription_runner.restore
|
|
11
19
|
end
|
|
12
20
|
end
|
|
@@ -61,14 +61,19 @@ module PgEventstore
|
|
|
61
61
|
# given subscription.
|
|
62
62
|
# @param max_retries [Integer] max number of retries of failed Subscription
|
|
63
63
|
# @param retries_interval [Integer, Float] a delay between retries of failed Subscription
|
|
64
|
-
# @param restart_terminator [#call, nil] a callable object which
|
|
65
|
-
#
|
|
64
|
+
# @param restart_terminator [#call, nil] a callable object which is invoked with PgEventstore::Subscription instance
|
|
65
|
+
# to determine whether restarts should be stopped(true - stops restarts, false - continues restarts)
|
|
66
|
+
# @param failed_subscription_notifier [#call, nil] a callable object which is invoked with
|
|
67
|
+
# PgEventstore::Subscription instance and error instance after the related subscription died due to error and no
|
|
68
|
+
# longer can be automatically restarted due to max retries number reached. You can use this hook to send a
|
|
69
|
+
# notification about failed subscription.
|
|
66
70
|
# @return [void]
|
|
67
71
|
def subscribe(subscription_name, handler:, options: {}, middlewares: nil,
|
|
68
72
|
pull_interval: config.subscription_pull_interval,
|
|
69
73
|
max_retries: config.subscription_max_retries,
|
|
70
74
|
retries_interval: config.subscription_retries_interval,
|
|
71
|
-
restart_terminator: config.subscription_restart_terminator
|
|
75
|
+
restart_terminator: config.subscription_restart_terminator,
|
|
76
|
+
failed_subscription_notifier: config.failed_subscription_notifier)
|
|
72
77
|
subscription = Subscription.using_connection(config.name).new(
|
|
73
78
|
set: @set_name, name: subscription_name, options: options, chunk_query_interval: pull_interval,
|
|
74
79
|
max_restarts_number: max_retries, time_between_restarts: retries_interval
|
|
@@ -77,7 +82,8 @@ module PgEventstore
|
|
|
77
82
|
stats: SubscriptionHandlerPerformance.new,
|
|
78
83
|
events_processor: EventsProcessor.new(create_event_handler(middlewares, handler)),
|
|
79
84
|
subscription: subscription,
|
|
80
|
-
restart_terminator: restart_terminator
|
|
85
|
+
restart_terminator: restart_terminator,
|
|
86
|
+
failed_subscription_notifier: failed_subscription_notifier
|
|
81
87
|
)
|
|
82
88
|
|
|
83
89
|
@subscription_feeder.add(runner)
|
|
@@ -102,6 +102,22 @@ module PgEventstore
|
|
|
102
102
|
erb :'subscriptions/index'
|
|
103
103
|
end
|
|
104
104
|
|
|
105
|
+
get '/subscriptions/:state' do
|
|
106
|
+
@set_collection = Subscriptions::WithState::SetCollection.new(connection, state: params[:state])
|
|
107
|
+
@current_set = params[:set_name] || @set_collection.names.first
|
|
108
|
+
subscriptions_set = Subscriptions::WithState::SubscriptionsSet.new(
|
|
109
|
+
connection, @current_set, state: params[:state]
|
|
110
|
+
).subscriptions_set
|
|
111
|
+
subscriptions = Subscriptions::WithState::Subscriptions.new(
|
|
112
|
+
connection, @current_set, state: params[:state]
|
|
113
|
+
).subscriptions
|
|
114
|
+
@association = Subscriptions::SubscriptionsToSetAssociation.new(
|
|
115
|
+
subscriptions_set: subscriptions_set,
|
|
116
|
+
subscriptions: subscriptions
|
|
117
|
+
)
|
|
118
|
+
erb :'subscriptions/index'
|
|
119
|
+
end
|
|
120
|
+
|
|
105
121
|
post '/change_config' do
|
|
106
122
|
config = params[:config]&.to_sym
|
|
107
123
|
config = :default unless PgEventstore.available_configs.include?(config)
|
|
@@ -16,7 +16,7 @@ module PgEventstore
|
|
|
16
16
|
where('context is not null and stream_name is not null').
|
|
17
17
|
group('event_type').order("event_type #{order}").limit(per_page)
|
|
18
18
|
sql_builder.where("event_type #{direction_operator} ?", starting_id) if starting_id
|
|
19
|
-
sql_builder.where('event_type ilike ?', "
|
|
19
|
+
sql_builder.where('event_type ilike ?', "%#{options[:query]}%")
|
|
20
20
|
connection.with do |conn|
|
|
21
21
|
conn.exec_params(*sql_builder.to_exec_params)
|
|
22
22
|
end.to_a
|
|
@@ -32,7 +32,7 @@ module PgEventstore
|
|
|
32
32
|
SQLBuilder.new.select('event_type').from('partitions').
|
|
33
33
|
where('context is not null and stream_name is not null').
|
|
34
34
|
where("event_type #{direction_operator} ?", starting_id).
|
|
35
|
-
where('event_type ilike ?', "
|
|
35
|
+
where('event_type ilike ?', "%#{options[:query]}%").
|
|
36
36
|
group('event_type').order("event_type #{order}").limit(1).offset(per_page)
|
|
37
37
|
|
|
38
38
|
connection.with do |conn|
|
|
@@ -12,10 +12,11 @@ module PgEventstore
|
|
|
12
12
|
@_collection ||=
|
|
13
13
|
begin
|
|
14
14
|
sql_builder =
|
|
15
|
-
SQLBuilder.new.select('context').from('partitions').
|
|
16
|
-
|
|
15
|
+
SQLBuilder.new.select('context').from('partitions').
|
|
16
|
+
where('stream_name is null and event_type is null').
|
|
17
|
+
limit(per_page).order("context #{order}")
|
|
17
18
|
sql_builder.where("context #{direction_operator} ?", starting_id) if starting_id
|
|
18
|
-
sql_builder.where('context ilike ?', "
|
|
19
|
+
sql_builder.where('context ilike ?', "%#{options[:query]}%")
|
|
19
20
|
connection.with do |conn|
|
|
20
21
|
conn.exec_params(*sql_builder.to_exec_params)
|
|
21
22
|
end.to_a
|
|
@@ -29,7 +30,7 @@ module PgEventstore
|
|
|
29
30
|
starting_id = collection.first['context']
|
|
30
31
|
sql_builder =
|
|
31
32
|
SQLBuilder.new.select('context').from('partitions').where('stream_name is null and event_type is null').
|
|
32
|
-
where("context #{direction_operator} ?", starting_id).where('context ilike ?', "
|
|
33
|
+
where("context #{direction_operator} ?", starting_id).where('context ilike ?', "%#{options[:query]}%").
|
|
33
34
|
limit(1).offset(per_page).order("context #{order}")
|
|
34
35
|
|
|
35
36
|
connection.with do |conn|
|
|
@@ -14,7 +14,7 @@ module PgEventstore
|
|
|
14
14
|
sql_builder =
|
|
15
15
|
SQLBuilder.new.select('stream_name').from('partitions').
|
|
16
16
|
where('event_type is null and context = ?', options[:context]).
|
|
17
|
-
where('stream_name ilike ?', "
|
|
17
|
+
where('stream_name ilike ?', "%#{options[:query]}%")
|
|
18
18
|
sql_builder.where("stream_name #{direction_operator} ?", starting_id) if starting_id
|
|
19
19
|
sql_builder.limit(per_page).order("stream_name #{order}")
|
|
20
20
|
connection.with do |conn|
|
|
@@ -31,7 +31,7 @@ module PgEventstore
|
|
|
31
31
|
sql_builder =
|
|
32
32
|
SQLBuilder.new.select('stream_name').from('partitions').
|
|
33
33
|
where("stream_name #{direction_operator} ?", starting_id).
|
|
34
|
-
where('stream_name ilike ?', "
|
|
34
|
+
where('stream_name ilike ?', "%#{options[:query]}%").
|
|
35
35
|
where('event_type is null and context = ?', options[:context]).
|
|
36
36
|
limit(1).offset(per_page).order("stream_name #{order}")
|
|
37
37
|
|
|
@@ -215,3 +215,14 @@ $(function(){
|
|
|
215
215
|
$(this).find('form').attr('action', $clickedLink.data('url'));
|
|
216
216
|
});
|
|
217
217
|
});
|
|
218
|
+
|
|
219
|
+
// Display subscriptions of the selected state
|
|
220
|
+
$(function(){
|
|
221
|
+
"use strict";
|
|
222
|
+
|
|
223
|
+
let $subscriptionsState = $('#subscriptions-state');
|
|
224
|
+
$subscriptionsState.change(function(){
|
|
225
|
+
let $selected = $(this).find('option:selected');
|
|
226
|
+
window.location.href = $selected.data('url');
|
|
227
|
+
});
|
|
228
|
+
});
|
|
@@ -13,6 +13,21 @@ module PgEventstore
|
|
|
13
13
|
url("/subscriptions?#{encoded_params}")
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
# @param state [String]
|
|
17
|
+
# @return [String]
|
|
18
|
+
def subscriptions_state_url(state:, **params)
|
|
19
|
+
params = params.compact
|
|
20
|
+
return url("/subscriptions/#{state}") if params.empty?
|
|
21
|
+
|
|
22
|
+
encoded_params = Rack::Utils.build_nested_query(params)
|
|
23
|
+
url("/subscriptions/#{state}?#{encoded_params}")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @return [String, nil]
|
|
27
|
+
def subscriptions_state
|
|
28
|
+
params[:state] if PgEventstore::RunnerState::STATES.include?(params[:state])
|
|
29
|
+
end
|
|
30
|
+
|
|
16
31
|
# @param set_id [Integer]
|
|
17
32
|
# @param id [Integer]
|
|
18
33
|
# @param cmd [String]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgEventstore
|
|
4
|
+
module Web
|
|
5
|
+
module Subscriptions
|
|
6
|
+
module WithState
|
|
7
|
+
class SetCollection
|
|
8
|
+
# @!attribute connection
|
|
9
|
+
# @return [PgEventstore::Connection]
|
|
10
|
+
attr_reader :connection
|
|
11
|
+
private :connection
|
|
12
|
+
|
|
13
|
+
# @param connection [PgEventstore::Connection]
|
|
14
|
+
# @param state [String]
|
|
15
|
+
def initialize(connection, state:)
|
|
16
|
+
@connection = connection
|
|
17
|
+
@state = state
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @return [Array<String>]
|
|
21
|
+
def names
|
|
22
|
+
@set_collection ||= subscription_queries.set_collection(@state)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
# @return [PgEventstore::SubscriptionQueries]
|
|
28
|
+
def subscription_queries
|
|
29
|
+
SubscriptionQueries.new(connection)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgEventstore
|
|
4
|
+
module Web
|
|
5
|
+
module Subscriptions
|
|
6
|
+
module WithState
|
|
7
|
+
class Subscriptions
|
|
8
|
+
# @!attribute connection
|
|
9
|
+
# @return [PgEventstore::Connection]
|
|
10
|
+
attr_reader :connection
|
|
11
|
+
private :connection
|
|
12
|
+
|
|
13
|
+
# @param connection [PgEventstore::Connection]
|
|
14
|
+
# @param current_set [String, nil]
|
|
15
|
+
# @param state [String]
|
|
16
|
+
def initialize(connection, current_set, state:)
|
|
17
|
+
@connection = connection
|
|
18
|
+
@current_set = current_set
|
|
19
|
+
@state = state
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @return [Array<PgEventstore::Subscription>]
|
|
23
|
+
def subscriptions
|
|
24
|
+
@subscriptions ||= subscription_queries.find_all(set: @current_set, state: @state).map do |attrs|
|
|
25
|
+
Subscription.new(**attrs)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
# @return [PgEventstore::SubscriptionQueries]
|
|
32
|
+
def subscription_queries
|
|
33
|
+
SubscriptionQueries.new(connection)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgEventstore
|
|
4
|
+
module Web
|
|
5
|
+
module Subscriptions
|
|
6
|
+
module WithState
|
|
7
|
+
class SubscriptionsSet
|
|
8
|
+
# @!attribute connection
|
|
9
|
+
# @return [PgEventstore::Connection]
|
|
10
|
+
attr_reader :connection
|
|
11
|
+
private :connection
|
|
12
|
+
|
|
13
|
+
# @param connection [PgEventstore::Connection]
|
|
14
|
+
# @param current_set [String, nil]
|
|
15
|
+
# @param state [String]
|
|
16
|
+
def initialize(connection, current_set, state:)
|
|
17
|
+
@connection = connection
|
|
18
|
+
@current_set = current_set
|
|
19
|
+
@state = state
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @return [Array<PgEventstore::SubscriptionsSet>]
|
|
23
|
+
def subscriptions_set
|
|
24
|
+
@subscriptions_set ||=
|
|
25
|
+
subscriptions_set_queries.find_all_by_subscription_state(name: @current_set, state: @state).map do |attrs|
|
|
26
|
+
PgEventstore::SubscriptionsSet.new(**attrs)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# @return [PgEventstore::SubscriptionsSetQueries]
|
|
33
|
+
def subscriptions_set_queries
|
|
34
|
+
SubscriptionsSetQueries.new(connection)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -4,6 +4,18 @@
|
|
|
4
4
|
<div class="title_left">
|
|
5
5
|
<h3>Subscriptions</h3>
|
|
6
6
|
</div>
|
|
7
|
+
<div class="title_right">
|
|
8
|
+
<div class="col-md-5 col-sm-5 form-group pull-right top_search">
|
|
9
|
+
<div class="input-group">
|
|
10
|
+
<select class="form-control" id="subscriptions-state" autocomplete="off">
|
|
11
|
+
<option value="" data-url="<%= subscriptions_url %>" <% unless subscriptions_state %> selected <% end %>>All</option>
|
|
12
|
+
<% PgEventstore::RunnerState::STATES.values.each do |state| %>
|
|
13
|
+
<option value="<%= state %>" <% if state == subscriptions_state %> selected <% end %> data-url="<%= subscriptions_state_url(state: state) %>"><%= state.capitalize %></option>
|
|
14
|
+
<% end %>
|
|
15
|
+
</select>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
7
19
|
</div>
|
|
8
20
|
|
|
9
21
|
<div class="clearfix"></div>
|
|
@@ -11,7 +23,7 @@
|
|
|
11
23
|
<ul class="nav nav-tabs bg-white">
|
|
12
24
|
<% @set_collection.names.each do |set_name| %>
|
|
13
25
|
<li class="nav-item">
|
|
14
|
-
<a class="nav-link <%= "active bg-dark text-white" if @current_set == set_name %>" href="<%= subscriptions_url(set_name: set_name) %>">
|
|
26
|
+
<a class="nav-link <%= "active bg-dark text-white" if @current_set == set_name %>" href="<%= subscriptions_state ? subscriptions_state_url(state: subscriptions_state, set_name: set_name) : subscriptions_url(set_name: set_name) %>">
|
|
15
27
|
<%= set_name %>
|
|
16
28
|
</a>
|
|
17
29
|
</li>
|
data/lib/pg_eventstore/web.rb
CHANGED
|
@@ -13,6 +13,9 @@ require_relative 'web/subscriptions/set_collection'
|
|
|
13
13
|
require_relative 'web/subscriptions/subscriptions'
|
|
14
14
|
require_relative 'web/subscriptions/subscriptions_set'
|
|
15
15
|
require_relative 'web/subscriptions/subscriptions_to_set_association'
|
|
16
|
+
require_relative 'web/subscriptions/with_state/set_collection'
|
|
17
|
+
require_relative 'web/subscriptions/with_state/subscriptions'
|
|
18
|
+
require_relative 'web/subscriptions/with_state/subscriptions_set'
|
|
16
19
|
require_relative 'web/subscriptions/helpers'
|
|
17
20
|
require_relative 'web/application'
|
|
18
21
|
|
data/pg_eventstore.gemspec
CHANGED
|
@@ -44,6 +44,8 @@ module PgEventstore
|
|
|
44
44
|
|
|
45
45
|
attr_accessor subscription_restart_terminator: _RestartTerminator?
|
|
46
46
|
|
|
47
|
+
attr_accessor failed_subscription_notifier: _FailedSubscriptionNotifier?
|
|
48
|
+
|
|
47
49
|
attr_accessor subscriptions_set_max_retries: Integer
|
|
48
50
|
|
|
49
51
|
attr_accessor subscriptions_set_retries_interval: Integer
|
|
@@ -12,7 +12,7 @@ module PgEventstore
|
|
|
12
12
|
# _@param_ `attrs`
|
|
13
13
|
def find_all: (::Hash[untyped, untyped] attrs) -> ::Array[::Hash[untyped, untyped]]
|
|
14
14
|
|
|
15
|
-
def set_collection: () -> ::Array[String]
|
|
15
|
+
def set_collection: (?String? state) -> ::Array[String]
|
|
16
16
|
|
|
17
17
|
# _@param_ `id`
|
|
18
18
|
def find!: (Integer id) -> ::Hash[untyped, untyped]
|
|
@@ -11,6 +11,8 @@ module PgEventstore
|
|
|
11
11
|
# The same as #find_all, but returns first result
|
|
12
12
|
def find_by: (::Hash[untyped, untyped] attrs) -> ::Hash[untyped, untyped]?
|
|
13
13
|
|
|
14
|
+
def find_all_by_subscription_state: (name: String?, state: String) -> ::Array[::Hash[untyped, untyped]]
|
|
15
|
+
|
|
14
16
|
# _@param_ `id`
|
|
15
17
|
def find!: (Integer id) -> ::Hash[untyped, untyped]
|
|
16
18
|
|
|
@@ -12,11 +12,14 @@ module PgEventstore
|
|
|
12
12
|
# _@param_ `subscription`
|
|
13
13
|
#
|
|
14
14
|
# _@param_ `restart_terminator`
|
|
15
|
+
#
|
|
16
|
+
# _@param_ `failed_subscription_notifier`
|
|
15
17
|
def initialize: (
|
|
16
18
|
stats: PgEventstore::SubscriptionHandlerPerformance,
|
|
17
19
|
events_processor: PgEventstore::EventsProcessor,
|
|
18
20
|
subscription: PgEventstore::Subscription,
|
|
19
|
-
?restart_terminator: _RestartTerminator
|
|
21
|
+
?restart_terminator: _RestartTerminator?,
|
|
22
|
+
?failed_subscription_notifier: _FailedSubscriptionNotifier?
|
|
20
23
|
) -> void
|
|
21
24
|
|
|
22
25
|
def next_chunk_query_opts: () -> ::Hash[untyped, untyped]
|
|
@@ -47,7 +50,7 @@ module PgEventstore
|
|
|
47
50
|
def update_subscription_chunk_stats: (Integer global_position) -> void
|
|
48
51
|
|
|
49
52
|
# _@param_ `_error`
|
|
50
|
-
def restart_subscription: (StandardError
|
|
53
|
+
def restart_subscription: (StandardError error) -> void
|
|
51
54
|
|
|
52
55
|
# Returns the value of attribute subscription.
|
|
53
56
|
attr_accessor subscription: PgEventstore::Subscription
|
|
@@ -30,7 +30,9 @@ module PgEventstore
|
|
|
30
30
|
#
|
|
31
31
|
# _@param_ `retries_interval` — a delay between retries of failed Subscription
|
|
32
32
|
#
|
|
33
|
-
# _@param_ `restart_terminator` — a callable object which
|
|
33
|
+
# _@param_ `restart_terminator` — a callable object which is invoked with PgEventstore::Subscription instance to determine whether restarts should be stopped(true - stops restarts, false - continues restarts)
|
|
34
|
+
#
|
|
35
|
+
# _@param_ `failed_subscription_notifier` - a callable object which is invoked with PgEventstore::Subscription instance and error instance after the related subscription died due to error and no longer can be automatically restarted due to max retries number reached. You can use this hook to send a notification about failed subscription.
|
|
34
36
|
def subscribe: (
|
|
35
37
|
String subscription_name,
|
|
36
38
|
handler: _SubscriptionHandler,
|
|
@@ -39,7 +41,8 @@ module PgEventstore
|
|
|
39
41
|
?pull_interval: Integer | Float,
|
|
40
42
|
?max_retries: Integer,
|
|
41
43
|
?retries_interval: Integer | Float,
|
|
42
|
-
?restart_terminator: _RestartTerminator
|
|
44
|
+
?restart_terminator: _RestartTerminator?,
|
|
45
|
+
?failed_subscription_notifier: _FailedSubscriptionNotifier?
|
|
43
46
|
) -> void
|
|
44
47
|
|
|
45
48
|
def subscriptions: () -> ::Array[PgEventstore::Subscription]
|
|
@@ -5,6 +5,10 @@ module PgEventstore
|
|
|
5
5
|
# _@param_ `set_name`
|
|
6
6
|
def subscriptions_url: (?set_name: String?) -> String
|
|
7
7
|
|
|
8
|
+
def subscriptions_state_url: (state: String, **untyped params) -> String
|
|
9
|
+
|
|
10
|
+
def subscriptions_state: -> String?
|
|
11
|
+
|
|
8
12
|
# _@param_ `set_id`
|
|
9
13
|
#
|
|
10
14
|
# _@param_ `id`
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module PgEventstore
|
|
2
|
+
module Web
|
|
3
|
+
module Subscriptions
|
|
4
|
+
module WithState
|
|
5
|
+
class SetCollection
|
|
6
|
+
@state: String
|
|
7
|
+
|
|
8
|
+
attr_reader connection: PgEventstore::Connection
|
|
9
|
+
|
|
10
|
+
def initialize: (PgEventstore::Connection connection, state: String) -> void
|
|
11
|
+
|
|
12
|
+
def names: -> Array[String]
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def subscription_queries: -> PgEventstore::SubscriptionQueries
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module PgEventstore
|
|
2
|
+
module Web
|
|
3
|
+
module Subscriptions
|
|
4
|
+
module WithState
|
|
5
|
+
class Subscriptions
|
|
6
|
+
@current_set: String?
|
|
7
|
+
|
|
8
|
+
@state: String
|
|
9
|
+
|
|
10
|
+
attr_reader connection: PgEventstore::Connection
|
|
11
|
+
|
|
12
|
+
def initialize: (PgEventstore::Connection connection, String? current_set, state: String) -> void
|
|
13
|
+
|
|
14
|
+
def subscriptions: -> Array[PgEventstore::Subscription]
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def subscription_queries: -> PgEventstore::SubscriptionQueries
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module PgEventstore
|
|
2
|
+
module Web
|
|
3
|
+
module Subscriptions
|
|
4
|
+
module WithState
|
|
5
|
+
class SubscriptionsSet
|
|
6
|
+
@current_set: String?
|
|
7
|
+
|
|
8
|
+
@state: String
|
|
9
|
+
|
|
10
|
+
attr_reader connection: PgEventstore::Connection
|
|
11
|
+
|
|
12
|
+
def initialize: (PgEventstore::Connection connection, String? current_set, state: String) -> untyped
|
|
13
|
+
|
|
14
|
+
def subscriptions_set: -> Array[PgEventstore::SubscriptionsSet]
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def subscriptions_set_queries: -> PgEventstore::SubscriptionsSetQueries
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pg_eventstore
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ivan Dzyzenko
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-
|
|
11
|
+
date: 2024-08-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: pg
|
|
@@ -42,16 +42,22 @@ dependencies:
|
|
|
42
42
|
name: sinatra
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- - "
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3'
|
|
48
|
+
- - "<"
|
|
46
49
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '
|
|
50
|
+
version: '5'
|
|
48
51
|
type: :runtime
|
|
49
52
|
prerelease: false
|
|
50
53
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
54
|
requirements:
|
|
52
|
-
- - "
|
|
55
|
+
- - ">="
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
version: '3'
|
|
58
|
+
- - "<"
|
|
53
59
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '
|
|
60
|
+
version: '5'
|
|
55
61
|
description: EventStore implementation using PostgreSQL
|
|
56
62
|
email:
|
|
57
63
|
- ivan.dzyzenko@gmail.com
|
|
@@ -182,6 +188,9 @@ files:
|
|
|
182
188
|
- lib/pg_eventstore/web/subscriptions/subscriptions.rb
|
|
183
189
|
- lib/pg_eventstore/web/subscriptions/subscriptions_set.rb
|
|
184
190
|
- lib/pg_eventstore/web/subscriptions/subscriptions_to_set_association.rb
|
|
191
|
+
- lib/pg_eventstore/web/subscriptions/with_state/set_collection.rb
|
|
192
|
+
- lib/pg_eventstore/web/subscriptions/with_state/subscriptions.rb
|
|
193
|
+
- lib/pg_eventstore/web/subscriptions/with_state/subscriptions_set.rb
|
|
185
194
|
- lib/pg_eventstore/web/views/home/dashboard.erb
|
|
186
195
|
- lib/pg_eventstore/web/views/home/partials/event_filter.erb
|
|
187
196
|
- lib/pg_eventstore/web/views/home/partials/events.erb
|
|
@@ -195,6 +204,7 @@ files:
|
|
|
195
204
|
- sig/interfaces/callback.rbs
|
|
196
205
|
- sig/interfaces/event_class_resolver.rbs
|
|
197
206
|
- sig/interfaces/event_modifier.rbs
|
|
207
|
+
- sig/interfaces/failed_subscription_notifier.rbs
|
|
198
208
|
- sig/interfaces/restart_terminator.rbs
|
|
199
209
|
- sig/interfaces/subscription_handler.rbs
|
|
200
210
|
- sig/pg/basic_type_registry.rbs
|
|
@@ -277,6 +287,9 @@ files:
|
|
|
277
287
|
- sig/pg_eventstore/web/subscriptions/subscriptions.rbs
|
|
278
288
|
- sig/pg_eventstore/web/subscriptions/subscriptions_set.rbs
|
|
279
289
|
- sig/pg_eventstore/web/subscriptions/subscriptions_to_set_association.rbs
|
|
290
|
+
- sig/pg_eventstore/web/subscriptions/with_state/set_collection.rbs
|
|
291
|
+
- sig/pg_eventstore/web/subscriptions/with_state/subscriptions.rbs
|
|
292
|
+
- sig/pg_eventstore/web/subscriptions/with_state/subscriptions_set.rbs
|
|
280
293
|
homepage: https://github.com/yousty/pg_eventstore
|
|
281
294
|
licenses:
|
|
282
295
|
- MIT
|