[HN Gopher] A LiveView Is a Process
___________________________________________________________________
A LiveView Is a Process
Author : clessg
Score : 145 points
Date : 2023-06-15 13:06 UTC (1 days ago)
(HTM) web link (fly.io)
(TXT) w3m dump (fly.io)
| jeremyjh wrote:
| I suppose this is good basic information for people new to
| Erlang/Elixir, but I don't feel like it does a good job of
| explaining the significance of the fact that state is stored in a
| process, compared to other frameworks which would store the state
| in a dictionary and retrieve it for each event/request as its
| dispatched in an event loop or whatever.
|
| I'd think the dictionary approach is functionally equivalent in
| most respects, and could even imitate how crashes are handled in
| Elixir. The framework has to implement more code to do this (e.g.
| messages between processes might be something some frameworks
| don't bother to implement because its such a hassle, while its
| almost free in Elixir), but that doesn't matter at all to users
| of the framework if the features are there.
| weatherlight wrote:
| In essence, the dictionary approach you're referencing isn't
| entirely dissimilar to Elixir's process-based state management,
| and you're absolutely correct that, at a fundamental level,
| they both accomplish a similar task: preserving state across
| requests.
|
| However, I'd argue that the key difference lies in the
| granularity of control and the inherent characteristics of the
| Erlang/Elixir process model, which is designed to excel in
| concurrent, real-time, and distributed systems.
|
| For instance, in Elixir, every LiveView session is an isolated
| process that runs concurrently. This is native to the BEAM
| (Erlang's virtual machine), not an add-on. It's this built-in
| process model that allows LiveView to handle many users
| simultaneously, manage state efficiently, and push real-time
| updates, all while maintaining high performance.
|
| Fault isolation, too, is a baked-in benefit of this process
| model. A crash in one process doesn't affect others. While it's
| certainly feasible to engineer fault isolation in a different
| paradigm, it's a baseline guarantee in Elixir, reducing a
| considerable amount of potential complexity from the get-go.
|
| Elixir's supervision trees further provide a robust way of
| handling failures, automatically restarting processes when they
| crash. Implementing a similar mechanism outside of Elixir can
| be quite intricate and might not offer the same level of
| reliability.
|
| Additionally, Elixir processes facilitate straightforward and
| efficient inter-process communication, making it easier to
| build distributed and concurrent systems. Other frameworks
| could implement similar features, but it might not be as
| effortless or as integral a part of the programming model as it
| is in Elixir.
|
| So, while the dictionary approach can mimic some aspects of
| Elixir's processes, Elixir's model provides a more complete,
| integrated solution for building highly concurrent, real-time
| systems. The fact that many of these features are "almost free"
| in Elixir does matter, as it can reduce the complexity of
| application code, improve robustness, and increase developer
| productivity.
| jeremyjh wrote:
| None of this is new information to me or contradicts anything
| in my post. Yes, Elixir has a lot of features that are nice
| and save framework developers time. That's why I've been
| using Elixir for the last 10 years.
|
| But most of us reading this article do not develop
| frameworks, we develop applications. And when we choose a
| framework to use for that, we look at the features it
| provides, not the features it leverages from lower-level
| frameworks.
| HappMacDonald wrote:
| Well in that case this boils down to: "LiveView does this
| for you. In fact it does this because the underlying
| language does this for you. Most other frameworks in other
| languages do not do this for you. You might be able to roll
| your own but it would be a huge headache to do". :)
| throwawaymaths wrote:
| > Fault isolation, too, is a baked-in benefit of this process
| model
|
| I wouldn't call it baked in, it's the _entire purpose_ of the
| process model. The other benefits of the process model are
| secondary.
| manmal wrote:
| Isn't it another quite important trait of this that one can
| manage millions of ,,processes" on one machine which is
| outright impossible with most other systems? It puts a one
| machine setup for mid sized apps into the range of the
| possible.
| OkayPhysicist wrote:
| The message passing is, IMO, the biggest win you get from the
| process model. In the process model, you have the LiveView
| process, which sits there, listening for messages, which it can
| receive both from the browser client, or from independent
| going-ons in the backend, quite symmetrically. To the
| programmer, it looks just like any other process that you'd be
| used to using everywhere in Elixir, which provides useful
| interop with things like Task.async, which sends a message back
| to it's linked process on completion, or other libraries that
| are completely unaware of LiveView.
|
| You could simulate the same thing with a dictionary lookup
| scheme, but A) it would be far more complex, because of the
| lack of native message passing support, and B) the you'd miss
| out on the symmetries and interop, because the rest of your
| program wouldn't be using message passing.
| no_wizard wrote:
| Legitimate question: is there anything Elixir / BEAM is
| particularly bad at?
|
| I've seen it start cropping up in some Fintech circles so I'm
| wondering if this language has some serious juice for concurrent
| data analysis or something.
| ashton314 wrote:
| Any algorithm that needs mutable data to be performant would be
| a bad fit. Numerical number crunching isn't stellar either.
|
| That said, there are ways to extend the BEAM with C or Rust
| code to make those areas performant. I've written one such
| extension (called a NIF; forget what it stands for exactly) and
| it wasn't all that hard.
| HalcyonicStorm wrote:
| It is historically not great at number computing. This is being
| addressed by a relatively new project called Nx.
| https://github.com/elixir-nx/nx
|
| It is not the right choice for CPU intensive tasks like
| graphics, HFT, etc. Some companies have used Rust to write
| native extensions for those kinds of problems.
| https://discord.com/blog/using-rust-to-scale-elixir-for-11-m...
| Etheryte wrote:
| While the charts are nice for illustrating the flows, they could
| use a little bit more love. The process flowchart doesn't need to
| have any crossing lines, but it has multiple. While removing the
| crossings is a small change, it reduces cognitive load
| considerably.
| cush wrote:
| This is my gripe with mermaid, and is where excalidraw really
| took over the space. Sure mermaid can be stuck in any text
| file, but it's not worth the tradeoff of the diagram being
| unreadable.
| peregrine wrote:
| Yea I should have used excalidraw instead of mermaid, thats
| on me. I am trying to focus on writing good content and I try
| to not get stuck on the stuff I'm bad at which is making
| nicer charts.
| ketzo wrote:
| Hey, getting the work out there is always better than it
| sitting in the drafts waiting to be perfected! Thanks for
| the great article.
| derekkraan wrote:
| I'm glad someone has written about this. I actually wanted to
| write this very blog post, and even made a crappier version of
| this flow chart.
|
| Why? Because people think they know what LiveView is, but they
| don't, because the pretenders out there (LiveWire, StimulusReflex
| and all the rest) are poor imitations.
|
| Don't sleep on LiveView.
| Scarbutt wrote:
| OTOH, those other languages have decent ecosystems.
| ashton314 wrote:
| Have you, like, used Elixir seriously? I've worked as a
| professional Elixir dev and we were never wanting for a
| library to do what we needed. mix is excellent. It all feels
| very mature given its age.
| giraffe_lady wrote:
| What do you need that isn't in OTP though? Integrating with
| SaaS APIs is basically the only thing I've wanted that isn't
| buried in there somewhere.
| cultofmetatron wrote:
| come join us and contribute!
|
| built my startup on elixir/phoenix. while there could
| certainly be a better selection of libraries, its not that
| hard to roll your own and elixir has straight up features
| that you can't replicate in most other ecosystems
| parthdesai wrote:
| Ecto on it's own should be a good enough reason to use
| Elixir!
| cultofmetatron wrote:
| I concur.. once I wrapped my head around the way ecto
| worked, I couldn't help but wonder why this wasnt the way
| every orm works. its lightyears ahead of anything I tried
| in node, rust or ruby.
| mikl wrote:
| I don't think it's fair to call the Elixir/Erlang ecosystem
| _indecent_. Of course it's not on par with the vast
| ecosystems of the top 10 most popular languages, but in my
| experience, there's at least one solid package for most
| things you might need.
| OkayPhysicist wrote:
| One of my favorite things about programming in Elixir is
| the fact that for an absurd number of problems, there's not
| just _a_ library that solves it, but an official one from
| the OTP. It cuts down dramatically on time spent evaluating
| different options.
| omnimus wrote:
| Why so much negativity? 37signals (with Stimulus) are the OGs
| of this architecture. Livewire started at same time as LiveView
| and because of PHPs limitations it has to use different
| tactics/innovations (like using clientside JS more with
| Alpinejs) that then LiveView benefits from.
|
| Calling them poor imitations is disingenuous and spitting on
| open work of many people.
| regulation_d wrote:
| "Poor imitations" is probably harsh, but I agree with the
| idea that LiveView's architecture is substantially different
| from Hotwire or LiveWire. To have experienced Hotwire is not
| to have experienced LiveView, ironically enough, for reasons
| outlined in the posted article.
| omnimus wrote:
| But all this sounds like Hotwire/Livewire are not good
| architectures for many many types of projects.
|
| Biggest Liveview app i know is fly.io dashboard and the
| issues it has from ux standpoint are very similar to
| hotwire apps.
|
| Actually Basecamp and Hey.com are a lot bigger apps than
| fly.io dashboard and they are doing just fine.
|
| You don't have to jump to Elixir to experience similar
| approach when you know rails/laravel already.
| stanmancan wrote:
| The best part about Livewire is that it was appealing enough to
| try out but bad enough that I left PHP/Laravel and moved to
| Elixir/Phoenix for the real deal.
| Alifatisk wrote:
| I would not call out StimulusReflex and the rest like that, it
| all boils down to the language runtime they are built upon.
| They are good at what they are trying to accomplish in my
| opinion.
| derekkraan wrote:
| Yes, it does boil down to the language runtime.
|
| But that doesn't change the fact that they don't reproduce
| half of what LiveView can do.
|
| They didn't have to call themselves "LiveView for Ruby!"
|
| I meant it more as a PSA: if you've tried any of these other
| projects, you still owe it to yourself to give LiveView a
| try!
| Alifatisk wrote:
| You're right, the claim of an equivalent to LiveView is a
| bit far fetched.
|
| https://github.com/liveviews/liveviews
| Alifatisk wrote:
| You misspelled "Phoenix LivViews"
| peregrine wrote:
| Thanks fixed.
| floodfx wrote:
| I think it is more exciting and more innovative to think about
| LiveView as a new architectural approach to building reactive
| applications. Yes in Elixir land it is a Process and there are
| some amazing things about the BEAM. But LiveViews have the
| potential have an impact beyond just the Elixir ecosystem and
| folks should embrace that.
|
| I've been a part of porting the Phoenix LiveView Protocol to both
| Javascript (https://LiveViewJS.com) and Go
| (https://github.com/canopyclimate/golive) backends and supported
| a friend that is porting it to Python.
|
| Ironically I think taking LiveViews outside of Elixir could
| actually make it easier for folks to adopt Elixir-based LiveViews
| in the future.
| jolux wrote:
| Porting this is cool but why would people adopt Elixir if they
| can have LiveViews in their preferred language?
| floodfx wrote:
| Understanding LiveViews as a concept could make it easier to
| commit to learning a new language. I am not saying one should
| but that one could and it would probably be easier since you
| don't have the additional overhead of also learning what is a
| LiveView.
| weatherlight wrote:
| Ergonomics matter.
|
| Because outside of Go (and maybe Rust) it will be very
| difficult to actually do what Elixir does, with the same
| level of concurrency and fault tolerance, etc, with the same
| ergonomics.
|
| Ruby/Rails/StimulusReflex does something very similar, but
| kind of falls over unless you replace ActionCable with
| AnyCable which is written in Go.
|
| So now, you have to support Go and Ruby runtimes. Some
| developer who decided that the above was a nightmare to work
| with, __might__ start a new project in Elixir, to get
| something that actually does what Elixir does instead of just
| mimicking it.
|
| I'm not sure I buy this, personally, but I can understand the
| argument.
| troupo wrote:
| > Because outside of Go (and maybe Rust) it will be very
| difficult to actually do what Elixir does
|
| It's just as difficult in Go and Rust. BEAM, the Erlang VM
| that powers Elixir, is not just about lightweight
| processes. It's also about _guarantees_ that neither Go nor
| Rust provide. E.g. to do what Elixir does you need robust
| process supervision trees. You can imitate, but not
| replicate those in other languages.
| thomasfortes wrote:
| Virding's Law: Any sufficiently complicated concurrent
| program in another language contains an ad hoc
| informally-specified bug-ridden slow implementation of
| half of Erlang.
| floodfx wrote:
| Comments like this push people away from Erlang rather
| than draw them in.
| thomasfortes wrote:
| It's a play on
| https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule
| troupo wrote:
| I find it quite the opposite: what is it that other
| languages are trying to re-implement, and why they can't?
| Rapzid wrote:
| And yet it doesn't matter.
| ziftface wrote:
| Is your friend's python library open source by any chance? I
| was thinking about doing the same.
| floodfx wrote:
| https://github.com/ogrodnek/pyview
| whalesalad wrote:
| The term 'assigns' has always rubbed me the wrong way. Context or
| "view context" has always made more sense.
| sodapopcan wrote:
| Sure that's not a great reason not to use something. If you
| want you can think of it as short for "assignments" just as
| "conn" is short for "connection" or "attrs" is short for
| "attributes". Just consider a coincidence that this shorthand
| has the same name as a verb.
| pavlov wrote:
| "Assign" also rubs me the wrong way because it's a needless
| nouning of a verb. The word is "assignment" and it's only four
| letters longer.
| edvinbesic wrote:
| Not sure what you mean. assign
| @-sin' transitive verb 1. To select for a
| duty or office; appoint: synonym: appoint. 2. To set
| apart for a particular purpose or place in a particular
| category; designate: synonym: allocate. 3. To give
| out as a task; allot.
| osener wrote:
| Is there any widely used and public web or mobile app with its
| entire UI built with LiveView?
| a_bored_husky wrote:
| You can find some here: https://github.com/caspg/made-with-
| liveview
| swlkr wrote:
| cars dot com uses it
| benzible wrote:
| ElixirConf 2022: "The Launch of Elixir and LiveView at Scale
| on the New Cars.com"
| https://www.youtube.com/watch?v=XzAupUHiryg
| suciptoid wrote:
| fly.io dashboard use LiveView
| mrcwinn wrote:
| I absolutely loved working with Elixir and LiveView. I made a
| decision to migrate to Python/Flask to simplify our
| infrastructure and move application code into one language, but
| I'll miss it nonetheless!
| ashton314 wrote:
| The real "aha!" moment for me with LiveView came when I was using
| LaTeX to render a PDF in response to some user actions. The first
| time I did something like this, I did some janky polling on the
| client side. Other (bad) solutions involved blocking the client
| process or just praying that the PDF would render in time before
| the HTTP request timed out.
|
| With LiveView, it works like this:
|
| - user pushes a button to render the PDF
|
| - the LV process calls `Task.async(fn -> do_work({data,
| self.pid()}))` so the worker process has the PID _of the LiveView
| process itself_
|
| - when the job completes on a different thread, the worker sends
| an _Elixir message_ using the standard and highly-flexible built-
| in mechanism with `send()` to the PID of the LV
|
| - the LV gets the message and updates the UI and/or initiates a
| download of the rendered PDF automatically
|
| It is so simple to get this workflow going. It's super efficient.
| Perfect for low- to mid-range load on a web app. Perfect for one-
| person development.
| throwawaymaths wrote:
| Task.async already implements a result message so you're
| reduplicating the effort hete. You can listen for the
| task.async callback from LiveView.handle_info directly, instead
| of having the asynchronously run function send back the
| message. You may want to store the ref and pid of the task in
| the assigns.
|
| From the docs: "Alternatively, if you spawn a task [via async]
| inside a GenServer, then the GenServer will automatically await
| for you and call GenServer.handle_info/2 with the task
| response..."
|
| Also if you prefer sequencing the response manually the way
| you're doing, Task.start_link is probably more appropriate.
|
| Note that the way you're doing it now your liveview's message
| queue will leak with unhandled Task.async responses and down
| messages (probably not a big deal given your problem domain).
| If you do go the Task.start_link way, you do get two way
| binding (if the task dies the liveview will restart itself).
| ashton314 wrote:
| Ok, that all sounds much better. Thanks for the reply! It's
| been a hot minute since I've used LV--so much good stuff
| happening.
|
| I think it's a testament to the power of the platform that
| the obvious dumb solution worked so well for me. Lol
| throwawaymaths wrote:
| Always do the obvious dumb solution first!!
| [deleted]
| diob wrote:
| Is it a good experience for folks with high latency internet?
| lewantmontreal wrote:
| With higher latency the experience suffers. As an example
| liveview page navigations work via websocket which is not
| cacheable so navigating back/forward always needs to make a
| request. You really need some edge setup like fly, or only
| serve a geographically local audience.
| gangstead wrote:
| It can be pretty bad especially for UI updates that you are
| used to being handled client side.
|
| Example: You click on an upvote button and it changes color,
| but there's 1 second of latency.
|
| SPA: Color updates immediately, the "upvote pressed"
| http/websocket call to the server arrives one second later.
|
| LiveView: liveview.js sends "upvote pressed" over the web
| socket, one second later the liveview process on the server
| gets the message, patches the dom and replies, one more second
| later the button changes color. Meanwhile the user has pressed
| the button 2 more times wondering why the color isn't updating.
|
| There are phx-hooks (https://hexdocs.pm/phoenix_live_view/js-
| interop.html#client-...) to address this with small targeted
| bits of js where you can add event listeners but it can get
| messy quickly.
| kgeist wrote:
| Can a LiveView process migrate to a different machine/VM? For
| example, there's a scheduled maintenance and I need to shut down
| one of the machines/containers. The main advantage of stateless
| architectures for me is that state is not bound to a specific
| machine -- so you can easily add/remove machines, state is not
| lost if application dies, etc.
| jeremyjh wrote:
| No, and while there is a capability to hot reload releases (so
| that you could preserve state while deploying an update, for
| example), in practice almost no uses it because it is
| complicated.
|
| In practice, if you care about this aspect of user experience
| you may have to take some reasonably small steps to preserve
| state information in the client. Form state gets preserved
| automatically for most purposes, though there may be some forms
| that need to implement a call-back to preserve state, as
| explained in the docs:
| https://hexdocs.pm/phoenix_live_view/form-bindings.html#reco...
| throwawaymaths wrote:
| I think liveview live reload uses hot reloading, so that's
| definitely a very nice ergonomic improvement that basically
| everyone uses all the time
| jeremyjh wrote:
| No, the dev tool works differently, it does not use the OTP
| release feature I'm talking about. If you hot upgrade
| stateful modules you have to supply migration functions
| when the structure changes.
|
| https://www.erlang.org/doc/design_principles/release_handli
| n...
| notpublic wrote:
| This video may be of interest to you:
|
| https://youtu.be/pQ0CvjAJXz4?t=1992
|
| Bryan Hunter explains how they do it at HCA healthcare (not
| specifically LiveView process, but processes in general).
| sodapopcan wrote:
| Not without doing that work yourself, no.
|
| I take a more classic web approach to LiveView which is to say
| I persist any important state right away. Like any multiple-
| step forms I would never store in server state, I'd persist
| each step. Of course that doesn't help if someone is halfway
| through filling out a form. If the socket disconnects then re-
| connects then you don't lose your work but not if you do a
| restart. I do wish there was a built-in way to store state on
| the client until it's submitted, we may get there, though!
|
| The true value of LiveView for me is the simplicity of not
| having to write yourself a web API to interact with your own
| backend as well as the dead simple real-time features. If you
| don't need the latter, that's fine, but having worked on
| collaborative apps that was a giant pain is what led me to
| LiveView.
| throwawaymaths wrote:
| Can a LiveView process migrate to a different machine/VM?
|
| Liveview makes no assumptions about the client connection or
| even stickiness of client to nodes in a cluster. If you store
| critical data in the liveview you could be in for some trouble.
| Always store important stuff into a recoverable, network aware
| datastore. The nice thing is that liveview is _designed_ to be
| tolerant to client or client connection failures, you should
| design to be able to repopulate state sanely in the on_mount
| call.
|
| While this sounds bad, think of it as isolating the client
| connection failure domain from the data failure domain, so you
| should organize your code in those domains respectively
|
| If you want some sort of ephermal network state that lives on
| one node and not the database only (e.g. a game), the liveview
| should connect into that. If you want to store that in a
| genserver, a strategy like this is doable:
|
| https://youtu.be/nLApFANtkHs
| pythonaut_16 wrote:
| My recollection of the details is fuzzy, but I think a common
| solution to this is connection draining. You set up your deploy
| to bring up the new instance and direct all new traffic to that
| one and then hold the old one open until all
| sessions/connections end.
|
| Can't remember if/how that routing was accomplished in the BEAM
| (Erlang/Elixir VM). It's definitely possible but you might have
| to implement it yourself.
| mikl wrote:
| In general, LiveView applications are built so they can be
| safely reloaded without significant data loss, according to the
| Erlang/Elixir "Let it crash"-philosophy.
|
| Besides scheduled maintenance, there's all sorts of reasons why
| this might be needed: The user's log-in expires, network
| issues, browser crashes, server hardware issues, deployment of
| a new version of your app...
|
| "Hot upgrades" can be implemented if you wish to, but often
| this is just handled by asking the client to reload the page,
| establishing a new connection, because any data or preferences
| have been persisted.
___________________________________________________________________
(page generated 2023-06-16 23:01 UTC)