Packages
gnat
1.8.5
1.16.0
1.15.2
1.15.1
1.15.0
1.14.1
1.14.0
1.14.0-rc1
1.14.0-rc0
1.13.1
1.13.0
1.12.1
1.12.0
1.11.1
1.11.0
1.10.2
1.10.2-rc1
1.10.2-rc0
1.10.1
1.10.0
1.9.1
1.9.0
1.8.5
1.8.4
1.8.3
1.8.2
1.8.1
1.7.1
1.7.0
1.6.0
1.5.2
1.5.1
1.5.0
1.4.0
1.3.0
1.3.0-rc0
1.2.1
1.2.0
1.1.3
1.1.2
1.1.1
1.1.0
1.0.1
1.0.0
0.7.0
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.2
0.4.1
0.4.0
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
0.1.3
0.1.2
0.1.1
0.1.0
A nats client in pure elixir. Resilience, Performance, Ease-of-Use.
Current section
Files
Jump to
Current section
Files
lib/gnat/server.ex
defmodule Gnat.Server do
require Logger
@moduledoc """
A behavior for acting as a server for nats messages.
You can use this behavior in your own module and then use the `Gnat.ConsumerSupervisor` to listen for and respond to nats messages.
## Example
defmodule MyApp.RpcServer do
use Gnat.Server
def request(%{body: _body}) do
{:reply, "hi"}
end
# defining an error handler is optional, the default one will just call Logger.error for you
def error(%{gnat: gnat, reply_to: reply_to}, _error) do
Gnat.pub(gnat, reply_to, "Something went wrong and I can't handle your request")
end
end
"""
@doc """
Called when a message is received from the broker
"""
@callback request(message::Gnat.message()) :: :ok | {:reply, iodata()} | {:error, term()}
@doc """
Called when an error occured during the `request/1`
If your `request/1` function returned `{:error, term}`, then the `term` you returned will be passed as the second argument.
If an exception was raised during your `request/1` function, then the exception will be passed as the second argument.
If your `request/1` function returned something other than the supported return types, then its return value will be passed as the second argument.
"""
@callback error(message::Gnat.message(), error::term()) :: :ok | {:reply, iodata()}
defmacro __using__(_opts) do
quote do
@behaviour Gnat.Server
def error(_message, error) do
require Logger
Logger.error(
"Gnat.Server encountered an error while handling a request: #{inspect(error)}",
type: :gnat_server_error,
error: error
)
end
defoverridable error: 2
end
end
# The functions below are not documented because they are used internally to run
# the callback modules
@doc false
def execute(module, message) do
try do
case apply(module, :request, [message]) do
:ok -> :done
{:reply, data} -> send_reply(message, data)
{:error, error} -> execute_error(module, message, error)
other -> execute_error(module, message, other)
end
rescue e ->
execute_error(module, message, e)
end
end
@doc false
defp execute_error(module, message, error) do
try do
case apply(module, :error, [message, error]) do
:ok -> :done
{:reply, data} -> send_reply(message, data)
other ->
Logger.error(
"error handler for #{module} returned something unexpected: #{inspect(other)}",
type: :gnat_server_error
)
end
rescue e ->
Logger.error(
"error handler for #{module} encountered an error: #{inspect(e)}",
type: :gnat_server_error
)
end
end
@doc false
def send_reply(%{gnat: gnat, reply_to: return_address}, iodata) when is_binary(return_address) do
Gnat.pub(gnat, return_address, iodata)
end
def send_reply(_other, _iodata) do
Logger.error(
"Could not send reply because no reply_to was provided with the original message",
type: :gnat_server_error
)
end
end