Packages
phoenix_gen_api
2.12.0
2.22.0
2.21.1
2.21.0
2.20.1
2.20.0
2.19.0
2.18.1
2.18.0
2.17.1
2.17.0
2.16.0
2.15.0
2.14.0
2.13.0
2.12.0
2.11.0
2.10.0
2.9.1
2.9.0
2.8.0
2.7.0
2.6.1
2.6.0
2.5.0
2.4.0
2.3.0
2.2.0
2.1.1
2.1.0
2.0.1
2.0.0
1.2.0
1.1.3
1.1.2
1.1.1
1.1.0
1.0.1
1.0.0
0.2.1
0.2.0
0.1.1
0.1.0
0.0.16
0.0.15
0.0.14
0.0.13
0.0.12
0.0.11
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.3
0.0.2
0.0.1
A library for fast develop APIs in Elixir cluster, using Phoenix Channels for transport data, auto pull api configs from service nodes.
Current section
Files
Jump to
Current section
Files
lib/phoenix_gen_api/executor/stream_call.ex
defmodule PhoenixGenApi.StreamCall do
@moduledoc """
A GenServer that manages a streaming function call.
This process is responsible for executing a function that returns a stream of
results, and sending those results back to the client in chunks.
"""
use GenServer, restart: :temporary
alias PhoenixGenApi.Structs.{FunConfig, Request, Response}
alias PhoenixGenApi.Executor
require Logger
def start_link(args = %{fun_config: %FunConfig{}, request: %Request{}, receiver: nil}) do
receiver = self()
start_link(Map.put(args, :receiver, receiver))
end
def start_link(args = %{fun_config: %FunConfig{}, request: %Request{}, receiver: receiver})
when is_pid(receiver) do
case GenServer.start_link(__MODULE__, args) do
{:ok, pid} ->
Process.put({:phoenix_gen_api, :stream_call_pid, args.request.request_id}, pid)
{:ok, pid}
{:error, reason} ->
{:error, reason}
end
end
def stop(pid) when is_pid(pid) do
GenServer.cast(pid, :stop)
end
def stop(request_id) when is_binary(request_id) do
case Process.get({:phoenix_gen_api, :stream_call_pid, request_id}) do
nil ->
Logger.warning(
"PhoenixGenApi.StreamCall, stop, not found stream for request_id: #{inspect(request_id)}"
)
{:error, :not_found}
pid when is_pid(pid) ->
Logger.debug("PhoenixGenApi.StreamCall, stop, stream call pid: #{inspect(pid)}")
stop(pid)
end
end
### GenServer Callbacks
@impl true
def init(args) do
{:ok, args, {:continue, :start_stream}}
end
@impl true
def handle_continue(:start_stream, state) do
result = Executor.sync_call(state.request, state.fun_config)
if Response.error?(result) do
send(state.receiver, {:stream_response, result})
{:stop, :normal, state}
else
send(
state.receiver,
{:stream_response, Response.stream_response(state.request.request_id, result)}
)
{:noreply, state}
end
end
@impl true
def handle_cast(:stop, state) do
send_completion(state)
{:stop, :normal, state}
end
@impl true
def handle_info({:result, result}, state) do
send(
state.receiver,
{:stream_response, Response.stream_response(state.request.request_id, result)}
)
{:noreply, state}
end
def handle_info({:last_result, result}, state) do
send(
state.receiver,
{:stream_response, Response.stream_response(state.request.request_id, result, false)}
)
{:stop, :normal, state}
end
def handle_info({:error, error}, state) do
error_message =
if Application.get_env(:phoenix_gen_api, :detail_error, false) do
"Internal Server Error: #{inspect(error)}"
else
"Internal Server Error"
end
send(
state.receiver,
{:stream_response, Response.error_response(state.request.request_id, error_message)}
)
{:stop, :normal, state}
end
def handle_info(:complete, state) do
send_completion(state)
{:stop, :normal, state}
end
def handle_info(unknown, state) do
Logger.warning("PhoenixGenApi.StreamCall, received unknown message: #{inspect(unknown)}")
{:noreply, state}
end
@impl true
def terminate(reason, state) do
Logger.debug(
"PhoenixGenApi.StreamCall, terminating for request_id: #{state.request.request_id}, reason: #{inspect(reason)}"
)
:ok
end
defp send_completion(state) do
send(
state.receiver,
{:stream_response, Response.stream_end_response(state.request.request_id)}
)
end
end