Bandit intercepting liveview send/2 messages
ringofhealth opened this issue · 4 comments
Hi again!
in our app, we are using liveview, and we are using send/2 and handl_info in :liveview
after switch to bandit, we been noticing that bandit is intercepting the handle_info call within the liveview
[error] GenServer #PID<0.5234.0> terminating
** (FunctionClauseError) no function clause matching in Bandit.HTTP1.Handler.handle_info/2
(bandit 1.0.0-pre.3) lib/thousand_island/handler.ex:5: Bandit.HTTP1.Handler.handle_info({:update_user_view_count, "21691d84-2656-4556-9b02-f87c3f94bbbd"}, {%ThousandIsland.Socket{socket: #Port<0.216>, transport_module: ThousandIsland.Transports.TCP, read_timeout: 60000, span: %ThousandIsland.Telemetry{span_name: :connection, telemetry_span_context: #Reference<0.2582905735.3298820105.108121>, start_time: -576455428605852008, start_metadata: %{parent_telemetry_span_context: #Reference<0.2582905735.3298820098.52671>, remote_address: {127, 0, 0, 1}, remote_port: 56410, telemetry_span_context: #Reference<0.2582905735.3298820105.108121>}}}, %{handler_module: Bandit.HTTP1.Handler, http_1_enabled: true, http_2_enabled: true, opts: %{http_1: [], http_2: [], websocket: []}, plug: {Phoenix.Endpoint.SyncCodeReloadPlug, {HelioWeb.Endpoint, []}}, requests_processed: 10, websocket_enabled: true}})
here is how the code is being called in our liveview
def mount(
%{"id" => id},
_session,
%{assigns: %{current_user: current_user}} = socket
) do
user = Accounts.get_by_username!(id)
send(self(), {:update_user_view_count, user.id})
{:ok,
socket}
end
@impl true
def handle_info({:update_user_view_count, user_id}, socket) do
# Posts.update_post_field_count({:view, post_id})
Helio.Posts.BatchCounter.Supervisor.increment_user({:view, user_id})
{:noreply, socket}
end
any guidance is appreciated
Is this a websocket or long poll based liveview?
Try it like this:
def mount(
%{"id" => id},
_session,
%{assigns: %{current_user: current_user}} = socket
) do
user = Accounts.get_by_username!(id)
if connected?(socket), do: send(self(), {:update_user_view_count, user.id})
{:ok,
socket}
end
If the LiveView isn't connected yet, your self()
will return the Bandit.DelegatingHandler
and not your LiveView.
(The message will still be send to your LiveView so your implementation will work, but the send will be called twice)
Is this a websocket or long poll based liveview?
This is websocket
Try it like this:
def mount( %{"id" => id}, _session, %{assigns: %{current_user: current_user}} = socket ) do user = Accounts.get_by_username!(id) if connected?(socket), do: send(self(), {:update_user_view_count, user.id}) {:ok, socket} endIf the LiveView isn't connected yet, your
self()
will return theBandit.DelegatingHandler
and not your LiveView. (The message will still be send to your LiveView so your implementation will work, but the send will be called twice)
will try this and report back! thank!
See https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#connected?/1 for docs on this; I think this ought to be more prominent in the live view docs (or maybe even a explicit flag that gets passed to mount) as it's an easy point of confusion.
Closing since I'm 99% sure that @moogle19's advice will work. If not, feel free to reopen!