Ecto is stopped while I push an item after delete with GenServer immediately

Hi, I have a simple GenServer which loads all record of a table of my database and store on itself.
It works good for me, but I have this error when I delete a record on database I send a request to my GenServer to check if my table is empty, it creates a basic info immediately. But it stops my db and Repo module even though I put Repo in my Application file.

could not lookup Ecto repo MishkaDatabase.Repo because it was not started or it does not exist

Then, if I want to work with this, I should put sending request into a Task with a sleep time to work like this:

Task.Supervisor.async_nolink(MishkaDatabase.Public.ReStartSettingAgentTaskSupervisor, fn ->
      :timer.sleep(10000)
      MishkaDatabase.Cache.SettingCache.stop()
    end)

If I user MishkaDatabase.Cache.SettingCache.stop() without Task or sleep time, it stops my Repo module.


My application:

defmodule MishkaDatabase.Application do
  @moduledoc false

  use Application

  @impl true
  def start(_type, _args) do
    children = [
      {MishkaDatabase.Cache.MnesiaToken, []},
      {MishkaDatabase.Cache.RandomCode, []},
      MishkaDatabase.Repo,
      {MishkaDatabase.Cache.SettingCache, []},
      {Task.Supervisor, name: MishkaDatabase.Public.ReStartSettingAgentTaskSupervisor}
    ]

    opts = [strategy: :one_for_one, name: MishkaDatabase.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

After stopping Repo, I should re-start server to work again!!! I am using {:ecto_sql, "~> 3.7"} and my project is an umbrella project.

I have read these posts, but I couldn’t fix this.

It seems like the only way to run into this problem is to either run the code before repo starts or during compilation. When is your Task.Supervisor.async_nolink being called?

In particular, I don’t quite understand this part:

I have this error when I delete a record on database I send a request to my GenServer to check if my table is empty, it creates a basic info immediately. But it stops my db and Repo module even though I put Repo in my Application file.

How does Repo stop? Why do you think it’s stopped? Does that genserver do anything with Repo?

2 Likes

Hello, all of my GenServer files work after Repo module:

def start(_type, _args) do
    children = [
      MishkaDatabase.Repo,
      {MishkaDatabase.Cache.MnesiaToken, []},
      {MishkaDatabase.Cache.RandomCode, []},
      {MishkaDatabase.Cache.SettingCache, []},
      {Task.Supervisor, name: MishkaDatabase.Public.ReStartSettingAgentTaskSupervisor}
    ]

After every record is added or edited on my database (setting table).

Because all of my site pages show me this error

could not lookup Ecto repo MishkaDatabase.Repo because it was not started or it does not exist

Yes, check if is there a record on setting table or not!?, then insert a data into this table

Please see my project:

send stop request to my GenServer

https://github.com/mishka-group/mishka-cms/blob/master/apps/mishka_database/lib/public/setting.ex#L98-L101

My GenServer

https://github.com/mishka-group/mishka-cms/blob/master/apps/mishka_database/lib/cache/setting_cache.ex

Stop request and re-create a record

https://github.com/mishka-group/mishka-cms/blob/master/apps/mishka_database/lib/cache/setting_cache.ex#L74-L87

I created a video for describing

Thanks

Your application shuts down at 04:21, and repo shuts down with the application. You’d need to check why it shuts down in the logs prior to the ones shown at 04:21. Maybe start_setting never returns on restart, it seems like it might not have a stop condition for recursion.

I changed my code and deleted start_setting, now I just call 2 functions on my

def handle_continue(:start_storing_setting, _state) do
    create_basic_setting()
    {:noreply, Setting.settings(filters: %{})}
  end

create_basic_setting() is a simple crud:

defp create_basic_setting() do
    Setting.create(%{
      section: "public",
      configs: %{
        "google_recaptcha_client_side_code" => "PLEASE PUT YOUR CODE",
        "google_recaptcha_server_side_code" => "PLEASE PUT YOUR CODE",
        "captcha_status" => "developer",
      }
    })
  end

and the other function is a query with pagination:

def settings(filters: filters) do
    try do
      query = from(set in SettingSchema) |> convert_filters_to_where(filters)
      from([set] in query,
      order_by: [desc: set.inserted_at, desc: set.id],
      select: %{
        id: set.id,
        section: set.section,
        configs: set.configs,
        updated_at: set.updated_at,
        inserted_at: set.inserted_at,
      })
      |> MishkaDatabase.Repo.all()
    rescue
      Ecto.Query.CastError -> []
    end
  end

After pushing the delete button, I have that error: (full error)

In this log, it says we have no repo module, and GenServer.whereis(MishkaDatabase.Repo) returns a nil.

If I started Repo manually MishkaDatabase.Repo.start_link, repo is started, but application is dropped as you said.

exited in: GenServer.call(MishkaDatabase.Cache.SettingCache, {:get, :public, “captcha_status”}, 5000) ** (EXIT) no process: the process is not alive or there’s no process currently associated with the given name, possibly because its application isn’t started


I don’t know where I should check for it, why it drops all application? :sob: :thinking:
Is the application file my last stronghold? Can’t I supervise it?

GenServer.whereis MishkaDatabase.Application
-> nil

Updated


I disabled all repo query or insert in my GenServer, and I just stop setting Genserver in terminal several times, and it breaks my application

Screen Shot 1400-06-19 at 10.08.48

I changed this:

def handle_continue(:start_storing_setting, state) do
    {:noreply, state}
end

I find this problem

  • :max_restarts — the maximum number of restarts allowed in a time frame. Defaults to 3.
  • :max_seconds - the time frame in seconds in which :max_restarts applies. Defaults to 5.

I changed this on my application file:

opts = [strategy: :one_for_one, name: MishkaDatabase.Supervisor, max_restarts: 100]

and it doesn’t crash, but I have a question:

My strategy is one_for_one why does it drop the other children or my application? Just stops itself.

And the other my question is:

if I raise max_restarts, it creates problems for me?

https://hexdocs.pm/elixir/Supervisor.html#module-start_link-2-init-2-and-strategies

and is there a way just rise max_restarts of a GenServer instead of all the children? How can I isolate them on my application, I mean the GenServers which have problems.

I unfortunately do not have answers to your other questions, but for this one I do:

Isolating GenServers is done by adding an extra layer of supervision in-between. So rather than your main application supervisor directly running the ‘GenServer(s) that have problems’, you the application supervisor runs a supervisor whose sole task is to properly manage the ‘GenServer(s) that have problems’.

And then options such as :max_restarts and :max_seconds can then be set to values that make sense for that scenario, without impacting the rest of the application.

1 Like