Current section

Files

Jump to
extreme lib extreme shared_subscription.ex
Raw

lib/extreme/shared_subscription.ex

defmodule Extreme.SharedSubscription do
@moduledoc """
This module contains functions shared between `Extreme.Subscription` and `Extreme.ReadingSubscription`.
"""
alias Extreme.RequestManager
alias Extreme.Messages, as: Msg
require Logger
@doc """
Sends subscription request and waits for positive response. Returns `{:ok, subscription_confirmation}`.
"""
def subscribe(state) do
message =
Msg.SubscribeToStream.new(
event_stream_id: state.read_params.stream,
resolve_link_tos: state.read_params.resolve_link_tos
)
{:ok, subscription_confirmation} =
state.base_name
|> RequestManager.execute(message, state.correlation_id)
Logger.debug(fn ->
"Successfully subscribed to stream #{inspect(subscription_confirmation)}"
end)
{:ok, subscription_confirmation}
end
@doc """
Sends unsubscribe "fire and forget" request to EventStoreDB.
"""
def unsubscribe(state) do
spawn_link(fn ->
message = Msg.UnsubscribeFromStream.new()
:ok =
state.base_name
|> RequestManager.execute(message, state.correlation_id)
:ok =
state.base_name
|> RequestManager.unregister_subscription(state.correlation_id)
end)
:ok
end
@doc """
Executes `fun` function for decoding response and responds on that message.
"""
def process_push(fun, state), do: fun.() |> _process_push(state)
@doc """
Calls subscriber with {:on_event, event}, expecting :ok as result
in order to apply backpressure.
"""
def on_event(subscriber, event, ack_timeout),
do: GenServer.call(subscriber, {:on_event, event}, ack_timeout)
defp _process_push(
{_auth, _correlation_id,
%Msg.StreamEventAppeared{
event: %Msg.ResolvedEvent{event: %Msg.EventRecord{event_type: "$streamDeleted"}}
}},
state
) do
send(state.subscriber, {:extreme, :stream_hard_deleted})
RequestManager.unregister_subscription(state.base_name, state.correlation_id)
{:stop, {:shutdown, :stream_hard_deleted}, state}
end
defp _process_push(
{_auth, _correlation_id, %Msg.StreamEventAppeared{} = e},
state
) do
state.subscriber
|> on_event(e.event, state.read_params.ack_timeout)
|> case do
:ok ->
{:noreply, state}
:stop ->
Logger.info("Processing of event requested stopping subscription")
RequestManager.unregister_subscription(state.base_name, state.correlation_id)
{:stop, {:shutdown, :processing_of_event_requested_stopping_subscription}, state}
end
end
defp _process_push(
{_auth, _correlation_id, %Msg.SubscriptionDropped{reason: reason}},
state
) do
send(state.subscriber, {:extreme, reason})
RequestManager.unregister_subscription(state.base_name, state.correlation_id)
{:stop, {:shutdown, reason}, state}
end
defp _process_push(
{_auth, _correlation_id,
%Msg.PersistentSubscriptionConfirmation{subscription_id: subscription_id} = confirmation},
state
) do
Logger.debug(fn -> "Successfully subscribed #{inspect(confirmation)}" end)
{:noreply, %{state | status: :subscribed, subscription_id: subscription_id}}
end
defp _process_push(
{_auth, correlation_id, %Msg.PersistentSubscriptionStreamEventAppeared{} = e},
state
) do
:ok = GenServer.cast(state.subscriber, {:on_event, e.event, correlation_id})
{:noreply, state}
end
end