thoughtarray

thoughtarray

I’ve ran into several situations where LiveView and gen_statem being combined would be ideal. The simplest example would be any kind of calculator project. If you make even a simple calculator in LiveView, you’ll eventually want to think about state to keep track of where you are.

I know LiveView is a process running some kind of specialized gen_server. So it’s behavior and state. Similar situation with gen_statem. The only way I can think to combine them is to kick off and link a gen-statem on a LiveView mount, but that uses two processes per client.

Is there a way to do this with one process? Or would I have to write a gen_server from scratch that emulates both LiveView and gen_statem?

Showing Posts 1 to 7

al2o3cr

al2o3cr

It really depends on exactly which properties of gen_statem you need - for instance, do you need the state machine to move between states autonomously (versus only changing when it receives a message)?

RudManusachi

RudManusachi

While not answering directly to your question:

I’d say that should be a default way to go. Moreover - that gen_statem would want to live under a different supervisor and be registered under a name that LiveView process for a connection can uniquely identify (for example some user_id).. The reason is - LiveView process might get restarted because of faulty internet connection of a client.. and you don’t want to lose the state of the gen_statem, do you?

The number of processes used is still O(n) where n is the number of active LiveView connections.. (how many concurrent LiveView connections you expect to have simultaneously? 1k? 10k? BEAM by default allows upto 1m processes :slightly_smiling_face:)

And thinking of optimizing the number of processes in such case seems like a premature optimization.

Usually it becomes a concern when the logic might dynamically spawn unbound number of processes for some computation.. for example, if you want to implement some sort of a BFS.. and even then there are mechanisms to workaround - such as using process pools which would limit the number of processes used per computation.

thoughtarray

thoughtarray OP

I think calling this a premature optimization is fair in many cases. Conversely, I do think choosing to manage state as a state machine instead of the very general purpose gen_server isn’t unreasonable in some cases.

Even LiveView’s callback handle_event is similar to gen_statem. The key characteristic being the inability to match on the current state (or mode for another word). I mean, it’s possible to stick it in the socket assigns, but that gets very nested.

Regarding disconnects, it’s an interesting idea for an app to be recoverable. I think the Elixir tutorial covers this with its KV Buckets example. Is it typical in non-trivial LiveView apps to do this? To have something running that the LiveView process kicks off and later reconnects to?

thoughtarray

thoughtarray OP

I don’t have a specific use case per se. I’ve simply ran into situations where the gen_statem behavior would be really, really nice. Calculators, certain complex/conditional forms, etc.

RudManusachi

RudManusachi

Is it typical in non-trivial LiveView apps to do this? To have something running that the LiveView process kicks off and later reconnects to?

I like to think of most of LiveViews as of controllers (except render callback). Trying to keep them thin. Delegate most of the work to functions defined in the “core”. In other words LiveView takes care of the “presentation layer” and shouldn’t be used for “business layer”. The fact that it uses GenServer underneath and is stateful - doesn’t mean I should “abuse” its state.

With “Let it Crash” in mind - you should think of what’s going to happen if the process crashes?
LiveView will take care of reconnection, scroll position, some forms and UI components will get their state back via assigns and whatnot.. That’s all about the presentation layer. LiveView :slightly_smiling_face:

For your calculator project, it would be part of the “business layer” - a module that would provide with public function to start a new calculator, and functions to do operations on it.

And then with LiveView build a UI that would allow users to create and interact with the calculators.
Similarly you could add controller to provide with a json api to the calculator project etc.

thoughtarray

thoughtarray OP

I’m sold. Thanks for the architectural opinions! I often don’t get that :slight_smile:

thoughtarray

thoughtarray OP

Follow up for others that run across this.

FSM for stateless or very thin-stated things like presentation concerns (as @RudManusachi was talking about), Saša Jurić created a now archived/non-maintained fsm library. His conclusion:

Pure functional FSMs are still my preferred approach (as opposed to gen_statem), but you don’t need this library for that. Regular data structures, such as maps or structs, with pattern matching in multiclauses will serve you just fine.

This is completely compatible with GenServer/LiveView since it’s a process-less approach.

In conclusion, using FSM inside of some process-based thing (GenServer, LiveView, etc) is achievable with Elixir primitives. Not knowing how is a basic skill issue that doesn’t necessarily need to be solved with a library or involved Erlang module.

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New

Other Trending Topics Top

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
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
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
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews