From 2fe6882dfaf3f80882908aab1875488802b6c5ed Mon Sep 17 00:00:00 2001 From: Matthew Johnston Date: Mon, 20 Jan 2025 18:02:24 -0600 Subject: [PATCH] Add note about calling interrupt and close immediately Closes: #315 You can not call close immediately after interrupt. It will result in undefined behavior. Instead, shim a small `Process.sleep/1` in and it should mitigate the issue. --- CHANGELOG.md | 3 +++ lib/exqlite/sqlite3.ex | 9 +++++++++ test/exqlite/sqlite3_test.exs | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00ecadc..d8a0cf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ - changed: Removed `Exqlite.bind/3`, please use `bind/2` instead. - changed: Improved multi-threaded access to underlying sqlite resource. +- changed: Document issue with calling `close/1` immediately after calling + `interrupt/1`. If you encounter the issue where the entire BEAM crashes, put + a short sleep between the call to `interrupt/1` and `close/1`. ## v0.28.0 diff --git a/lib/exqlite/sqlite3.ex b/lib/exqlite/sqlite3.ex index d302ef1..64acd12 100644 --- a/lib/exqlite/sqlite3.ex +++ b/lib/exqlite/sqlite3.ex @@ -86,6 +86,15 @@ defmodule Exqlite.Sqlite3 do @doc """ Interrupt a long-running query. + + > #### Warning {: .warning} + > If you are going to interrupt a long running process, it is unsafe to call + > `close/1` immediately after. You run the risk of undefined behavior. This + > is a limitation of the sqlite library itself. Please see the documentation + > https://www.sqlite.org/c3ref/interrupt.html for more information. + > + > If close must be called after, it is best to put a short sleep in order to + > let sqlite finish doing its book keeping. """ @spec interrupt(db() | nil) :: :ok | {:error, reason()} def interrupt(nil), do: :ok diff --git a/test/exqlite/sqlite3_test.exs b/test/exqlite/sqlite3_test.exs index 643044e..22f4b98 100644 --- a/test/exqlite/sqlite3_test.exs +++ b/test/exqlite/sqlite3_test.exs @@ -792,7 +792,7 @@ defmodule Exqlite.Sqlite3Test do Process.sleep(100) :ok = Sqlite3.interrupt(conn) - + Process.sleep(100) :ok = Sqlite3.close(conn) end end