Handling concurrent tasks

I have multiple concurrent tasks, all of them trying to check record existance, then, if not exist, will insert one.

Unfortunately, I end up with duplicate writing to the record into DB, as it seems that all of tasks decides that the record does not exist at the same time, then all of them do insertion.

The desired behavior, is that I got the insertion only once, and then, other tasks would recognize the existence of just inserted record.

Here is my attempt:

alias MyApp.Parent, as: Parent
alias MyApp.Repo, as: Repo
changeset = Parent.changeset(%Parent{}, model)

case Repo.all(from p in Parent, where: p.mobile_number == ^model.mobile_number) do

    [] ->
    #does not exist
      case Repo.insert_or_update(changeset) do
        {:ok, %MyApp.Parent{ id: parent_id }} -> parent_id
        error_message -> nil
      end


    [parent_get_by|t] ->
    #already exist
    %MyApp.Parent{ id: parent_id }= parent_get_by
        parent_id

end

Any help is appreciated!

Unfortunately you have not told us which database you are using. But assuming your database supports transactions, you will want to use one. Any time you have multiple queries that rely on the data of some previous query, you will want to run them in a transaction to make sure that things were not changed / deleted between each of the different queries.

Oh, I am sorry, I am using postgress

Yeah just as with any Postgres API then you really must be using transactions, which in Ecto is Ecto.Multi.