Packages
extreme
0.13.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