3

I have a threaded comment system which works fine 99.9% of the time, but very occasionally the tree breaks down and left/right values get duplicated.

I have discovered that this happens when two posts happen at the same time (within a second of each other), and presumably what is happening is that the second post is updating the left/right values of the tree before the first has completed doing so.

My comment insert code from views.py is the following:

@login_required
@transaction.autocommit
def comment(request, post_id):
    parent = get_object_or_404(Post, pk=post_id)

    if request.method == 'POST':
        form = PostForm(request.POST)

        form.parent = post_id
        if form.is_valid():
            new_post = newPost(request.user, form.cleaned_data['subject'], form.cleaned_data['body'])
            new_post.insert_at(parent, 'last-child', save=True)
            return HttpResponseRedirect('/posts/')
    else:
        form = PostForm()

    return render_to_response('posts/reply.html', {'requestPost': request.POST, 'form': form, 'parent': parent}, context_instance=RequestContext(request))

What is the correct approach to dealing with this? Is there a django way to ensure that the second view does not get called until the first database transaction is complete? Or should I rebuild the tree after each insert to ensure integrity? Or is there a better insert method to be using?

Thanks!

edit: I'm using MySQL.

meepmeep
  • 3,018
  • 7
  • 33
  • 47
  • did you find a solution or better to say a workaround? – Daviddd Mar 28 '17 at 15:30
  • I migrated to a new (faster) host and upgraded django-mptt in the process, and the issue disappeared - probably just due to db updates running faster (so the chances of concurrency being greatly reduced) rather than the actual underlying issue being solved. – meepmeep Apr 30 '17 at 17:42

1 Answers1

1

transaction.autocommit() is a standard django behavior. You decorator does nothing, if global transaction behavior was not redefined. Use should use commit_on_success() decorator. All db operations in view will be in one transaction. You can read more on https://docs.djangoproject.com/en/1.5/topics/db/transactions/

PS: In django 1.6 transaction management will be updated, be attentive.

Sergei
  • 280
  • 1
  • 10
  • thank you - but does this prevent other database transactions (called by other sessions) from being enacted concurrently? Basically I'm trying to make sure transactions from different users are queued so that the second doesn't read incorrect left/right values before the first transaction completes. – meepmeep Nov 01 '13 at 20:07
  • There is https://docs.djangoproject.com/en/1.5/ref/models/querysets/#select-for-update It can block records, but I don`t know how to use it in django-mptt code. – Sergei Nov 04 '13 at 08:58