julismz

julismz

Hi!

I have some doubts about this documentation:

https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#c:terminate/2

I was trying to catch when / why every exit reason is triggered to understand the possible situations where some socket is disconnected and make some decisions.

From what I’ve read on the documentation there are 5 possible exit statuses:

  • :normal
  • :shutdown
  • {:shutdown, :left}
  • {:shutdown, :closed}
  • term()

I can’t figure out when :normal or {:shutdown, :left} will be called. Could the documentation be outdated? Probably I’m missing something.

These are some tests I did:

Notice: Just in case, I have trap exit enable on liveview server

Results:

|          Action         |         Reason       |
|-------------------------|----------------------|
|     push_redirect       |        :shutdown     | 
|.       redirect         |        :shutdown     | 
|     kill lv process     |        :shutdown     |
|   close tab / browser   | {:shutdown, :closed} | 
|        change URL       | {:shutdown, :closed} | 
|         refresh         | {:shutdown, :closed} | 
|disconnect socket with JS| {:shutdown, :closed} | 
|       raise error       |          term()      | 

Method used to kill liveview process
Process.whereis(QtixWeb.Endpoint) |> Process.exit(:kill)

I’m not able to get {:shutdown, :left} not :normal

I found this peace of code on liveview project:

def handle_info(%Message{topic: topic, event: "phx_leave"} = msg, %{topic: topic} = state) do
    send(state.socket.transport_pid, {:socket_close, self(), {:shutdown, :left}})
    reply(state, msg.ref, :ok, %{})
    {:stop, {:shutdown, :left}, state}
end

So I think it is something related with the Phoenix.socket, am I right?

On the other hand, I couldn’t find the way to get the :normal reason neither.

Once I have this clear, how possible is it to improve the documentation explaining every case? Is there a standard for keeping the documentation so minimalist?

Thanks!

Showing Posts 1 to 10

LostKobrakai

LostKobrakai

Did you try closing the socket via the API from the JS on the frontend?

Call exit(:normal) from your code.

Yes, exit reasons are a well defined set:

Given LVs run user supplied code any of those could be triggered by the user defined code, so there’s no possibility to limit this set further.

The only thing LV could be doing it document the reasons behind the ones it controls specifically, but then again any user provided code could hijack the same reason and use it under different circumstances.

julismz

julismz OP

I mean in the specific liveview context. I think is good to know when we will get each one, if I would like to know what’s the exit if people close the tab we have to make tests and experiments, that could be explained, I’ve no problem in improve the doc in any case it’s possible.

This seems forced (hijacked as you said), what’s the natural way when I will get this? I can run exit(:foo) but the :foo exit is not in the documentation. I assume that if :normal is on the documentation there is some organic reason that returns it.

Yes, I ran liveSocket.disconnect(); from chrome console and got {:shutdown, :closed}

I will add this last test to the table too.

Thanks!

LostKobrakai

LostKobrakai

User code calling exit(:normal) is at least one of the expected paths to get this exit reason. Yes you can call exit with any term, but OTP behaviours react in certain ways according to those specific exit reasons listed. Like a supervised process with restart strategy :transient would only restart on an abnormal (not :normal, :shutdown, {:shutdown, term}) exit reason. And again LV (like any otp behaviour) expect the user provided code to potentially call exit/1, so terminate/2 needs to be able to handle all of them (the non-abnormal ones, because abnormal ones don’t call terminate/2).

I agree that it would be useful to know what values LV does exit independently from user provided code, but that’s never going to be the full set terminate/2 needs to handle.

julismz

julismz OP

is not terminate/2 called if you enable trapping exit on the process? I intentionally raised an exception on an handle_event/3 and got it as term() in terminate/2, I think…

Update: Now I remember, for having this work the liveview lifecycle has to be started, if I raise some error on the mount/3 everything blow up and terminate/2 is no called at all, you’re right.

Once I had to detect even those cases and used process monitors, but that is another chapter :slight_smile:

LostKobrakai

LostKobrakai

The details are listed here: GenServer — Elixir v1.20.2

But given the many reasons for it not being called I’d stick to non-abnormal exit reasons if the intention is to have it be called (and complete).

julismz

julismz OP

Yes… The only mystery is when or why the {:shutdown, :left} is triggered… Just in case I will use a wildcard on my pattern-matching and consider it the same as {:shutdown, :closed}, in any case, the shutdown is shutdown. I intend to detect when the exit is voluntary or because of an error to take different actions.

If I have some time I will prepare some socket routes and try interacting directly with the socket, maybe that is the way.

MMore

MMore

Have you found something on this? I see this one too and I am wondering what the reason is :thinking:

julismz

julismz OP

No… I never found the answer…

steffend

steffend

Phoenix Core Team

You’ll get a {:shutdown, :left} if a user navigates away using a <.link navigate="/page">.

julismz

julismz OP

Thanks! I will try that

— All posts loaded —

Where Next? Top

Trending in Discussions Top

AstonJ
As the title says, please share what you’ve been up to with Elixir. Whether that’s been learning it, looking into it, making stuff with i...
2977 94592 917
New
cblavier
Hey there, It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
heathen
Quite interesting article Google brought me. Didn’t find any mentions about it here. What do you think in general? Would you use togethe...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
axelson
Hi there! :wave: @frigidcode and I (but mostly him) have been running an Elixir Book club, we’re almost done with Designing Elixir Syste...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
georgeguimaraes
Just published claude-code-elixir, a plugin marketplace for Claude Code with Elixir support. These are the plugins I’ve been using for my...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews