ericteubert

ericteubert

Ecto: retry query on timeout

My situation: I have a table with millions of download tracking entries that I am running queries on to generate report data. Query times seem to vary a lot, but sometimes even giving multiple minutes timeout is not enough. When I then go to the database manually and try to run the identical query again it finishes in seconds.

Postgrex.Protocol (#PID<0.438.0>) disconnected: ** (DBConnection.ConnectionError) client #PID<0.593.0> timed out because it checked out the connection for longer than 300000ms

My workaround idea is to rerun the query when it timeouts. But how do I do that? Isolate each query execution in Task.Supervisor.async_nolink and check if the task finishes normally or is killed? Is there a more direct way?

Bonus question: What could be the reason for these erratic timeouts?

Most Liked

fmcgeough

fmcgeough

If its Postgres then there are resources available to figure what the issue is. There are some basic things you should know.

The pg_stat_statements suggestion by @benwilson512 is great. What I do with every Postgres db I use for production is to ensure that’s loaded then grab all the data from the table that it uses on an hourly basis, write it all to an archive database (with an hour timestamp) and reset the pg_stat_statements table. This allows me to see impact of a release and compare hours historically (number of queries, average execution time, etc).

pg_stat_activity shows your current transactions and the last (or currently active) query that is executing as part of that transaction. This query might be helpful:

SELECT s."state", s.client_addr, s.usename, now()-s.query_start as age, s.pid, s.query
FROM pg_stat_activity s
WHERE s.query != '<IDLE>'
AND s."state" != 'idle'
and s.pid != pg_backend_pid()
order by 4 desc;

pg_locks stores locking information. There are queries on the Postgres site for checking to see if your query is blocking and what is blocking it. Here’s a basic one to start with:

 SELECT bl.pid                 AS blocked_pid,
         a.usename              AS blocked_user,
         ka.query               AS blocking_statement,
         now() - ka.query_start AS blocking_duration,
         kl.pid                 AS blocking_pid,
         ka.usename             AS blocking_user,
         a.query                AS blocked_statement,
         now() - a.query_start  AS blocked_duration
  FROM  pg_catalog.pg_locks         bl
   JOIN pg_catalog.pg_stat_activity a  ON a.pid = bl.pid
   JOIN pg_catalog.pg_locks         kl ON kl.transactionid = bl.transactionid AND kl.pid != bl.pid
   JOIN pg_catalog.pg_stat_activity ka ON ka.pid = kl.pid
  WHERE NOT bl.GRANTED;

If you are stuck or determine that you have some sort of Postgres issue then I’d also suggest visiting the #postgres channel on free node IRC. There are some incredibly knowledgeable folks that hang out there and they are helpful.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

If you’re using postgres look into turning on the PostgreSQL: Documentation: 16: F.32. pg_stat_statements — track statistics of SQL planning and execution extension which will let the database itself help you track long running queries.

josevalim

josevalim

Creator of Elixir

Each database is going to have a different implementation, so I would recommend getting an advanced book on your database of choice. It has been a while since I read one about Postgres specifically, so I don’t have one to recommend, but hopefully others can chime in!

josevalim

josevalim

Creator of Elixir

My workaround idea is to rerun the query when it timeouts. But how do I do that? Isolate each query execution in Task.Supervisor.async_nolink and check if the task finishes normally or is killed? Is there a more direct way?

I like this approach. Task.yield/shutdown were designed exactly for this. :+1:

Whenever a query succeeds, we log some stuff. For the cases the query succeeds but still takes long, how long is the decoding/queue/query time? That should provide some guidance. If the query is the one varying a lot, then I would guess database locks maybe?

Where Next?

Popular in Questions Top

sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
mathew4509
I have a list say x = ["23gh", "56kh", "97mh"] I would like to pass each element to Val in each iteration. Say, in iteration 1 -------...
New
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; someth...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New

Other popular topics Top

sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
sergio
I couldn’t find any guides that worked well with Phoenix 1.6.0 and esbuild. I hope this helps people test the waters and eases you into t...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 45766 226
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 27727 240
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New

We're in Beta

About us Mission Statement