Простое использование — m3-mutex documentation

### Navigation

- index
- previous |
- m3-mutex documentation »

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

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

В качестве примера работы с 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'Объект занят'

### Navigation

- index
- previous |
- m3-mutex documentation »