3

I'm building a REST API in Django where users can run tasks for objects. I've created a simple example below where I use transactions to easily rollback the state of the object in case the task fails.

from django.db import IntegrityError, transaction

def send_object(id):
    obj = MyModel.objects.get(pk=id)
    if obj.state != 'Created':
        raise ValueError('Object not in state "Created"')
    with transaction.atomic():
        obj.state = 'Sending'
        obj.save()

        # send the object...

        obj.state = 'Sent'
        obj.save()

Now I want the state of the object to be visible for users through the API while the task is running. Since the transaction isn't commited until the task is done, users only see the current state before and after the task.

I need some sort of transaction in case of a system failure/shutdown occurs during the task and the object gets stuck at 'Sending'. The state must be reset so that the task easily can be retried.

The isolation level is set to READ COMMITTED and cannot be changed without updating other parts of the code.

Can I make the new state available before the transaction is commited (i.e. enable dirty reads) for just this transaction? Or is there something else I can do?

Oskar Persson
  • 6,605
  • 15
  • 63
  • 124

1 Answers1

5

Based on this similar question and comments to this answer, you could try using two database conexions with different isolation levels.

The following code is from the linked answer:

DATABASES = {
    'default': {
        'NAME': 'app_data',
        'ENGINE': 'django.db.backends.postgresql',
        'USER': 'postgres_user',
        'PASSWORD': 's3krit',
    },
    'serializable': {
        'NAME': 'app_data',
        'ENGINE': 'django.db.backends.postgresl',
        'USER': 'postgres_user',
        'PASSWORD': 's3krit',
        'OPTIONS': {
            'isolation_level': psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE,
        },
    },
}

You can change it to fit your needs (maybe use READ UNCOMMITED instead of SERIALIZABLE) and then let us know if that solves your problem.

Ralf
  • 16,086
  • 4
  • 44
  • 68
  • Couldn't get it working with `SERIALIZABLE` but `READ UNCOMMITED` works great! Tested in Django 1.11 with MariaDB 10.2.13 – Oskar Persson Jul 05 '18 at 09:20