コード例 #1
0
ファイル: messages.py プロジェクト: xglhjk6/zaqar
    def _list(self, queue, project=None, marker=None,
              limit=storage.DEFAULT_MESSAGES_PER_PAGE,
              echo=False, client_uuid=None,
              include_claimed=False, sort=1):
        """List messages in the queue, oldest first(ish)

        Time ordering and message inclusion in lists are soft, there is no
        global order and times are based on the UTC time of the zaqar-api
        server that the message was created from.

        Here be consistency dragons.
        """
        if not self._queue_ctrl.exists(queue, project):
            raise errors.QueueDoesNotExist(queue, project)

        client = self._client
        container = utils._message_container(queue, project)
        query_string = None
        if sort == -1:
            query_string = 'reverse=on'

        try:
            _, objects = client.get_container(
                container,
                marker=marker,
                # list 2x the objects because some listing items may have
                # expired
                limit=limit * 2,
                query_string=query_string)
        except swiftclient.ClientException as exc:
            if exc.http_status == 404:
                raise errors.QueueDoesNotExist(queue, project)
            raise

        def is_claimed(msg, headers):
            if include_claimed or msg['claim_id'] is None:
                return False
            claim_obj = self.driver.claim_controller._get(
                queue, msg['claim_id'], project)
            return claim_obj is not None and claim_obj['ttl'] > 0

        def is_echo(msg, headers):
            if echo:
                return False
            return headers['x-object-meta-clientid'] == str(client_uuid)

        filters = [
            is_echo,
            is_claimed,
        ]
        marker = {}
        get_object = functools.partial(client.get_object, container)
        list_objects = functools.partial(client.get_container, container,
                                         limit=limit * 2,
                                         query_string=query_string)
        yield utils._filter_messages(objects, filters, marker, get_object,
                                     list_objects, limit=limit)
        yield marker and marker['next']
コード例 #2
0
ファイル: pooling.py プロジェクト: rose/zaqar
 def set_metadata(self, name, metadata, project=None):
     control = self._get_controller(name, project)
     if control:
         return control.set_metadata(name,
                                     metadata=metadata,
                                     project=project)
     raise errors.QueueDoesNotExist(name, project)
コード例 #3
0
ファイル: pooling.py プロジェクト: xglhjk6/zaqar
 def post(self, queue, messages, client_uuid, project=None):
     control = self._get_controller(queue, project)
     if control:
         return control.post(queue, project=project,
                             messages=messages,
                             client_uuid=client_uuid)
     raise errors.QueueDoesNotExist(queue, project)
コード例 #4
0
ファイル: messages.py プロジェクト: eclipsek20/zaqar
    def stats(self, name, project=None):
        if not self._queue_ctrl.exists(name, project=project):
            raise errors.QueueDoesNotExist(name, project)

        total = self._message_ctrl._count(name, project)

        if total:
            claimed = self._claim_ctrl._count_messages(name, project)
        else:
            claimed = 0

        message_stats = {
            'claimed': claimed,
            'free': total - claimed,
            'total': total,
        }

        if total:
            try:
                newest = self._message_ctrl.first(name, project, -1)
                oldest = self._message_ctrl.first(name, project, 1)
            except errors.QueueIsEmpty:
                pass
            else:
                message_stats['newest'] = newest
                message_stats['oldest'] = oldest

        return {'messages': message_stats}
コード例 #5
0
ファイル: messages.py プロジェクト: rose/zaqar
    def post(self, queue, messages, client_uuid, project=None):
        if not self._queue_ctrl.exists(queue, project):
            raise errors.QueueDoesNotExist(queue, project)

        msgset_key = utils.msgset_key(queue, project)
        counter_key = utils.scope_queue_index(queue, project,
                                              MESSAGE_RANK_COUNTER_SUFFIX)

        message_ids = []
        now = timeutils.utcnow_ts()

        with self._client.pipeline() as pipe:
            for msg in messages:
                prepared_msg = Message(
                    ttl=msg['ttl'],
                    created=now,
                    client_uuid=client_uuid,
                    claim_id=None,
                    claim_expires=now,
                    body=msg.get('body', {}),
                )

                prepared_msg.to_redis(pipe)
                message_ids.append(prepared_msg.id)

            pipe.execute()

        # NOTE(kgriffs): If this call fails, we will return
        # an error to the client and the messages will be
        # orphaned, but Redis will remove them when they
        # expire, so we will just pretend they don't exist
        # in that case.
        self._index_messages(msgset_key, counter_key, message_ids)

        return message_ids
コード例 #6
0
ファイル: subscriptions.py プロジェクト: wenchma/zaqar
    def create(self, queue, subscriber, ttl, options, project=None):
        subscription_id = str(uuid.uuid4())
        subset_key = utils.scope_subscription_ids_set(queue, project,
                                                      SUBSCRIPTION_IDS_SUFFIX)

        source = queue
        now = timeutils.utcnow_ts()
        ttl = int(ttl)
        expires = now + ttl

        subscription = {
            'id': subscription_id,
            's': source,
            'u': subscriber,
            't': ttl,
            'e': expires,
            'o': options,
            'p': project
        }

        if not self._queue_ctrl.exists(queue, project):
            raise errors.QueueDoesNotExist(queue, project)
        try:
            # Pipeline ensures atomic inserts.
            with self._client.pipeline() as pipe:
                pipe.zadd(subset_key, 1,
                          subscription_id).hmset(subscription_id, subscription)
                pipe.execute()
            return subscription_id
        except redis.exceptions.ResponseError:
            return None
コード例 #7
0
ファイル: utils.py プロジェクト: rose/zaqar
def get_qid(driver, queue, project):
    sel = sa.sql.select([tables.Queues.c.id],
                        sa.and_(tables.Queues.c.project == project,
                                tables.Queues.c.name == queue))
    try:
        return driver.get(sel)[0]
    except NoResult:
        raise errors.QueueDoesNotExist(queue, project)
コード例 #8
0
    def _get(self, queue, message_id, project=None, check_queue=True):
        if check_queue and not self._queue_ctrl.exists(queue, project):
            raise errors.QueueDoesNotExist(queue, project)

        now = timeutils.utcnow_ts(True)

        headers, msg = self._find_message(queue, message_id, project)
        return utils._message_to_json(message_id, msg, headers, now)
コード例 #9
0
ファイル: queues.py プロジェクト: eclipsek20/zaqar
    def set_metadata(self, name, metadata, project=None):
        if not self.exists(name, project):
            raise errors.QueueDoesNotExist(name, project)

        key = utils.scope_queue_name(name, project)
        fields = {'m': self._packer(metadata)}

        self._client.hmset(key, fields)
コード例 #10
0
ファイル: queues.py プロジェクト: eclipsek20/zaqar
    def get_metadata(self, name, project=None):
        if not self.exists(name, project):
            raise errors.QueueDoesNotExist(name, project)

        queue_key = utils.scope_queue_name(name, project)
        metadata = self._get_queue_info(queue_key, b'm', None)[0]

        return self._unpacker(metadata)
コード例 #11
0
    def _list(self,
              queue,
              project=None,
              marker=None,
              limit=storage.DEFAULT_MESSAGES_PER_PAGE,
              echo=False,
              client_uuid=None,
              include_claimed=False,
              include_delayed=False,
              to_basic=True):

        if not self._queue_ctrl.exists(queue, project):
            raise errors.QueueDoesNotExist(queue, project)

        msgset_key = utils.msgset_key(queue, project)
        client = self._client

        if not marker and not include_claimed:
            # NOTE(kgriffs): Skip claimed messages at the head
            # of the queue; otherwise we would just filter them all
            # out and likely end up with an empty list to return.
            marker = self._find_first_unclaimed(queue, project, limit)
            start = client.zrank(msgset_key, marker) or 0
        else:
            rank = client.zrank(msgset_key, marker)
            start = rank + 1 if rank else 0

        message_ids = client.zrange(msgset_key, start, start + (limit - 1))

        messages = Message.from_redis_bulk(message_ids, client)

        # NOTE(prashanthr_): Build a list of filters for checking
        # the following:
        #
        #     1. Message is expired
        #     2. Message is claimed
        #     3. Message should not be echoed
        #
        now = timeutils.utcnow_ts()
        filters = [functools.partial(utils.msg_expired_filter, now=now)]

        if not include_claimed:
            filters.append(functools.partial(utils.msg_claimed_filter,
                                             now=now))

        if not include_delayed:
            filters.append(functools.partial(utils.msg_delayed_filter,
                                             now=now))

        if not echo:
            filters.append(
                functools.partial(utils.msg_echo_filter,
                                  client_uuid=client_uuid))

        marker = {}

        yield _filter_messages(messages, filters, to_basic, marker)
        yield marker['next']
コード例 #12
0
ファイル: messages.py プロジェクト: eclipsek20/zaqar
    def get(self, queue, message_id, project=None):
        if not self._queue_ctrl.exists(queue, project):
            raise errors.QueueDoesNotExist(queue, project)

        message = Message.from_redis(message_id, self._client)
        now = timeutils.utcnow_ts()

        if message and not utils.msg_expired_filter(message, now):
            return message.to_basic(now)
        else:
            raise errors.MessageDoesNotExist(message_id, queue, project)
コード例 #13
0
    def get_metadata(self, name, project):
        if project is None:
            project = ''

        try:
            sel = sa.sql.select([tables.Queues.c.metadata],
                                sa.and_(tables.Queues.c.project == project,
                                        tables.Queues.c.name == name))
            return utils.json_decode(self.driver.get(sel)[0])
        except utils.NoResult:
            raise errors.QueueDoesNotExist(name, project)
コード例 #14
0
ファイル: queues.py プロジェクト: yiyezhiqiu1228/zaqar
    def get_metadata(self, name, project):
        if project is None:
            project = ''

        sel = sa.sql.select([tables.Queues.c.metadata],
                            sa.and_(tables.Queues.c.project == project,
                                    tables.Queues.c.name == name))

        queue = self.driver.run(sel).fetchone()
        if queue is None:
            raise errors.QueueDoesNotExist(name, project)

        return utils.json_decode(queue[0])
コード例 #15
0
ファイル: subscriptions.py プロジェクト: wenchma/zaqar
    def get(self, queue, subscription_id, project=None):
        if not self._queue_ctrl.exists(queue, project):
            raise errors.QueueDoesNotExist(queue, project)

        subscription = SubscripitonEnvelope.from_redis(subscription_id,
                                                       self._client)
        now = timeutils.utcnow_ts()

        if subscription and not utils.subscription_expired_filter(
                subscription, now):
            return subscription.to_basic(now)
        else:
            raise errors.SubscriptionDoesNotExist(subscription_id)
コード例 #16
0
ファイル: messages.py プロジェクト: eclipsek20/zaqar
    def stats(self, name, project=None):
        if not self._queue_ctrl.exists(name, project=project):
            raise errors.QueueDoesNotExist(name, project)

        total = 0
        claimed = 0
        container = utils._message_container(name, project)

        try:
            _, objects = self._client.get_container(container)
        except swiftclient.ClientException as exc:
            if exc.http_status == 404:
                raise errors.QueueIsEmpty(name, project)

        newest = None
        oldest = None
        now = timeutils.utcnow_ts(True)
        for obj in objects:
            try:
                headers = self._client.head_object(container, obj['name'])
            except swiftclient.ClientException as exc:
                if exc.http_status != 404:
                    raise
            else:
                created = float(headers['x-timestamp'])
                created_iso = datetime.datetime.utcfromtimestamp(
                    created).strftime('%Y-%m-%dT%H:%M:%SZ')
                newest = {
                    'id': obj['name'],
                    'age': now - created,
                    'created': created_iso
                }
                if oldest is None:
                    oldest = copy.deepcopy(newest)
                total += 1
                if headers.get('x-object-meta-claimid'):
                    claimed += 1

        msg_stats = {
            'claimed': claimed,
            'free': total - claimed,
            'total': total,
        }
        if newest is not None:
            msg_stats['newest'] = newest
            msg_stats['oldest'] = oldest

        return {'messages': msg_stats}
コード例 #17
0
    def set_metadata(self, name, metadata, project):
        if project is None:
            project = ''

        update = (tables.Queues.update().where(
            sa.and_(tables.Queues.c.project == project,
                    tables.Queues.c.name == name)).values(
                        metadata=utils.json_encode(metadata)))

        res = self.driver.run(update)

        try:
            if res.rowcount != 1:
                raise errors.QueueDoesNotExist(name, project)
        finally:
            res.close()
コード例 #18
0
ファイル: messages.py プロジェクト: rose/zaqar
    def bulk_get(self, queue, message_ids, project=None):
        if not self._queue_ctrl.exists(queue, project):
            raise errors.QueueDoesNotExist(queue, project)

        # NOTE(prashanthr_): Pipelining is used here purely
        # for performance.
        with self._client.pipeline() as pipe:
            for mid in message_ids:
                    pipe.hgetall(mid)

            messages = pipe.execute()

        # NOTE(kgriffs): Skip messages that may have been deleted
        now = timeutils.utcnow_ts()
        return (Message.from_hmap(msg).to_basic(now)
                for msg in messages if msg)
コード例 #19
0
ファイル: messages.py プロジェクト: rose/zaqar
    def delete(self, queue, message_id, project=None, claim=None):
        if not self._queue_ctrl.exists(queue, project):
            raise errors.QueueDoesNotExist(queue, project)

        # 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(queue, project, claim)

        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 self._claim_ctrl._exists(queue, claim, project):
                raise errors.ClaimDoesNotExist(queue, project, claim)

            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:
                self._claim_ctrl._del_message(queue, project,
                                              msg_claim['id'], message_id,
                                              pipe)

            pipe.execute()
コード例 #20
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']})
コード例 #21
0
    def bulk_delete(self, queue, message_ids, project=None):
        if not self._queue_ctrl.exists(queue, project):
            raise errors.QueueDoesNotExist(queue, project)

        msgset_key = utils.msgset_key(queue, project)

        with self._client.pipeline() as pipe:
            for mid in message_ids:
                if not self._exists(mid):
                    continue

                pipe.delete(mid)
                pipe.zrem(msgset_key, mid)

                msg_claim = self._get_claim(mid)
                if msg_claim is not None:
                    self._claim_ctrl._del_message(queue, project,
                                                  msg_claim['id'], mid, pipe)
            pipe.execute()
コード例 #22
0
ファイル: pooling.py プロジェクト: rose/zaqar
 def _stats(self, name, project=None):
     control = self._get_controller(name, project)
     if control:
         return control.stats(name, project=project)
     raise errors.QueueDoesNotExist(name, project)
コード例 #23
0
ファイル: pooling.py プロジェクト: xglhjk6/zaqar
 def get(self, queue, message_id, project=None):
     control = self._get_controller(queue, project)
     if control:
         return control.get(queue, message_id=message_id,
                            project=project)
     raise errors.QueueDoesNotExist(queue, project)
コード例 #24
0
ファイル: pooling.py プロジェクト: xglhjk6/zaqar
 def _stats(self, name, project=None):
     mqHandler = self._get_controller(name, project)
     if mqHandler:
         return mqHandler.stats(name, project=project)
     raise errors.QueueDoesNotExist(name, project)
コード例 #25
0
ファイル: pooling.py プロジェクト: xglhjk6/zaqar
 def first(self, queue, project=None, sort=1):
     control = self._get_controller(queue, project)
     if control:
         return control.first(queue, project=project, sort=sort)
     raise errors.QueueDoesNotExist(queue, project)