Example #1
0
def user_lock_acquire(context, user_id, action_id, engine=None,
                      forced=False):
    """Try to lock the specified user.

    :param context: the context used for DB operations;
    :param user_id: ID of the user to be locked.
    :param action_id: ID of the action that attempts to lock the user.
    :param engine: ID of the engine that attempts to lock the user.
    :param forced: set to True to cancel current action that owns the lock,
                   if any.
    :returns: True if lock is acquired, or False otherwise.
    """

    owner = db_api.user_lock_acquire(user_id, action_id)
    if action_id == owner:
        return True

    retries = cfg.CONF.lock_retry_times
    retry_interval = cfg.CONF.lock_retry_interval

    while retries > 0:
        sleep(retry_interval)
        LOG.debug(_('Acquire lock for user %s again'), user_id)
        owner = db_api.user_lock_acquire(user_id, action_id)
        if action_id == owner:
            return True
        retries = retries - 1

    if forced:
        owner = db_api.user_lock_steal(user_id, action_id)
        return action_id == owner

    action = db_api.action_get(context, owner)
    if (action and action.owner and action.owner != engine and
            is_engine_dead(context, action.owner)):
        LOG.info(_LI('The user %(u)s is locked by dead action %(a)s, '
                     'try to steal the lock.'), {
            'u': user_id,
            'a': owner
        })
        reason = _('Engine died when executing this action.')
        db_api.action_mark_failed(context, action.id, time.time(),
                                  reason=reason)
        db_api.user_lock_steal(user_id, action_id)
        return True

    LOG.error(_LE('User is already locked by action %(old)s, '
                  'action %(new)s failed grabbing the lock'),
              {'old': owner, 'new': action_id})

    return False
Example #2
0
    def set_status(self, result, reason=None):
        """Set action status based on return value from execute."""

        timestamp = wallclock()

        if result == self.RES_OK:
            status = self.SUCCEEDED
            db_api.action_mark_succeeded(self.context, self.id, timestamp)

        elif result == self.RES_ERROR:
            status = self.FAILED
            db_api.action_mark_failed(self.context, self.id, timestamp,
                                      reason=reason or 'ERROR')

        elif result == self.RES_TIMEOUT:
            status = self.FAILED
            db_api.action_mark_failed(self.context, self.id, timestamp,
                                      reason=reason or 'TIMEOUT')

        elif result == self.RES_CANCEL:
            status = self.CANCELLED
            db_api.action_mark_cancelled(self.context, self.id, timestamp)

        else:  # result == self.RES_RETRY:
            status = self.READY
            # Action failed at the moment, but can be retried
            # We abandon it and then notify other dispatchers to execute it
            db_api.action_abandon(self.context, self.id)

        if status == self.SUCCEEDED:
            EVENT.info(self.context, self, self.action, status, reason)
        elif status == self.READY:
            EVENT.warning(self.context, self, self.action, status, reason)
        else:
            EVENT.error(self.context, self, self.action, status, reason)

        self.status = status
        self.status_reason = reason