Skip to content

Latest commit

 

History

History
123 lines (97 loc) · 11 KB

File metadata and controls

123 lines (97 loc) · 11 KB

Configuration

Configuration options:

name value default value description
pg_uri String 'postgresql://postgres:postgres@localhost:5432/eventstore' PostgreSQL connection string. See PostgreSQL docs for more information.
max_count Integer 1000 Number of events to return in one response when reading from a stream.
middlewares Array {} A hash where a key is a name of your middleware and value is an object that respond to #serialize and #deserialize methods. See Writing middleware chapter.
event_class_resolver #call PgEventstore::EventClassResolver.new A #call-able object that accepts a string and returns an event's class. See Resolving events classes chapter bellow for more info.
connection_pool_size Integer 5 Max number of connections per ruby process. It must equal the number of threads of your application. When using subscriptions it is recommended to set it to the number of subscriptions divided by two or greater. See Picking max connections number chapter of this section.
connection_pool_timeout Integer 5 Time in seconds to wait for a connection in the pool to be released. If no connections are available during this time - ConnectionPool::TimeoutError will be raised. See connection_pool gem docs for more info.
subscription_pull_interval Float 1.0 How often to pull new subscription events in seconds. The minimum meaningful value is 0.2. Values less than 0.2 will act as it is 0.2.
subscription_max_retries Integer 5 Max number of retries of failed subscription.
subscription_retries_interval Integer 1 Interval in seconds between retries of failed subscriptions.
subscriptions_set_max_retries Integer 10 Max number of retries for failed subscription sets.
subscriptions_set_retries_interval Integer 1 Interval in seconds between retries of failed subscription sets.
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).
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.
subscription_graceful_shutdown_timeout Integer, Float 15 The number of seconds to wait until force-shutdown the subscription during the stop process. If your subscription handler does not finish current event processing during this time(for example because of heavy-lifting task) - it will be force-shutdown.

Multiple configurations

pg_eventstore allows you to have as many configs as you want. This allows you, for example, to have different databases, or to have a different set of middlewares for specific cases only. To do so, you have to name your configuration, and later provide that name to PgEventstore client.

Setup your configs:

PgEventstore.configure(name: :pg_db_1) do |config|
  # adjust your config here
  config.pg_uri = 'postgresql://postgres:postgres@localhost:5432/eventstore'
end
PgEventstore.configure(name: :pg_db_2) do |config|
  # adjust your second config here
  config.pg_uri = 'postgresql://postgres:postgres@localhost:5532/eventstore'
end

Tell PgEventstore which config you want to use:

# Read from "all" stream using :pg_db_1 config
PgEventstore.client(:pg_db_1).read(PgEventstore::Stream.all_stream)
# Read from "all" stream using :pg_db_2 config
PgEventstore.client(:pg_db_2).read(PgEventstore::Stream.all_stream)
# Delete a stream using :pg_db_1 config
stream = PgEventstore::Stream.new(context: 'FooCtx', stream_name: 'MyStream', stream_id: '1')
PgEventstore.maintenance.delete_stream(stream)

Default config

If you have one config only - you don't have to bother naming it or passing a config name to the client when performing any operations. You can configure it as usual.

Setup your default config:

PgEventstore.configure do |config|
  # config goes here
  config.pg_uri = 'postgresql://postgres:postgres@localhost:5432/eventstore'
end

Use it:

# Read from "all" stream using your default config
EventStoreClient.client.read(PgEventstore::Stream.all_stream)

Resolving event classes

During the deserialization process pg_eventstore tries to pick the correct class for an event. By default it does it using the PgEventstore::EventClassResolver class. All it does is Object.const_get(event_type). By default, if you don't provide the type attribute for an event explicitly, it will grab the event's class name, meaning by default:

  • event's type is event's class name
  • when instantiating an event - pg_eventstore tries to lookup an event class based on the value of event's type attribute with a fallback to PgEventstore::Event class

You can override the default event class resolver by providing any #call-able object. It should accept event's type and return event's class based on it. Example:

PgEventstore.configure do |config|
  config.event_class_resolver = proc { |event_type| Object.const_get(event_type.gsub('Foo', 'Bar')) rescue PgEventstore::Event }
end

Picking max connections number

A connection is hold from the connection pool to perform the request and it is released back to the connection pool once the request is finished. If you run into the (theoretical) edge case, when all your application's threads (or subscriptions) are performing pg_eventstore queries at the same time and all those queries take more than connection_pool_timeout seconds to complete, you have to have connection_pool_size set to the exact amount of your application's threads (or to the number of subscriptions when using subscriptions) to prevent timeout errors. Practically this is not the case, as all pg_eventstore queries are pretty fast. So, a good value for the connection_pool_size option is **half the number ** of your application's threads(or half the number of Subscriptions).

Exception scenario

If you are using the #multiple method - you have to take into account the execution time of the whole block you pass in it. This is because the connection will be released only after the block's execution is finished. So, for example, if you perform several commands within the block, as well as some API request, the connection will be release only after all those steps:

PgEventstore.client.multiple do
  # Connection is hold from the connection pool
  PgEventstore.client.read(some_stream)
  Stripe::Payment.create(some_attrs)
  PgEventstore.client.append_to_stream(some_stream, some_event)
  # Connection is released
end

Taking this into account you may want to increase connection_pool_size up to the number of your application's threads( or subscriptions).