Reputation: 13
update:
I did some test for select_for_update
. I am using django 1.8.12. I run the following functions in different shell, connecting to my local mariadb (engine is InnoDB). seems select_for_update
locks other row as well? Not sure if I did testing in correct way:
def with_sleep(resource):
try:
with transaction.atomic():
resource = resourceA.objects.select_for_update().filter(A=resource).first()
print('before sleep')
time.sleep(10)
print('after sleep')
resource.available = False
resource.save()
return True
except:
handle_exception()
def withouth_sleep(resource):
try:
with transaction.atomic():
print('try')
resource = resourceA.objects.select_for_update().filter(A=resource).first()
print('get resource')
resource.available = False
print('save')
resource.save()
return True
except:
handle_exception()
I call the with_sleep(resource1)
function first and call then without_sleep(resource2)
. resource1
and resource2
are different resources in my model. From the shell, I saw the second function blocked after try
till the first function awake from sleep. Is that mean row of resource2 is also locked?
The question might sound stupid. Thanks for any advise or any change for testing.
original question: I have a resource model which checks if a resource is available or not, and it runs multiple celery workers in 2 servers to retrieve the next available resource each time. If available, change it's status to unavailable and assign to the task.
For example:
Class resourceA(model.Model):
A = models.CharField(max_length=10)
available = models.BooleanField(default=True)
Every time, I just want to pick the next available resource and assign to task. If I do
resource = resourceA.objects.filter(available=True).first()
if resource:
resource.available=False
resource.save()
Then there is a chance that other workers might pick up the same resource and try to update it.
Django has select_for_update
to lock the entries. However, I don't want to lock and update all the available resources.
Please suggest if is there any way so that I can retrieve and update in one shot?
Upvotes: 1
Views: 2062
Reputation: 2014
select_for_update
will lock the rows only, so with first()
in your query there will be only one row locked.
Thus — use select_for_update
.
Upvotes: 3