mrcasals

mrcasals

Hi all!

I’m starting my first project with Elixir and Phoenix. I have a function in a context that creates a record and fires some asynchronous code using Task.start. This task fetches data from a local URL and updates the newly created record.

I want to reuse this code for my seed data, but the process seems to finish before the Task.start has finished running, so the seed records are not being updated with the complete data.

The code works as expected from iex -S mix.

Is there any way to force the process to wait until the Tasks are finished, without using Task.async? The only thing that comes to mind is a loop that counts the records in the DB that have not yet been updated, and sleep for a second if there’s any, but I’d like to try to find a better solution.

Thanks!

Showing Posts 1 to 4

idi527

idi527

:waving_hand:

You can enter a receive block, which is what Task.await does. But for that you’d need to send your process a message on task completion to leave that block. The easiest way to do that would probably be Task.async, so why don’t you want to use it?

peerreynders

peerreynders

Refactoring the code so that it can be used with either Task.start/3 or Task.async/3 and Task.await/3 should be the preferred approach - that way async/await could be used in the seeding script.

A more “hackey” solution: start returns {:ok, pid}; monitor the pid with Process.monitor/1 and at the end of the script put a receive/1 for the {:DOWN, ref, :process, object, reason} message.

mrcasals

mrcasals OP

For clarity, here’s my code.

My seeds.exs file:

alias MyApp.Multimedia
urls = [...] # an array of strings representing URLs

# I try to fetch the URL from my DB, or I create it
# To avoid double seeding the dev DB
Enum.map(urls, fn url -> Multimedia.get_url!(url) || Multimedia.create_url(url) end)
defmodule MyApp.Multimedia do
  def create_url(url) do
    %Url{}
    |> Video.creation_changeset(%{url: url})
    |> create_url
  end

  def create_url(%Ecto.Changeset{} = changeset) do
    case Repo.insert(changeset) do
      {:ok, %Url{} = url} ->
        get_basic_url_info(url)
        {:ok, url}

      other_value ->
        other_value
    end
  end

  def get_basic_url_info(%Url{} = url) do
    Task.start(fn -> Devflix.Brain.create(url.url) end)
  end
end

The problem right now is that when the Enum.map section of the seeds file finishes, all other Tasks are deleted.

I read that the Task.async needs to be used together with Task.await, and I don’t need to check the result during the normal life cycle of the app, only in the seeding part. That’s why I didn’t want to use it, but maybe I understood it wrong?

I finally moved to a mini-loop that checks if the seed data is complete to let the tasks run correctly:

defmodule Loops do
  def while(0), do: :ok
  def while(_n) do
    Process.sleep(1000)
    while(Repo.aggregate(query(), :count, :id))
  end

  def query do
    from(v in Url, where: is_nil(v.data)) # v.data is set via a `Task`
  end
end

Loops.while(Repo.aggregate(Loops.query, :count, :id))

I don’t find it a bad solution, although I guess mine is not the most Elixir-esque one…

Thanks to both, @idi527 @peerreynders

dimitarvp

dimitarvp

What about Task.yield?

You will immediately avoid the very ugly pattern of waiting fixed amounts and then re-checking.

— All posts loaded —

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
water
I’m aware of 2 such projects, are there others? git: GitHub - team-alembic/realworld: A fullstack Phoenix LiveView application with back...
New
itzmidinesh
Hi all, I’m working on a Phoenix project where I need to make external HTTP requests and I’m trying to choose between Req and HTTPoison....
New
pragdave
How do I tell Hologram not to escape HTML when substituting into templates? {Textile.render(@product.long_description)} escapes the HTM...
New
rlipscombe
I’d like to create a file with 600 permissions (rw-------), but there’s a race condition if I create it and then change the permissions. ...
New
leoschweizer
Hi, we run different LLM models across a cluster, with each node loading a configurable subset. Model-specific queues let nodes consume ...
New
rlipscombe
When I use Mix.install with a git dependency, using git@github.com:... how do I change the SSH identity used? I’ve got two Github accoun...
New

Other Trending Topics Top

dominicletz
Hey there, I haven’t seen a list of useful Elixir specific skills for the popular AI tools yet so I’m starting one here with my first. ...
New
raa-ziq
Hi everyone :waving_hand: I wanted to share something I’ve been building — NowBlind, a random chat app designed to help people discover ...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
OndrejValenta
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly) AI dream has many faces, but general...
New
kip
Localize is the next generation localisation library for Elixir. Think of it as ex_cldr version 3.0. The first version will be released ...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews