user6828492
user6828492

Reputation: 13

django filter and update

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

Answers (1)

Andrey Shipilov
Andrey Shipilov

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

Related Questions