Packages
Subscription support via Phoenix for Absinthe, the GraphQL implementation for Elixir.
Current section
Files
Jump to
Current section
Files
lib/absinthe/phoenix/socket.ex
defmodule Absinthe.Phoenix.Socket do
@moduledoc ~S"""
`Absinthe.Phoenix.Socket` is used as a module for setting up a control
channel for handling GraphQL subscriptions.
## Examples
defmodule MyApp.Web.UserSocket do
use Phoenix.Socket
use Absinthe.Phoenix.Socket,
schema: MyApp.Web.Schema
transport :websocket, Phoenix.Transports.WebSocket
def connect(params, socket) do
socket = Absinthe.Phoenix.Socket.put_options(socket, [
context: %{current_user: find_current_user(params)}
])
{:ok, socket}
end
def id(_socket), do: nil
end
## Phoenix 1.2
If you're on Phoenix 1.2 see `put_schema/2`.
## Garbage Collection
In some workloads, the Channel Process responsible for handling [subscriptions may accumulate
some gargage](https://elixirforum.com/t/why-does-garbage-collection-not-work-as-intended/50613/2), that is not being collected by the Erlang VM. A workaround for this is to instruct
the process to periodically tell the VM to collect its garbage. This can be done by setting the
`gc_interval`.
use Absinthe.Phoenix.Socket,
schema: MyApp.Web.Schema,
gc_interval: 10_000
"""
defmacro __using__(opts) do
opts =
if Macro.quoted_literal?(opts) do
Macro.prewalk(opts, &expand_alias(&1, __CALLER__))
else
opts
end
schema = Keyword.get(opts, :schema)
pipeline = Keyword.get(opts, :pipeline)
gc_interval = Keyword.get(opts, :gc_interval)
quote do
channel(
"__absinthe__:*",
Absinthe.Phoenix.Channel,
assigns: %{
__absinthe_schema__: unquote(schema),
__absinthe_pipeline__: unquote(pipeline),
__absinthe_gc_interval__: unquote(gc_interval)
}
)
end
end
@doc """
Configure Absinthe options for a socket.
## Examples
def connect(params, socket) do
current_user = current_user(params)
socket = Absinthe.Phoenix.Socket.put_options(socket, context: %{
current_user: current_user
})
{:ok, socket}
end
defp current_user(%{"user_id" => id}) do
MyApp.Repo.get(User, id)
end
"""
@spec put_options(Phoenix.Socket.t(), Absinthe.run_opts()) :: Phoenix.Socket.t()
def put_options(socket, opts) do
absinthe_assigns =
socket.assigns
|> Map.get(:absinthe, %{})
|> Map.put(:opts, opts)
Phoenix.Socket.assign(socket, :absinthe, absinthe_assigns)
end
@doc false
@deprecated "Use put_options/2 instead."
def put_opts(socket, opts) do
put_options(socket, opts)
end
@doc """
Configure the schema for a socket.
Only use this if you are not yet on Phoenix 1.3. If you're on Phoenix 1.3,
read the moduledocs.
"""
@spec put_schema(Phoenix.Socket.t(), Absinthe.Schema.t()) :: Phoenix.Socket.t()
def put_schema(socket, schema) do
absinthe_assigns =
socket.assigns
|> Map.get(:absinthe, %{})
|> Map.put(:schema, schema)
Phoenix.Socket.assign(socket, :absinthe, absinthe_assigns)
end
defp expand_alias({:__aliases__, _, _} = alias, env),
do: Macro.expand(alias, %{env | function: {:__using__, 1}})
defp expand_alias(other, _env), do: other
end