Experiencing delay when trying to push_redirect from one LiveView to another

I’m trying to push_redirect from one LiveView to another. It’s working BUT… there’s a seconds long delay until the browser refeshes and renders the new LiveView. What am I missing?

Push_redirect

Logger.info "pushing query"
{:noreply, socket |> push_redirect(to:  Routes.live_path(socket, DemoWeb.ResultsView, query ))}

In the ResultsView LiveView:

def handle_params(%{"query" => query}, _url, socket) do
  Logger.info "handling query"
  {:noreply, socket |> assign(query: query) |> fetch()}
end

The logging looks like this…

12:07:54.013: [info] pushing query

12:07:54.022: [info] handling query. #<- render not triggered

12:08:00.565: [info] GET /results/duk # <- render refreshes and new LiveView is displayed and data added 6 seconds later?

12:08:00.566: [info] handling query

When I go directly to the ResultsView in the browser it renders immediately, it’s only on redirect that it has this delay. I’m sure I’m missing something in terms of lifecycle/routing, but not really sure what! Many thanks

1 Like

Could you please create a minimal code to reproduce issue?

You can use a minimal example of LiveView script and update it to your needs:

1 Like

You can only live navigate between LiveView A and LiveView B if they are in the same live_session defined in your router. We detect the bad live navigation and instruct the client to do a full redirect instead, but you’ll pay an extra round trip for it. So in your case it’s whatever your RTT is * 3 to get to a new page. One for the event that does push_navigate , one for the attempt at the new LV mount which fails because it’s in a different live session, and one for the regular page redirect (the GET in your logs). Since your push_redirect (now renamed to push_navigate) results in a GET request in the logs, this is definitely what is happening. Hope that helps!

8 Likes

Excellent, thank you!

So should it be as simple as defining both of these as

live_session :search do
      live "/search", SearchLive.Search
      live "/results/:query", SearchLive.Results
end

Is there more that needs defining? Still getting the same.

Yes. We’ll need to see the full code and logs to say more. Are you seeing in logs on the client with liveSocket.enableDebug() in the js console? The client will also force refresh the page as a failsafe if it detects it’s in an unrecoverable scenario such as repeated LiveView mount failures after connecting to the websocket. You should see stacktrace errors in your server logs in such cases.

Thanks - extracted this to a repo that reproduces it here: GitHub - mhyrr/live_test: liveview session test

I reproduced the issue.

Indeed, there are 3 RTTs as Chris mentioned.

However, as you mention in your original post, there is a “mysterious” delay 6-7 seconds before the second RTT takes place.

Unfortunately, I cannot explain it.

1 Like

What happens if an app doesn’t use live_session/3 at all? Are all views treating as if they were all in the same live_session, or all as seperate ones (meaning extra RTTs)?

All routes would be treated as part of the same live session - live_redirect uses the websocket and doesn’t cause an additional HTTP request

1 Like

Glad someone else has been able to recreate this! I’m not seeing any liveSocket debug in the console and only the message destroyed: the child has been removed from the parent - undefined

Is this happening only in localhost? I’ve posted to this forum before that I had really odd delays in LiveView’s initial websocket connection when I was using localhost under Chrome. I was using Windows 10 and if I used 127.0.0.1 instead of localhost that delay wasn’t there.

Nope - this still happens on a deployed instance also.

1 Like

What browser do you use and does this happen with a different browser?

I’m on Chrome 107, but it happens on Firefox as well.

Repo is here, if anyone can help figure out what I’m doing wrong, thanks!

Wanted to bump this thread and see if anyone has any answers using the sample repo that reproduces this behavior?

The above could also be exasperated by a slow setup/mount phase of the target liveview (like a big data load or some other blocker in mount). in which case it would be the roundtrip penalty described + that slow startup/setup penalty.

I believe I’ve stumbled upon this issue. I push_navigate to this page in a couple places, but in just one of them… and only some of the time… my phx-click/handle_event doing push_navigate causes this weird 6-7 second hang. I can tell the push_navigate happened right away, but the next page doesn’t seem to hit its mount for this time. I emptied the template and stripped it bare, so it doesn’t seem to be any big data load or mount hold-up. I’m not sure where the delay is coming from!

I think I’ve got a workaround by using redirect here instead of push_navigate, but I’d love to understand this better.

Not sure if you’ve already fixed the issue… Trying to reproduce it from the linked repo, I’ve noticed that the form with search text input and button is rendered twice when visiting /search, because you have <%= live_render @conn, LiveTestWeb.SearchLive.Search %> in the root.html.heex.

If I follow correctly:

  1. when visiting /, SearchLive.Search is rendered as part of the PageController, you’re not within a live session and the push_redirect fails.
  2. when visiting /search, you see the form rendered twice. Using the first one fails for the same reason I think… Using the second one actually works, you get redirected to SearchLive.Results (with the first form still rendered as the root layout is used here as well)

Removing <%= live_render @conn, LiveTestWeb.SearchLive.Search %> from the layout fixes it for me, no more errors, redirect works.

The delay seems to be happening because the socket gets disconnected, not sure exactly what causes that, but I’ve noticed an error in the console about element with ID matches being present twice on the page. (again, because SearchLive.Search and hence <datalist id="matches"> is rendered twice)