-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pq as a "jobs queue" - items can not be read concurrently when using transactional get #33
Comments
This looks more like a question, @elawdio please check the testcase for an example how to handle the jobs in parallel: Also consider using a connection pooler if you're running jobs in parallel (examples also available in the tests). |
Thanks for the reply :) Regarding the connection pooler, it will not make a difference as I establish a new fresh connection with Postgres for each thread. (see the usage of '_create_queue_instance' in my code example) Am I still missing something? |
There is no table lock. In fact, the
|
Exactly, before I started to use this library, I was glad to see that it uses advisory locks, and this is why I was surprised by this code behavior. Do you have an idea of what can be done in my implementation / pq implementation to make it work? |
Back when #19 was reported, I had a new look at how the whole thing is set up and tried to implement changes that would better support the presumably common scenario where you pull out an item from the queue, make other database queries in the same transaction and either commit or abort the transaction. But I struggled to get the test cases to work out and ran out of time. |
To be honest, I didn't completely understand from your last comment if I can solve my problem with the current version of pq. I understand why #19 can be complex, but do you think that my specific problem can be solved easily? If so, as I mentioned before - I'll be glad to help. |
Thanks for helping me investigating this! Why would that limit the concurrency to 2? Correct me if I am wrong but the change to LIMIT 2 was made in the 'put' method and not in the 'get'. The problem that I am raising relates to being able to execute 'get' multiple times concurrently (in multiple threads) where each 'get' executed inside a separated transaction (with queue: ... handle_item_logic(queue.get()) ...), without blocking each other. |
@elawdio – using Your test script now runs as expected. Can you confirm? |
It works amazingly! Thank you very much! |
Hmm, First of all, I don't know why you'd want to place a queue that's blocking into a thread with a DB connection which is shared with a bunch of other threads. This is clearly not safe and it seems like that is the reason why your first thread is blocking the other threads (based on your logs, the Another question that I have is how and why you're fetching the items from the queue. The One more thing, when you do A bit of context, we've been running pq in production scaling over multiple processes with dozens of threads and had no issues around transactions being blocked. My advise would be to follow strictly the best practices re parallelism when designing your queue (as in, use a connections pool, use a separate connections pool inside the job handlers and so on...). What worked for us, is to wrap every queue into a separate process and let it manage a set of threads. Obviously you can use processes all-over, but that will cost you an expensive connection to every process (also more resources and stress on your DB). |
@stas – he's not sharing the connection, each thread opens its own connection. Which means that there's something incorrect about our tests because they didn't pick this up. |
Hi @stas, as @malthe just mentioned,
|
@stas – re |
Apologies, indeed, I missed the part where connection is initiated. I started looking at the locks in the running database. And it looks like there's a race condition or something. There are 28 locks with the query Take a look at this query while running your example:
It would be great if we could find a technical explanation of the current use-case. Though again, I doubt running pq in such a setup makes any sense (one connection per queue in a thread). Threads are just a pain to manage. |
@stas, well truth be told, that's the whole point of |
Can I kindly ask you when are you going to release a new version of pq including the skip locked change? |
This has now been fixed as is available in release 1.7.0. |
The use-case: running multiple threads that pull an item from the queue and handle it concurrently. In addition, in case of a failure (of any kind) in the handling logic, the item should be returned to the queue and be available in the next iteration (by opening a new transaction for each pull).
I realized that my jobs are running synchronously and that all threads are blocked when one thread works on an item, and they are released only after it finishes to handle the item and releases the transaction.
I believe it happens because there's an "UPDATE" SQL statement in "_pull_item" method in "pq/init.py" which probably locks the table until the transaction is released.
Any ideas on how to make the instances run concurrently?
Code example:
The output I get:
The text was updated successfully, but these errors were encountered: