예제 #1
0
    async def get_response(self, request_id) -> Awaitable:
        channel_name = QUEUE_PREFIX + request_id
        logger.debug('SUBSCRIBE %s', channel_name)
        channel = (await self.pool.subscribe(channel_name))[0]

        async def get_message():
            wait_coro = asyncio.ensure_future(channel.wait_message())
            timeout_coro = asyncio.ensure_future(
                asyncio.sleep(self.request_timeout))
            done = set()
            try:
                done, running = await asyncio.wait(
                    [wait_coro, timeout_coro],
                    return_when=asyncio.FIRST_COMPLETED)
            except Exception as error:  # pragma: no cover
                logger.error('Error while waiting for message:', error)
                raise exceptions.RadicalException(
                    f'Error while waiting for message: {str(error)}')
            else:
                if timeout_coro in done:
                    raise exceptions.TimeoutException(
                        'Timeout while waiting for response.')
                message = await channel.get()
                return message
            finally:
                timeout_coro.cancel()
                try:
                    await self.pool.unsubscribe(channel_name)
                except Exception as error:  # pragma: no cover
                    raise exceptions.TransportException(str(error))
                channel.close()

        return get_message()
예제 #2
0
 async def start(self):
     self.pool = await aioredis.create_redis_pool(
         self.transport_url,
         loop=self.loop,
         minsize=4  # At lest 2: one for BLPOP, other for PUBLISH
     )
     logger.debug('Redis transport started')
예제 #3
0
 async def call(self, queue_name, method, *args, **kwargs):
     logger.debug('Calling %s from %s (nowait mode)', method, queue_name)
     radical_request = RadicalRequest(signature=Signature(method=method,
                                                          args=args,
                                                          kwargs=kwargs),
                                      reply_to=None)
     data = self.serializer.encode_request(radical_request)
     await self.transport.send_to(queue_name, data)
예제 #4
0
 async def get_next_request(self):
     source_name = QUEUE_PREFIX + self.queue_name
     try:
         result = await self.pool.execute('blpop', source_name, 1)
         if result is not None:
             logger.debug('BLPOP %s', source_name)
             return result[1]
     except Exception as error:
         logger.error(f'ERROR: {repr(error)}, retrying in 1 second')
         await asyncio.sleep(1)
예제 #5
0
 async def send_to(self, queue_name, message):
     source_name = QUEUE_PREFIX + queue_name
     async with self.pool.acquire() as conn:
         async with conn.cursor() as cursor:
             logger.debug(f'Sending request to {queue_name}')
             try:
                 await self._lock(cursor)
                 await cursor.execute(
                     f'INSERT INTO {source_name}(data) VALUES(%s)',
                     [message])
             finally:
                 await self._unlock(cursor)
예제 #6
0
 async def get_message():
     async with self.pool.acquire() as conn:
         async with conn.cursor() as cursor:
             logger.debug(f'Waiting for response to {request_id}')
             try:
                 await cursor.execute(f'LISTEN {channel_name}')
                 msg = await asyncio.wait_for(conn.notifies.get(),
                                              self.request_timeout)
                 return msg.payload
             except asyncio.TimeoutError:
                 raise exceptions.TimeoutException(
                     'Timeout while waiting for response.')
             finally:
                 await cursor.execute(f'UNLISTEN {channel_name}')
예제 #7
0
 async def call_wait(self, queue_name, method, *args, **kwargs):
     logger.debug('Calling %s from %s (wait mode)', method, queue_name)
     message_id = uuid.uuid1().hex
     response_coroutine = await self.transport.get_response(message_id)
     response_future = asyncio.ensure_future(response_coroutine,
                                             loop=self.loop)
     radical_request = RadicalRequest(signature=Signature(method=method,
                                                          args=args,
                                                          kwargs=kwargs),
                                      reply_to=message_id)
     data = self.serializer.encode_request(radical_request)
     await self.transport.send_to(queue_name, data)
     response = await response_future
     # TODO: Add timeout
     radical_response = self.serializer.decode_response(response)
     if radical_response.error:
         raise RadicalException(radical_response.error)
     return radical_response.result
예제 #8
0
 async def get_next_request(self):
     result = None
     async with self.pool.acquire() as conn:
         async with conn.cursor() as cursor:
             try:
                 await self._lock(cursor)
                 await cursor.execute(
                     f'SELECT * FROM {self.request_table} LIMIT 1')
                 row = await cursor.fetchone()
                 if row:
                     logger.debug('Received new request in queue table.')
                     id_, data = row
                     await cursor.execute(
                         f'DELETE FROM {self.request_table} WHERE id = {id_}'
                     )
                     return bytes(data)
             finally:
                 await self._unlock(cursor)
     await asyncio.sleep(1)
     return result
예제 #9
0
 async def start(self):
     self.closed.clear()
     self.pool = await aiopg.create_pool(host=self.urlinfo.hostname,
                                         port=self.urlinfo.port or 5432,
                                         database=self.urlinfo.path[1:],
                                         user=self.urlinfo.username,
                                         password=self.urlinfo.password)
     async with self.pool.acquire() as conn:
         async with conn.cursor() as cursor:
             await self._lock(cursor)
             await cursor.execute(
                 'SELECT COUNT(*) FROM pg_tables WHERE tablename = %s',
                 [self.request_table])
             count, = await cursor.fetchone()
             if not count:
                 logger.debug('Creating queue table.')
                 await cursor.execute(
                     f'CREATE TABLE {self.request_table}(id serial, data bytea)'
                 )
             await self._unlock(cursor)
     logger.debug('Postgres transport started')
예제 #10
0
 async def send_to(self, queue_name, message):
     source_name = QUEUE_PREFIX + queue_name
     logger.debug('LPUSH %s', source_name)
     await self.pool.execute('lpush', source_name, message)
예제 #11
0
 async def reply_to(self, request_id, message):
     source_name = QUEUE_PREFIX + request_id
     logger.debug('PUBLISH %s', source_name)
     await self.pool.execute('publish', source_name, message)
예제 #12
0
 async def reply_to(self, request_id, message):
     source_name = QUEUE_PREFIX + request_id
     async with self.pool.acquire() as conn:
         async with conn.cursor() as cursor:
             logger.debug(f'NOTIFY {source_name}')
             await cursor.execute(f'NOTIFY {source_name}, %s', [message])