Packages
extreme
0.10.3
1.1.4
1.1.3
1.1.2
1.1.1
1.1.1-rc01
1.1.0
1.1.0-rc9
1.1.0-rc8
1.1.0-rc7
1.1.0-rc6
1.1.0-rc5
1.1.0-rc4
1.1.0-rc3
1.1.0-rc2
1.1.0-rc1
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.13.4
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.0
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.2
0.9.1
0.9.0
0.8.1
0.8.0
0.7.1
0.7.0
0.6.2
0.6.1
0.6.0
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
Elixir TCP client for EventStore.
Current section
Files
Jump to
Current section
Files
lib/persistent_subscription.ex
defmodule Extreme.PersistentSubscription do
use GenServer
require Logger
alias Extreme.Msg, as: ExMsg
def start_link(connection_settings, subscriber, params) do
GenServer.start_link(__MODULE__, {connection_settings, subscriber, params})
end
def init({connection_settings, subscriber, {subscription, stream, buffer_size}}) do
state = %{
connection_settings: connection_settings,
subscriber: subscriber,
subscription_ref: Process.monitor(subscriber),
subscription_id: nil,
connection: nil,
params: %{subscription: subscription, stream: stream, buffer_size: buffer_size},
status: :initialized,
}
GenServer.cast(self(), :connect)
{:ok, state}
end
# confirm receipt of an event
def ack(subscription, %{link: link}, correlation_id) when not is_nil(link) do
GenServer.call(subscription, {:ack, link.event_id, correlation_id})
end
def ack(subscription, %{event: event}, correlation_id) when not is_nil(event) do
GenServer.call(subscription, {:ack, event.event_id, correlation_id})
end
def ack(subscription, event_id, correlation_id) when is_binary(event_id) do
GenServer.call(subscription, {:ack, event_id, correlation_id})
end
def nack(_, _, _, _, message \\ nil)
def nack(subscription, %{link: link}, correlation_id, nack_action, message) when not is_nil(link) and is_atom(nack_action) do
GenServer.call(subscription, {:nack, link.event_id, correlation_id, nack_action, message})
end
def nack(subscription, %{event: event}, correlation_id, nack_action, message) when is_atom(nack_action) do
GenServer.call(subscription, {:nack, event.event_id, correlation_id, nack_action, message})
end
def handle_cast(:connect, %{connection_settings: connection_settings, params: params} = state) do
# create a connection to the event store for this persistent subscription
{:ok, connection} = Extreme.start_link(connection_settings)
{:ok, %ExMsg.PersistentSubscriptionConfirmation{subscription_id: subscription_id}} = GenServer.call(connection, {:subscribe, self(), connect(params)})
Logger.debug(fn -> "Successfully connected to persistent subscription id: #{inspect subscription_id}" end)
{:noreply, %{state | connection: connection, subscription_id: subscription_id, status: :subscribed}}
end
def handle_cast({:ok, %ExMsg.PersistentSubscriptionStreamEventAppeared{event: event} = msg, correlation_id}, %{subscription_id: subscription_id, subscriber: subscriber} = state) do
Logger.debug(fn -> "Persistent subscription #{inspect subscription_id} event appeared: #{inspect msg} correlation_id: #{inspect correlation_id}" end)
send(subscriber, {:on_event, event, correlation_id})
{:noreply, state}
end
def handle_cast({:ok, %ExMsg.SubscriptionDropped{ reason: :Unsubscribed}}, %{subscription_id: subscription_id} = state) do
Logger.info(fn -> "Stopping persistent subscription #{inspect subscription_id} as subscriber has been unsubscribed" end)
{:stop, {:shutdown, :subscriber_down}, state}
end
def handle_call({:ack, event_id, correlation_id}, _from, %{connection: connection, subscription_id: subscription_id} = state) do
Logger.debug(fn -> "Persistent subscription #{inspect subscription_id} ack event id: #{inspect event_id} correlation_id: #{inspect correlation_id}" end)
:ok = GenServer.call(connection, {:ack, ack_event(subscription_id, event_id), correlation_id})
{:reply, :ok, state}
end
def handle_call({:nack, event_id, correlation_id, nack_action, message}, _from, %{connection: connection, subscription_id: subscription_id} = state) do
Logger.debug(fn -> "Persistent subscription #{inspect subscription_id} nack event id: #{inspect event_id} correlation_id: #{inspect correlation_id} nack_action: #{inspect nack_action}" end)
:ok = GenServer.call(connection, {:nack, nack_event(subscription_id, event_id, nack_action, message), correlation_id})
{:reply, :ok, state}
end
# stop persistent subscription process when subscriber process is down
def handle_info({:DOWN, ref, :process, _pid, reason}, %{subscription_ref: ref, subscription_id: subscription_id} = state) do
Logger.info(fn -> "Stopping persistent subscription #{inspect subscription_id} as subscriber is down due to: #{inspect reason}" end)
{:stop, {:shutdown, :subscriber_down}, state}
end
defp connect(params) do
ExMsg.ConnectToPersistentSubscription.new(
subscription_id: params.subscription,
event_stream_id: params.stream,
allowed_in_flight_messages: params.buffer_size
)
end
defp nack_event(subscription_id, event_id, nack_action, message) do
ExMsg.PersistentSubscriptionNakEvents.new(
subscription_id: subscription_id,
processed_event_ids: [event_id],
message: message,
action: nack_action
)
end
defp ack_event(subscription_id, event_id) do
ExMsg.PersistentSubscriptionAckEvents.new(
subscription_id: subscription_id,
processed_event_ids: [event_id]
)
end
end