Простое использование

Простые примеры использования модуля

В качестве примера работы с m3-mutex реализуем небольшой класс-семафор, который будет блокировать повторное редактирование уже заданного объекта:

class ObjEditMutex(object):
u"""Класс-семафор, блокирующий повторное редактирование объекта
"""

Добавим метод, который позволит нам получать id объекта:

def get_obj_id(self, obj_id):
    u"""Подмена obj_id, для возможности переопределения класса.
    Позволяет использовать свой уникальный obj_id
    без изменения логики родительского класса.
    """
    return obj_id

Добавим метод, который позволит нам получать семафор по типу и id объекта:

def get_mutex_id(self, mode, obj_id):
    u"""Возвращает id семафора для указанного типа и id объекта

    :param basestring mode: Тип объекта
    :param int obj_id: id объекта

    :rtype: int
    """
    return m3_mutex.MutexID(mode=mode, id=str(obj_id))

Добавим метод, который позволит нам проверять наличие семафора:

def check(self, obj_id, mode, request_id):
    u"""Проверка на наличие семафора.
    Возвращает True, если объект не заблокирован или заблокирован нами.
    В противном случае возвращает False
    """
    obj_id = self.get_obj_id(obj_id)
    mutex_id = self.get_mutex_id(mode=mode, obj_id=obj_id)

    # По умолчанию семафор занят
    is_free = False
    state, mt = m3_mutex.request_mutex(mutex_id)

    # Проверяем свободен ли семафор
    if state == m3_mutex.MutexState.FREE:
        is_free = True
    # Если семафорт занят нами в текущем запросе, то тоже все ОК
    elif state == m3_mutex.MutexState.CAPTURED_BY_ME:
        is_free = True

    return is_free

Добавим метод, который позволит нам создавать семафор для последующей его блокировки:

def block(self, obj_id, mode, request_id):
    u"""Создание семафора и его блокировка.
    Передаётся id объекта, тип объекта и id запроса.

    :param int obj_id: id объекта
    :param basestring mode: тип объекта
    :param int request_id: id запроса

    :rtype: basestring or None
    """
    blocker = None
    obj_id = self.get_obj_id(obj_id)
    mutex_id = self.get_mutex_id(mode=mode, obj_id=obj_id)

    try:
        # Получаем состояние
        state, mt = m3_mutex.request_mutex(mutex_id)

        # Если mutex никем не занят, в том числе нами из другого места
        if state == m3_mutex.MutexState.FREE:
            # Захватываем mutex
            m3_mutex.capture_mutex(mutex_id, status_data=request_id)

        # Иначе блокируем
        else:
            # Получаем владельца mutex
            blocker = mt.owner.name

    # Если занят
    except m3_mutex.MutexBusy:
        blocker = u'Блокировщик неизвестен'

    return blocker

Добавим метод, который позволит нам обновлять блокировку семафора:

def refresh(self, obj_id, mode, request_id):
    u"""Обновление блокировки семафора, чтобы он не освободился по тайм-ауту.
    Передаётся id объекта, тип объекта и id запроса.

    :param int obj_id: id объекта
    :param basestring mode: тип объекта
    :param int request_id: id запроса

    :rtype: basestring or None
    """
    obj_id = self.get_obj_id(obj_id)
    mutex_id = self.get_mutex_id(mode=mode, obj_id=obj_id)

    # Получаем состояние
    state, mt = m3_mutex.request_mutex(mutex_id)

    # Если заблокирован нами и не из другого запроса
    if (state == m3_mutex.MutexState.CAPTURED_BY_ME
            and mt.status_data == request_id):
        # Обновляем блокировку для повторного захвата
        m3_mutex.capture_mutex(mutex_id, status_data=request_id)
    else:
        return u"Блокировка объекта снята!"

    return None

Добавим метод, который позволит нам освобождать семафор:

def release(self, obj_id, mode, request_id):
    u"""Освобождение семафора.
    Передаётся id объекта, тип объекта и id запроса.
    """
    obj_id = self.get_obj_id(obj_id)
    mutex_id = m3_mutex.MutexID(mode=mode, id=obj_id)

    state, mt = m3_mutex.request_mutex(mutex_id)

    if state == m3_mutex.MutexState.CAPTURED_BY_ME:
        mt = m3_mutex.capture_mutex(mutex_id)
        try:
            if mt.status_data == request_id:
                m3_mutex.release_mutex(mutex_id)
        except m3_mutex.MutexBusy:
            pass
    return None

После этого, данный семафор можно использовать следующим образом:

# создаем семафор
mutex = ObjEditMutex()
# создаем или получаем каким - либо образом объект
some_obj = SomeObjClass()

# блокируем объект
blocker = mutex.block(some_obj.id, some_obj.type, some_obj.uuid)
# если нам удалось заблокировать объект
if blocker is None:
        # делаем что - то с объектом
        do_something(some_obj)
        # освобождаем объект
        mutex.release(some_obj.id, some_obj.type, some_obj.uuid)
        print 'Операция с объектом завершена'
else:
        # говорим, что объект занят
        print u'Объект занят'