Skip to content

A process crash during a query wipes an in-memory database #134

Closed
@Gazler

Description

@Gazler

When using an in memory database, if the a process that performs a query crashes, then the database is destroyed.

This could potentially be avoided by isolating the process that performs the query from the calling process (e.g. using Task.Supervisor). If this behaviour is intentional, perhaps it should be documented in the "limitations" section so users are aware of it.

Here is a simple example to replicate this. You'll see that the second query fails as the database has been destroyed.

Mix.install([
  {:ecto_sql, "~> 3.10"},
  {:ecto_sqlite3, ">= 0.12.0"},
  {:exqlite, ">= 0.0.0"}
])

Application.put_env(:foo, Repo, database: ":memory:", pool_size: 1)

defmodule Repo do
  use Ecto.Repo,
    adapter: Ecto.Adapters.SQLite3,
    otp_app: :foo
end

defmodule Migration0 do
  use Ecto.Migration

  def change do
    create table("posts") do
      add(:title, :string)
      timestamps(type: :utc_datetime_usec)
    end
  end
end

defmodule Post do
  use Ecto.Schema

  schema "posts" do
    field(:title, :string)
    timestamps(type: :utc_datetime_usec)
  end
end

defmodule Main do
  import Ecto.Query, warn: false

  def start() do
    children = [
      Repo
    ]

    _ = Repo.__adapter__().storage_down(Repo.config())
    :ok = Repo.__adapter__().storage_up(Repo.config())

    {:ok, _} = Supervisor.start_link(children, strategy: :one_for_one)

    Ecto.Migrator.run(Repo, [{0, Migration0}], :up, all: true, log_migrations_sql: :debug)
    Repo.insert!(%Post{title: "Hello, World!"})

  end

  def query do
    from(Post) |> Repo.all()
  end

  def blowup do
    query = """
      WITH RECURSIVE r(i) AS (
      VALUES(0)
      UNION ALL
      SELECT i FROM r
      LIMIT 1000000
      )
      SELECT i FROM r WHERE i = 1;
      """
    spawn_link(fn ->
      :timer.sleep(10)
      raise "bad"
    end)

    Repo.query(query)
  end
end

Main.start()

Main.query() |> IO.inspect()

# We can trigger an error during a query
Process.flag(:trap_exit, true)
pid = spawn(&Main.blowup/0)
Process.monitor(pid)
receive do
  {:DOWN, _ref, :process, ^pid, _} -> :noop
end

Main.query() |> IO.inspect()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions