Hi, I want to preface my question with say that I am new to Elixir. I have been playing around with Phoenix and ash and loving both. I am still making a lot of silly mistakes.
To set the scene a little. I have a toy application that I am building that I would like to run an Oban job to do some processing once a resouce has been created. High level it is:
- Form submitted
- Resource created
- On successful creation queue an Oban job to do some post processing.
Form submission handler:
defp save_feed(socket, :new_feed_item, feed_params) do
%{assigns: %{feed_id: feed_id}} = socket
p = feed_params |> Map.put("feed_id", feed_id)
case FeedItemService.create_feed_item(socket.assigns.form, p) do
{:ok, feed_item} ->
notify_parent({:saved, feed_item})
socket =
socket
|> put_flash(:info, "Feed item saved!")
|> push_navigate(to: ~p"/feeds/#{feed_id}")
{:noreply, socket}
{:error, form} ->
socket =
socket
|> put_flash(:error, "Could not save feed item data")
|> assign(:form, form)
{:noreply, socket}
end
end
Service:
def create_feed_item(form, params) do
case AshPhoenix.Form.submit(form, params: params) do
{:ok, feed_item} ->
# Successfully created the new feed_item. We now need to enqueue the job that will start the logic around
# Processing the url that was provided.
%{id: id, resource_media_type: resource_media_type, resource_media_url: url} = feed_item
# This is a simple case now. Though the plan is to add more url types here
# We will need to process each differently
case resource_media_type do
# Clause 1: If status_code matches 200
:youtube ->
IO.puts("Found that we have a youtube url")
case %{feed_item_id: id} |> YoutubeDownloader.new() |> Oban.insert() do
{:ok, oban_res} ->
IO.puts("Successfully created the oban job")
{:error, _e} ->
IO.puts("Failed to create the oban job for youtube encoding")
end
_ ->
IO.puts("Was unable to process the url type: #{resource_media_type}")
end
{:ok, feed_item}
{:error, _e} ->
{:error, form}
end
end
My question is twofold. I am currently getting a race condition in this code as the first thing that the Oban job does is pull the FeedItem
from the database using get_feed_by_id(feed_item_id)
code interface method on my domain. I use iex and run the function manually the item has definately been inserted into the database. The Oban job is just not able to see it.
So firstly, any thoughts on what I might be doing wrong here? I am unsure why I am getting a race here?
Secondly, Adding a service layer seems like a bit of a hacky way to implement this. Feels like it is taking some of the logic away from the resource. Does Ash provide a nice way to run an post-create type action. Something to run code after a resource has been added?
Hope all that is clear and thanks in advance for taking the time to read my question :).