-
-
Notifications
You must be signed in to change notification settings - Fork 301
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
[Error] select_for_update happening when using replica(read-only) and default(write-only) DB. #558
Comments
I think this was added by someone who was using a database router to store the Schedule objects in a different database. Probably the easiest fix would be to introduce a config setting for this. I'm open to ideas and PR's. |
We are also experiencing this issue. As a temporary workaround, we modified our database router to always use the write db for Django-Q's
|
Although modifying the router works, I would suggest adding a In the # conf.py
class Conf:
"""
Configuration class
"""
# other settings...
# Support for read/write replicas
HAS_REPLICA = conf.get("has_replica", False) And the # cluster.py
def scheduler(broker: Broker = None):
"""
Creates a task from a schedule at the scheduled time and schedules next run
"""
if not broker:
broker = get_broker()
close_old_django_connections()
try:
# addition of database_to_use
database_to_use = {"using": Schedule.objects.db} if not Conf.HAS_REPLICA else {}
with db.transaction.atomic(**database_to_use):
for s in (
Schedule.objects.select_for_update()
.exclude(repeats=0)
.filter(next_run__lt=timezone.now())
): When we use read/write replicas we don't specify a database to use in the transaction. The transaction will be made without any problems, since the router will correctly use the write database when a write operation is made (in this case the The scenarios where some apps needs to write into one database and other apps into another, like it was suggested in a previous modification, would also works correctly when applying the That way the current usage would not break and it would allow the usage of read only replicas via a setting in the configuration. What do you all think? Does it make sense to add the If it does can I open a PR suggesting these additions and tests covering some scenarios around the multiple databases? |
And I think @Koed00 was talking about me 😉 The fix proposed in #561 by @abxsantos put us back to square one regarding the problem described in #434: using In my case, I do not use the ORM broker at all. However, I do use another db to store any data related to django-q administration, which means that I still need to be explicit about which database I'm using. This was done by #440. Ironically, the code snippet proposed above would probably have avoided this regression: # ok
database_to_use = {"using": Schedule.objects.db} if not Conf.HAS_REPLICA else {} But what was implemented is: # not ok
database_to_use = {"using": Conf.ORM} if not Conf.HAS_REPLICA else {} which is very different. EDIT @abxsantos it looks like you tried to prevent this regression with the test cases you added in the PR... Do you think there is something missing? I did not review the new test cases in detail, but maybe you only considered the case where the ORM broker was configured? |
Hello @edthrn ! From what I've understand you need to write in a specific database without the ORM being set as broker right? The scenarios I've proposed looked only at the ORM being set. Thus the regression. I've seen that you've opened a PR with the |
If you can improve the test scenarios so my fix passes the current tests + (why not) adding a test case to prevent this regression happening again, it would be great. Thank you. I gave you the authorization to push to my forked repo so we can work on this PR #587 together. Thanks |
Great! I'll take a look. |
Hello @edthrn, @abxsantos , I believe that the issue is in fact that Schedule.objects.db returns the database for reading Schedule objects, not writing them. This works in @edthrn use case (same database for read and write) but breaks @abxsantos use case (which is also mine). The best solution would be to use I have verified this with Django 3.1.12 and django-q 1.3.9. I think the same should be applied for Success objects in def save_task(task, broker: Broker): |
I've been getting a
select_for_update cannot be used outside of a transaction
error when using a replica set in my applications.Here are my settings
My database router currently uses the
replica
only to read and thedefault
just to write.I've been digging through the code (awesome documenation btw!) and found that during the task creation in the scheduler function it forces the database used in the transaction block.
Is there a reason for this behaviour? I couldn't really understand why, since when removing the
using
from the transaction block made it work like a charm, reading only fromreplica
and writing only ondefault
.Dependencies
The text was updated successfully, but these errors were encountered: