All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Note: certain Spear versions add support for new EventStoreDB features gated behind new EventStoreDB versions. You should not downgrade your Spear version in order to avoid these features: Spear aims to keep a stable interface usable across all EventStoreDB versions v20+.
- Enabled
nodelay: trueon the TCP transport by default to disable Nagle's algorithm, reducing latency for the small request/response messages exchanged with the EventStoreDB.- This default can be overridden via
mint_opts: [transport_opts: [nodelay: false]].
- This default can be overridden via
- Fixed the format of output returned by
Spear.append/3when passing the optionraw?: true.- Previously this function returned
:okwith this option. It now returns{:ok, AppendResp.t()}with the append response record from the server.
- Previously this function returned
Spear.stream!/3now saves one network request when the server returns fewer events than the requested chunk size.- Subscriptions now send
{:caught_up, subscription_ref}and{:fell_behind, subscription_ref}messages on EventStoreDB versions later than 23.10.
- A single HTTP/2 DATA frame might contain multiple messages from the EventStoreDB. Previously only the first message was handled at a time and the remaining data was buffered. Now all messages in a DATA frame are sent eagerly.
- Fixed a crash on start-up when Application environment values were not
set for a
Spear.Clientmodule usinguse Spear.Client. - Improved documentation for event metadata.
- HTTP/2 window size is now properly checked in
Spear.Connectionbefore attempting to send ack, nack, and batch-append messages.- Without this fix, some ack, nack and batch-append messages could be silently dropped on busy connections.
- Added documentation for setting up connection pools.
- Added
:on_connectand:on_disconnecthook options forSpear.Connectionwhich can be used for pooling.
- Fixed the return values for
Spear.subscribe/4when the subscription request fails.
For example, if a connection is made with an invalid password, Spear.subscribe/4
would previously return {:ok, %Spear.Connection.Response{}} (an internal
struct). Now Spear.subscribe/4 returns {:error, %Spear.Grpc.Response{}}.
- Added support for Persistent Subscription RPCs introduced in
server version 22.6.0:
Spear.get_persistent_subscription_info/4Spear.replay_parked_messages/4Spear.restart_persistent_subscription_subsystem/2
- A duration may now be specified for the
:deadlineoption toSpear.append_batch/5- Passing a duration (instead of a timestamp) requires EventStoreDB version 21.10.5 or higher
0may now be passed in the:expectoption when appending or batch appending
- Fixed
Spear.stream!/3when providing a:fromevent number that does not existSpear.stream!/3gives the empty list in this case
This release represent stability in the API. There are no functional changes between this release and v0.11.0.
- Added the
:filteroption toSpear.read_stream/3andSpear.stream!/3- This allows one to perform a non-subscription read of the
$allstream and use a server-side filter
- This allows one to perform a non-subscription read of the
- Added
Spear.get_supported_rpcs/2andc:Spear.Client.get_supported_rpcs/1for getting the available RPC methods implemented in the connected EventStoreDB server - Added
Spear.get_server_version/2andc:Spear.Client.get_server_version/2for getting the version string of the connected EventStoreDB Server
These features require the new EventStoreDB version v21.10.0 released on 2021-11-03.
- According to the v21.10.0 server release notes's breaking changes section, deleting a stream that does not currently exist will now throw an error
- Implemented the creation, updating, reading, and deletion of persistent
subscriptions to the
:allstream- this feature requires EventStoreDB v21.6.0 or later
- Implemented
Spear.append_batch/5for high-throughput asynchronous appends- this feature requires EventStoreDB v21.6.0 or later
Spear.append_batch_stream/2has also been added for convenience
- Added
Spear.subscribe_to_stats/3andc:Spear.Client.subscribe_to_stats/2- this opens a subscription for EventStoreDB monitoring
- this feature requires EventStoreDB v21.6.0 or later
- Added a dependency on the
:event_store_db_gpb_protobfspackage- this package is just a convenience for developing spear: we can build gpb definitions for the EventStoreDB protobufs on-the-fly via the rebar3 gpb plugin, so we never need to commit the erl/hrl files for the generated gpb modules.
- this also allows other (non-Elixir even) libraries to take advantage of versioned, pre-generated gpb definitions for the EventStoreDB grpc interface
- Non-event read responses are now discarded when reading from a stream
- this will allow the compatibility of spear v0.10.0 with the next release of EventStoreDB
- this should not change behavior with any existing EventStoreDB versions
- Fixed the
Spear.set_global_acl/4function to correctly append ACL data as an event to the$streamsmetadata stream, instead of to the$streamsstream directly.
- Added
Spear.park_stream/2to the utilities API
- Removed compilation of mint version in user-agent function
- This could cause a compilation error when using spear as a transitive dependency
- Added a
:linkfield to thet:Spear.Event.t/0struct- this is used to provide accurate stream revisions and IDs in projected
streams as with
Spear.subscribe/4or inSpear.ack/3orSpear.nack/4
- this is used to provide accurate stream revisions and IDs in projected
streams as with
- Added
Spear.Event.id/1andSpear.Event.revision/1which take at:Spear.Event.t/0and give the ID and revision, respectively- these new functions respect the new
:linkfield and return link information instead of event information if the link is present
- these new functions respect the new
- Removed link metadata from the
Spear.Event.metadatamap's possible:linkfield.- use the new top-level
:linkfield asSpear.Event.link.metadata
- use the new top-level
Note that this may be a breaking change for any consumers depending on the
optional :link field in the metadata packet. Consumers should update by
instead matching on a t:Spear.Event.t/0 struct in the :link field of any
event, or by using the new Spear.Event.id/1 or Spear.Event.revision/1
functions.
- Added the link's stream to the
Spear.Event.metadata.linkfield
- Fixed some stray references to structs which should be typed as records
- Fixed
Spear.Event.to_checkpoint/1to carry over the:subscriptionkey from at:Spear.Event.t/0's metadata - Fixed a bug in
Spear.Connection.Configurationwhich would incorrectly choose the:httpscheme when the:tls?option was set totrue
- Added the
:read_only?configuration flag forSpear.Connection.Configuration- this allows one to limit what the
Spear.Connectionwill perform to read-only operations such as reading streams
- this allows one to limit what the
- Added link metadata to the
Spear.Event.metadatapacket in a new:linkfield
- Fixed the
:fromoption in read requests (Spear.read_stream/3,Spear.stream!/3andSpear.subscribe/4) to respect the new link information in metadata
- Added the subscription reference returned by
Spear.subscribe/4andSpear.connect_to_persistent_subscription/5to- the metadata map of
t:Spear.Event.t/0in the pathSpear.Event.metadata.subscription t:Spear.Filter.Checkpoint.t/0in a new field:subscription- the
:eostuples in the new shape of{:eos, reference(), :closed | :dropped}
- the metadata map of
Note that this is a breaking change for any consumers matching explicitly
on :eos tuples. Consumers relying on the prior data shape should update
like so
- def handle_info({:eos, reason}, state) do
+ def handle_info({:eos, _subscription, reason}, state) doSpear.stream!/3now reads:fromrevisions as inclusive- e.g. passing some
eventin the stream to:fromwill ensure that the first element in the enumerable is^event - the same principal applies when passing event revisions
- see #26
- if this behavior is undesirable, a Spear user may
Stream.drop/2the initial element in the enumerable
- e.g. passing some
Spear.connect_to_persistent_subscription/5now returns an error tuple when attempting to connect to a persistent subscription stream and group that has not yet been created.- the reason is a
Spear.Grpc.Responsestruct with a status of:not_found
- the reason is a
- Subscriptions may now emit
{:eos, :dropped}in cases where the EventStoreDB explicitly terminates the subscription- this can happen if a persistent subscription is deleted while it has subscribers actively connected
- each subscriber will receive
{:eos, :dropped}in its mailbox
- Added the CRUD portions of persistent subscriptions API
Spear.create_persistent_subscription/5Spear.update_persistent_subscription/5Spear.delete_persistent_subscription/4Spear.list_persistent_subscriptions/2- associated callbacks in
Spear.Client
- Added subscription functionality for persistent subscriptions
Spear.connect_to_persistent_subscription/5Spear.ack/3Spear.nack/4- associated callbacks in
Spear.Client
- Moved
Spear.cancel_subscription/3under the utils API instead of streams- This function may also be used to cancel persistent subscriptions
- Added the gossip API
- this API is very small: just one function
Spear.cluster_info/2 - also added
c:Spear.Client.cluster_info/1 - under the hood, this also added the ability to decode structured
UUIDs received from the EventStoreDB, as are received in the
Spear.ClusterMember.instance_idfield. SeeSpear.Uuidfor the interesting implementation. - added the record interface
Spear.Records.Gossip
- this API is very small: just one function
- Properly grouped free-floating modules under the proper structures and types or record interface groupings in the documentation
- Updated security guide to use new configuration style
- Added the operations API
Spear.merge_indexes/2Spear.resign_node/2Spear.restart_persistent_subscriptions/2Spear.set_node_priority/3Spear.shutdown/2Spear.start_scavenge/2Spear.stop_scavenge/3- and associated wrappers in
Spear.Client
- Added record interface modules for all remaining APIs
- Added functions for interacting with the Users API
Spear.change_user_password/5Spear.create_user/6Spear.delete_user/3Spear.disable_user/3Spear.enable_user/3Spear.reset_user_password/4Spear.update_user/6Spear.user_details/3- associated functions in
Spear.Client
- Wrapped new ACL-related functions in
Spear.Clientc:Spear.Client.get_stream_metadata/2c:Spear.Client.set_stream_metadata/2c:Spear.Client.set_global_acl/3
- Refactored connection configuration to go through validation
:optsoption has been renamed to:mint_opts- credentials are passed through the
:connection_stringoption or as:usernameand:passwordoptions
- Implemented and documented keep-alive
- This can be configured through the
keepAliveIntervalandkeepAliveTimeoutquery params in:connection_stringor by the new:keep_alive_intervaland:keep_alive_timeoutconfiguration options
- This can be configured through the
{:eos, :closed}is now emitted when a subscription is broken due to the connection between closed betweenSpear.Connectionand EventStoreDBSpear.Connectionnow monitors subscription processes and cancels EventStoreDB subscriptions upon subscriber process exit
- Added documentation and functionality for using TLS certificates
- see
Spear.Connectionand the security guide
- see
- Added documentation and functionality for setting the global stream ACL
- see
Spear.set_global_acl/4and theSpear.Aclmodule
- see
- Added functionality for getting and setting stream-level metadata.
Spear.meta_stream/1Spear.get_stream_metadata/3Spear.set_stream_metadata/3Spear.StreamMetadata
- Added dependency on
connection - Added ping functionality for
Spear.ConnectionsSpear.ping/1andSpear.ping/2c:Spear.Client.ping/0andc:Spear.Client.ping/1
- Added the ability to disconnect a connection by
GenServer.call/3ing it with:closeas the message - Added the ability to explicitly reconnect a connection by
GenServer.cast/2ing it a message of:connect
- Changed the internals of
Spear.Connectionto take advantage of the newConnectiondependency- A failure to connect on GenServer init for a connection will no longer take down the supervision tree
- Failures to connect will result in back-off retries in 500ms segments
- The life-cycle of the HTTP2 connection spawned by a
Spear.Connectionis now divorced from the life-cycle of theSpear.Connectionprocess
- Removed dependency on
elixir-protobuf/protobuf- see #4
- also removed all generated files from protobuf
- Added dependency on
:gpb- and associated generated erlang files
- Added
Spear.Records.*interface for interacting with gpb-generated records
- Initial implementation of a client for the streams API
- all notable functions are labeled with the
since: "0.1.0"doc attribute
- all notable functions are labeled with the