sezaru
The update_many/1 callback let’s you make your update call more efficient by handing all update calls from the same component type all at once.
The documentation shows an example where instead of doing a query to the DB for each component, you do it only once inside the update_many/1 callback.
That’s great, but the DB call is still a blocking operation in the LV, meaning that if this query is slow, the LV component will also not finish loading until the callback is done.
The “obvious” solution for that would be to leverage LV’s async functionality by using start_async or assign_async, that way I can make the DB call not block anymore.
The issue now is that I’m back to doing one DB call for each async operation.
I can’t see how to still keep one DB call that update_many/1 allows but doing it without blocking the component.
The only way I can see that being possible right now would be to start a new process in the update_many/1 callback, and inside of it call a bunch of send_update for each component with its reply… Something like this:
def update_many(assigns_and_sockets) do
ids =
Enum.map(assigns_and_socket, fn {%{id: id, component_id: comp_id}, _socket} ->
{id, comp_id}
end)
Task.start(fn ->
results = ids |> Enum.map(fn {id, _} -> ids end) |> DB.get!()
Enum.each(results, fn {id, comp_id} ->
send_update __MODULE__, id: com_id, result: results[id]
end)
end)
Enum.map(assigns_and_sockets, fn {assigns, socket} ->
{assign(assigns, loading?: true), socket}
end)
end
It is missing the code to handle the send_update message, but this should work. But doing something like this just feels wrong since I’m kinda just “re-implementing” the async operations (and, at least with the above code, without its great guarantees).
Why is this not already built-in in LV’s api? Or, if it is, where can I read more about it?
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #security










Showing Posts 1 to 6- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
mayel
I’m currently doing something similar to your example, and the downside is that it makes testing tricky since can’t use render_async, so keen to learn a better approach as well…
sezaru
I don’t link to bump my own post, but I feel that this issue is not something too obscure to just be ignored.
It feels to me like an oversight from LV to not have a proper way to handle this use case. Or is there something in the architecture that makes this not so easy to fix in the first place?
drikanius
Funny enough, a few weeks ago I fell into the same rabbit hole. I would really love a more interesting approach to this problem
codeanpeace
Maybe I’m missing something but if memory serves, it should be possible to use
start_asyncandhandle_asyncfrom within a LiveComponent. Not sure if I like this approach personally, but maybe try callingstart_asyncfrom withinupdate_manyinstead ofTask.startand then relaying the results to its sibling LiveComponents viasend_updatewithinhandle_async?sezaru
That would kinda work, but it would make the first component responsible to all the changes which I’m not a fan. Also, it seems like it would be hard to handle errors.
sezaru
So, in the end I decided to create a library that does this myself.
You can check it out here: LiveBulkAsync - A library to allow LV's async functionality in update_many function
It should has all the same guarantees that the LV’s async functions has (unless I messed something up
)