Я не могу найти хороший чистый способ заблокировать критический раздел в Django. Я мог бы использовать блокировку или семафор, но реализация python предназначена только для потоков, поэтому, если производственные серверные вилки тогда не будут соблюдаться. Кто-нибудь знает о способе (я думаю, что семафоры posix прямо сейчас), чтобы гарантировать блокировку процессов или запрет на то, чтобы остановить запуск Django-сервера.
Как заблокировать критический раздел в Django?
Ответ 1
Вам нужен распределенный менеджер блокировок в момент, когда ваше приложение внезапно должно работать на нескольких сервисах. Для этой цели я написал elock. Есть более крупные, а другие выбрали игнорировать каждое предложение и сделали то же самое с memcached.
Пожалуйста, не используйте memcached для чего-либо большего, чем легкая консультативная блокировка. Он предназначен для того, чтобы забыть что-то.
Мне нравится притворяться, что файловые системы не существуют, когда я делаю веб-приложения. Улучшает масштабирование.
Ответ 2
Если вы используете РСУБД, вы можете использовать его механизм "LOCK". Например, в то время как транзакция "ВЫБЕРИТЕ ДЛЯ ОБНОВЛЕНИЯ" блокирует строку, другие транзакции "ВЫБЕРИТЕ ДЛЯ ОБНОВЛЕНИЯ" с этой строкой должны ждать.
# You can use any Python DB API.
[SQL] BEGIN;
[SQL] SELECT col_name FROM table_name where id = 1 FOR UPDATE;
[Process some python code]
[SQL] COMMIT;
Ответ 3
Используйте функцию Django builtin select_for_update.
https://docs.djangoproject.com/en/1.8/ref/models/querysets/#select-for-update
Из документов:
Возвращает набор запросов, который блокирует строки до конца транзакции, генерируя инструкцию SELECT... FOR UPDATE SQL в поддерживаемых базах данных.
Например:
entries = Entry.objects.select_for_update().filter(author=request.user)
Все согласованные записи будут заблокированы до конца транзакционного блока, что означает, что другим транзакциям будет запрещено изменять или приобретать блокировки на них.
Ответ 4
Вы можете использовать простую блокировку файлов как механизм взаимного исключения, см. мой рецепт здесь. Это не подходит для всех сценариев, но тогда вы не много говорили о том, почему вы хотите использовать этот тип блокировки.
Ответ 5
В итоге я решил использовать решение, связанное с блокировкой файлов. Если кто-то здесь заканчивает использовать его, помните, что контрольные блокировки и NFS не смешиваются хорошо, поэтому держите их локальными. Кроме того, это блокировка блокировки, если вы хотите общаться с циклами и постоянно проверять, тогда в коде есть инструкции.
import os
import fcntl
class DjangoLock:
def __init__(self, filename):
self.filename = filename
# This will create it if it does not exist already
self.handle = open(filename, 'w')
# flock() is a blocking call unless it is bitwise ORed with LOCK_NB to avoid blocking
# on lock acquisition. This blocking is what I use to provide atomicity across forked
# Django processes since native python locks and semaphores only work at the thread level
def acquire(self):
fcntl.flock(self.handle, fcntl.LOCK_EX)
def release(self):
fcntl.flock(self.handle, fcntl.LOCK_UN)
def __del__(self):
self.handle.close()
Usage:
lock = DJangoLock('/tmp/djangolock.tmp')
lock.acquire()
try:
pass
finally:
lock.release()
Ответ 6
Я не писал эту статью, но я нашел ее в высшей степени полезной, столкнувшись с этой же проблемой:
http://chris-lamb.co.uk/2010/06/07/distributing-locking-python-and-redis/
В основном вы используете сервер Redis для создания центрального сервера, который предоставляет функции блокировки.