Exemplo n.º 1
0
    def get(self, queue, claim_id, project=None):
        msg_ctrl = self.driver.message_controller

        # Base query, always check expire time
        now = timeutils.utcnow_ts()
        cid = utils.to_oid(claim_id)
        if cid is None:
            raise errors.ClaimDoesNotExist(claim_id, queue, project)

        try:
            # Lets get claim's data
            # from the first message
            # in the iterator
            msgs = _messages_iter(
                msg_ctrl._claimed(queue, cid, now, project=project))
            claim = next(msgs)

            update_time = claim['e'] - claim['t']
            age = now - update_time

            claim_meta = {
                'age': int(age),
                'ttl': claim['t'],
                'id': str(claim['id']),
            }
        except StopIteration:
            raise errors.ClaimDoesNotExist(cid, queue, project)

        return claim_meta, msgs
Exemplo n.º 2
0
    def get(self, queue, claim_id, project=None):
        if project is None:
            project = ''

        cid = utils.cid_decode(claim_id)
        if cid is None:
            raise errors.ClaimDoesNotExist(claim_id, queue, project)

        with self.driver.trans() as trans:
            sel = sa.sql.select([tables.Claims.c.id,
                                 tables.Claims.c.ttl,
                                 tables.Claims.c.created],
                                sa.and_(tables.Claims.c.ttl >
                                        utils.get_age(tables.Claims.c.created),
                                        tables.Claims.c.id == cid,
                                        tables.Queues.c.project == project,
                                        tables.Queues.c.name == queue),
                                from_obj=[tables.Queues.join(tables.Claims)])

            res = trans.execute(sel).fetchone()
            if res is None:
                raise errors.ClaimDoesNotExist(claim_id, queue, project)

            cid, ttl, created = res
            return (
                {'id': claim_id,
                 'ttl': ttl,
                 'age': (timeutils.utcnow() - created).seconds},
                list(self.__get(cid, trans))
            )
Exemplo n.º 3
0
    def update(self, queue, claim_id, metadata, project=None):
        cid = utils.to_oid(claim_id)
        if cid is None:
            raise errors.ClaimDoesNotExist(claim_id, queue, project)

        now = timeutils.utcnow_ts()
        grace = metadata['grace']
        ttl = metadata['ttl']
        claim_expires = now + ttl
        claim_expires_dt = datetime.datetime.utcfromtimestamp(claim_expires)
        message_ttl = ttl + grace
        message_expires = datetime.datetime.utcfromtimestamp(claim_expires +
                                                             grace)

        msg_ctrl = self.driver.message_controller
        claimed = msg_ctrl._claimed(queue,
                                    cid,
                                    expires=now,
                                    limit=1,
                                    project=project)

        try:
            next(claimed)
        except StopIteration:
            raise errors.ClaimDoesNotExist(claim_id, queue, project)

        meta = {
            'id': cid,
            't': ttl,
            'e': claim_expires,
        }

        # TODO(kgriffs): Create methods for these so we don't interact
        # with the messages collection directly (loose coupling)
        scope = utils.scope_queue_name(queue, project)
        collection = msg_ctrl._collection(queue, project)
        collection.update_many({
            'p_q': scope,
            'c.id': cid
        }, {'$set': {
            'c': meta
        }},
                               upsert=False)

        # NOTE(flaper87): Dirty hack!
        # This sets the expiration time to
        # `expires` on messages that would
        # expire before claim.
        collection.update_many(
            {
                'p_q': scope,
                'e': {
                    '$lt': claim_expires_dt
                },
                'c.id': cid
            }, {'$set': {
                'e': message_expires,
                't': message_ttl
            }},
            upsert=False)
Exemplo n.º 4
0
    def update(self, queue, claim_id, metadata, project=None):
        if project is None:
            project = ''

        cid = utils.cid_decode(claim_id)
        if cid is None:
            raise errors.ClaimDoesNotExist(claim_id, queue, project)

        age = utils.get_age(tables.Claims.c.created)
        with self.driver.trans() as trans:
            qid = utils.get_qid(self.driver, queue, project)

            update = tables.Claims.update().where(sa.and_(
                tables.Claims.c.ttl > age,
                tables.Claims.c.id == cid,
                tables.Claims.c.id == qid))

            update = update.values(ttl=metadata['ttl'])

            res = trans.execute(update)
            if res.rowcount != 1:
                raise errors.ClaimDoesNotExist(claim_id, queue, project)

            update = (tables.Messages.update().
                      values(ttl=metadata['ttl'] + metadata['grace']).
                      where(sa.and_(
                          tables.Messages.c.ttl < metadata['ttl'],
                          tables.Messages.c.cid == cid)))
            trans.execute(update)
Exemplo n.º 5
0
    def get(self, queue, claim_id, project=None):
        if not self._exists(queue, claim_id, project):
            raise errors.ClaimDoesNotExist(queue, project, claim_id)

        claim_msgs_key = utils.scope_claim_messages(claim_id,
                                                    CLAIM_MESSAGES_SUFFIX)

        # basic_messages
        msg_keys = self._get_claimed_message_keys(claim_msgs_key)
        claimed_msgs = messages.Message.from_redis_bulk(msg_keys,
                                                        self._client)
        now = timeutils.utcnow_ts()
        basic_messages = [msg.to_basic(now)
                          for msg in claimed_msgs if msg]

        # claim_meta
        now = timeutils.utcnow_ts()
        expires, ttl = self._get_claim_info(claim_id, [b'e', b't'])
        update_time = expires - ttl
        age = now - update_time

        claim_meta = {
            'age': age,
            'ttl': ttl,
            'id': claim_id,
        }

        return claim_meta, basic_messages
Exemplo n.º 6
0
    def delete(self, queue, message_id, project=None, claim=None):
        claim_ctrl = self.driver.claim_controller
        if not self._queue_ctrl.exists(queue, project):
            return

        # NOTE(kgriffs): The message does not exist, so
        # it is essentially "already" deleted.
        if not self._exists(message_id):
            return

        # TODO(kgriffs): Create decorator for validating claim and message
        # IDs, since those are not checked at the transport layer. This
        # decorator should be applied to all relevant methods.
        if claim is not None:
            try:
                uuid.UUID(claim)
            except ValueError:
                raise errors.ClaimDoesNotExist(claim, queue, project)

        msg_claim = self._get_claim(message_id)
        is_claimed = (msg_claim is not None)

        # Authorize the request based on having the correct claim ID
        if claim is None:
            if is_claimed:
                raise errors.MessageIsClaimed(message_id)

        elif not is_claimed:
            raise errors.MessageNotClaimed(message_id)

        elif msg_claim['id'] != claim:
            if not claim_ctrl._exists(queue, claim, project):
                raise errors.ClaimDoesNotExist(claim, queue, project)

            raise errors.MessageNotClaimedBy(message_id, claim)

        msgset_key = utils.msgset_key(queue, project)

        with self._client.pipeline() as pipe:
            pipe.delete(message_id)
            pipe.zrem(msgset_key, message_id)

            if is_claimed:
                claim_ctrl._del_message(queue, project, msg_claim['id'],
                                        message_id, pipe)

            pipe.execute()
Exemplo n.º 7
0
 def update(self, queue, claim_id, metadata, project=None):
     control = self._get_controller(queue, project)
     if control:
         return control.update(queue,
                               claim_id=claim_id,
                               project=project,
                               metadata=metadata)
     raise errors.ClaimDoesNotExist(claim_id, queue, project)
Exemplo n.º 8
0
 def _exists(self, queue, claim_id, project=None):
     try:
         return self._client.head_object(
             utils._claim_container(queue, project), claim_id)
     except swiftclient.ClientException as exc:
         if exc.http_status == 404:
             raise errors.ClaimDoesNotExist(claim_id, queue, project)
         raise
Exemplo n.º 9
0
    def update(self, queue, claim_id, metadata, project=None):
        if not self._exists(queue, claim_id, project):
            raise errors.ClaimDoesNotExist(claim_id, queue, project)

        now = timeutils.utcnow_ts()

        claim_ttl = metadata['ttl']
        claim_expires = now + claim_ttl

        grace = metadata['grace']
        msg_ttl = claim_ttl + grace
        msg_expires = claim_expires + grace

        claim_msgs_key = utils.scope_claim_messages(claim_id,
                                                    CLAIM_MESSAGES_SUFFIX)

        msg_keys = self._get_claimed_message_keys(claim_msgs_key)
        claimed_msgs = messages.MessageEnvelope.from_redis_bulk(msg_keys,
                                                                self._client)
        claim_info = {
            't': claim_ttl,
            'e': claim_expires,
        }

        with self._client.pipeline() as pipe:
            for msg in claimed_msgs:
                if msg:
                    msg.claim_id = claim_id
                    msg.claim_expires = claim_expires

                    if _msg_would_expire(msg, claim_expires):
                        msg.ttl = msg_ttl
                        msg.expires = msg_expires

                    # TODO(kgriffs): Rather than writing back the
                    # entire message, only set the fields that
                    # have changed.
                    #
                    # When this change is made, don't forget to
                    # also call pipe.expire with the new TTL value.
                    msg.to_redis(pipe)

            # Update the claim id and claim expiration info
            # for all the messages.
            pipe.hmset(claim_id, claim_info)
            pipe.expire(claim_id, claim_ttl)

            pipe.expire(claim_msgs_key, claim_ttl)

            claims_set_key = utils.scope_claims_set(queue, project,
                                                    QUEUE_CLAIMS_SUFFIX)

            pipe.zadd(claims_set_key, claim_expires, claim_id)

            pipe.execute()
Exemplo n.º 10
0
    def update(self, queue, claim_id, metadata, project=None):
        if not self._queue_ctrl.exists(queue, project):
            raise errors.QueueDoesNotExist(queue, project)

        container = utils._claim_container(queue, project)
        try:
            headers, obj = self._client.get_object(container, claim_id)
        except swiftclient.ClientException as exc:
            if exc.http_status == 404:
                raise errors.ClaimDoesNotExist(claim_id, queue, project)
            raise

        self._client.put_object(container,
                                claim_id,
                                obj,
                                content_type='application/json',
                                headers={'x-delete-after': metadata['ttl']})
Exemplo n.º 11
0
    def delete(self, queue, message_id, project, claim=None):
        if project is None:
            project = ''

        mid = utils.msgid_decode(message_id)
        if mid is None:
            return

        with self.driver.trans() as trans:
            if not self._exists(queue, message_id, project):
                return

            statement = tables.Messages.delete()
            and_stmt = [tables.Messages.c.id == mid]

            exists = sa.sql.select([tables.Messages.c.id], sa.and_(*and_stmt))

            if not trans.execute(exists).first():
                return

            cid = claim and utils.cid_decode(claim) or None

            if claim and cid is None:
                raise errors.ClaimDoesNotExist(queue, project, claim)

            and_stmt.append(tables.Messages.c.cid == cid)

            statement = statement.where(sa.and_(*and_stmt))
            res = trans.execute(statement)

            if res.rowcount == 0:
                # NOTE(kgriffs): Either the message is not claimed,
                # or if it is, the specified claim does not exist.
                cid = self._get_cid(mid)
                if cid is None:
                    raise errors.MessageNotClaimed(mid)

                # NOTE(kgriffs): The message exists, but the claim
                # must have expired or something, since it
                # was not associated with the message.
                raise errors.MessageNotClaimedBy(mid, claim)
Exemplo n.º 12
0
 def get(self, queue, claim_id, project=None):
     control = self._get_controller(queue, project)
     if control:
         return control.get(queue, claim_id=claim_id,
                            project=project)
     raise errors.ClaimDoesNotExist(claim_id, queue, project)