예제 #1
0
    def test_timed_request(self):
        nc = NATS()
        msgs = []
        counter = 0

        @asyncio.coroutine
        def worker_handler(msg):
            nonlocal counter
            counter += 1
            msgs.append(msg)
            yield from nc.publish(msg.reply,
                                  'Reply:{}'.format(counter).encode())

        @asyncio.coroutine
        def slow_worker_handler(msg):
            yield from asyncio.sleep(0.5, loop=self.loop)
            yield from nc.publish(msg.reply, b'timeout by now...')

        yield from nc.connect(io_loop=self.loop)
        yield from nc.subscribe("help", cb=worker_handler)
        yield from nc.subscribe("slow.help", cb=slow_worker_handler)

        response = yield from nc.timed_request("help", b'please', timeout=1)
        self.assertEqual(b'Reply:1', response.data)
        response = yield from nc.timed_request("help", b'please', timeout=1)
        self.assertEqual(b'Reply:2', response.data)

        with self.assertRaises(ErrTimeout):
            yield from nc.timed_request("slow.help", b'please', timeout=0.1)
        yield from asyncio.sleep(1, loop=self.loop)
        yield from nc.close()
예제 #2
0
  def test_timed_request(self):
    nc = NATS()
    msgs = []
    counter = 0

    @asyncio.coroutine
    def worker_handler(msg):
      nonlocal counter
      counter += 1
      msgs.append(msg)
      yield from nc.publish(msg.reply, 'Reply:{}'.format(counter).encode())

    @asyncio.coroutine
    def slow_worker_handler(msg):
      yield from asyncio.sleep(0.5, loop=self.loop)
      yield from nc.publish(msg.reply, b'timeout by now...')

    yield from nc.connect(io_loop=self.loop)
    yield from nc.subscribe("help", cb=worker_handler)
    yield from nc.subscribe("slow.help", cb=slow_worker_handler)

    response = yield from nc.timed_request("help", b'please', timeout=1)
    self.assertEqual(b'Reply:1', response.data)
    response = yield from nc.timed_request("help", b'please', timeout=1)
    self.assertEqual(b'Reply:2', response.data)

    with self.assertRaises(ErrTimeout):
      yield from nc.timed_request("slow.help", b'please', timeout=0.1)
    yield from asyncio.sleep(1, loop=self.loop)
    yield from nc.close()
예제 #3
0
def run(loop):
    nc = Nats()
    yield from nc.connect(io_loop=loop)

    # Send a request and expect a single response and trigger timeout if not
    # faster than 50 ms.
    try:
        response = yield from nc.timed_request("conf.host", b'host', 0.050)
        print("Received response: {message}".format(message=response.data.decode()))
    except ErrTimeout:
        print("Request timed out")

    yield from nc.publish("log.info", b'initializing')
    yield from nc.publish("log.info", b'scraping item 1')

    @asyncio.coroutine
    def help_request(msg):
        subject = msg.subject
        reply = msg.reply
        data = msg.data.decode()
        print("Received a message on '{subject} {reply}': {data}".format(
            subject=subject, reply=reply, data=data
)       )
        yield from nc.publish(reply, b'I can help')

    # Use queue named 'workers' for distributing requests among subscribers.
    yield from nc.subscribe("cmd.help", "workers", help_request)

    yield from asyncio.sleep(20, loop=loop)
    yield from nc.close()
예제 #4
0
def go(loop):
    nc = NATS()

    try:
        yield from nc.connect(io_loop=loop)
    except:
        pass

    @asyncio.coroutine
    def message_handler(msg):
        print("[Received on '{}']: {}".format(msg.subject, msg.data.decode()))

    try:
        # Interested in receiving 2 messages from the 'discover' subject.
        sid = yield from nc.subscribe("discover", "", message_handler)
        yield from nc.auto_unsubscribe(sid, 2)

        yield from nc.publish("discover", b'hello')
        yield from nc.publish("discover", b'world')

        # Following 2 messages won't be received.
        yield from nc.publish("discover", b'again')
        yield from nc.publish("discover", b'!!!!!')
    except ErrConnectionClosed:
        print("Connection closed prematurely")

    @asyncio.coroutine
    def request_handler(msg):
        print("[Request on '{} {}']: {}".format(msg.subject, msg.reply, msg.data.decode()))
        yield from nc.publish(msg.reply, b'OK')

    if nc.is_connected:
        
        # Subscription using a 'workers' queue so that only a single subscriber
        # gets a request at a time.
        yield from nc.subscribe("help", "workers", cb=request_handler)

        try:
            # Make a request expecting a single response within 500 ms,
            # otherwise raising a timeout error.
            msg = yield from nc.timed_request("help", b'help please', 0.500)
            print("[Response]: {}".format(msg.data))

            # Make a roundtrip to the server to ensure messages
            # that sent messages have been processed already.
            yield from nc.flush(0.500)
        except ErrTimeout:
            print("[Error] Timeout!")

        # Wait a bit for message to be dispatched...
        yield from asyncio.sleep(1, loop=loop)

        # Detach from the server.
        yield from nc.close()

    if nc.last_error is not None:
        print("Last Error: {}".format(nc.last_error))

    if nc.is_closed:
        print("Disconnected.")
예제 #5
0
def run(loop):
    nc = NATS()

    ssl_ctx = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)
    ssl_ctx.protocol = ssl.PROTOCOL_TLSv1_2
    ssl_ctx.load_verify_locations('../tests/certs/ca.pem')
    ssl_ctx.load_cert_chain(certfile='../tests/certs/client-cert.pem',
                            keyfile='../tests/certs/client-key.pem')
    yield from nc.connect(io_loop=loop, tls=ssl_ctx)

    @asyncio.coroutine
    def message_handler(msg):
        subject = msg.subject
        reply = msg.reply
        data = msg.data.decode()
        print("Received a message on '{subject} {reply}': {data}".format(
            subject=subject, reply=reply, data=data))

    # Simple publisher and async subscriber via coroutine.
    sid = yield from nc.subscribe("foo", cb=message_handler)

    # Stop receiving after 2 messages.
    yield from nc.auto_unsubscribe(sid, 2)
    yield from nc.publish("foo", b'Hello')
    yield from nc.publish("foo", b'World')
    yield from nc.publish("foo", b'!!!!!')

    @asyncio.coroutine
    def help_request(msg):
        subject = msg.subject
        reply = msg.reply
        data = msg.data.decode()
        print("Received a message on '{subject} {reply}': {data}".format(
            subject=subject, reply=reply, data=data))
        yield from nc.publish(reply, b'I can help')

    # Use queue named 'workers' for distributing requests
    # among subscribers.
    yield from nc.subscribe("help", "workers", help_request)

    # Send a request and expect a single response
    # and trigger timeout if not faster than 50 ms.
    try:
        response = yield from nc.timed_request("help", b'help me', 0.050)
        print("Received response: {message}".format(
            message=response.data.decode()))
    except ErrTimeout:
        print("Request timed out")

    yield from asyncio.sleep(1, loop=loop)
    yield from nc.close()
예제 #6
0
파일: tls.py 프로젝트: Gr1N/asyncio-nats
def run(loop):
    nc = NATS()

    ssl_ctx = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)
    ssl_ctx.protocol = ssl.PROTOCOL_TLSv1_2
    ssl_ctx.load_verify_locations('../tests/certs/ca.pem')
    ssl_ctx.load_cert_chain(certfile='../tests/certs/client-cert.pem',
                            keyfile='../tests/certs/client-key.pem')
    yield from nc.connect(io_loop=loop, tls=ssl_ctx)

    @asyncio.coroutine
    def message_handler(msg):
        subject = msg.subject
        reply = msg.reply
        data = msg.data.decode()
        print("Received a message on '{subject} {reply}': {data}".format(
            subject=subject, reply=reply, data=data))

    # Simple publisher and async subscriber via coroutine.
    sid = yield from nc.subscribe("foo", cb=message_handler)

    # Stop receiving after 2 messages.
    yield from nc.auto_unsubscribe(sid, 2)
    yield from nc.publish("foo", b'Hello')
    yield from nc.publish("foo", b'World')
    yield from nc.publish("foo", b'!!!!!')

    @asyncio.coroutine
    def help_request(msg):
        subject = msg.subject
        reply = msg.reply
        data = msg.data.decode()
        print("Received a message on '{subject} {reply}': {data}".format(
            subject=subject, reply=reply, data=data))
        yield from nc.publish(reply, b'I can help')

    # Use queue named 'workers' for distributing requests
    # among subscribers.
    yield from nc.subscribe("help", "workers", help_request)

    # Send a request and expect a single response
    # and trigger timeout if not faster than 50 ms.
    try:
        response = yield from nc.timed_request("help", b'help me', 0.050)
        print("Received response: {message}".format(message=response.data.decode()))
    except ErrTimeout:
        print("Request timed out")

    yield from asyncio.sleep(1, loop=loop)
    yield from nc.close()
예제 #7
0
def main(loop):
    parser = argparse.ArgumentParser()
    parser.add_argument('-n',
                        '--iterations',
                        default=DEFAULT_ITERATIONS,
                        type=int)
    parser.add_argument('-S', '--subject', default='test')
    parser.add_argument('--servers', default=[], action='append')
    args = parser.parse_args()

    servers = args.servers
    if len(args.servers) < 1:
        servers = ["nats://127.0.0.1:4222"]
    opts = {"servers": servers}

    # Make sure we're connected to a server first...
    nc = NATS()
    try:
        yield from nc.connect(**opts)
    except Exception as e:
        sys.stderr.write("ERROR: {0}".format(e))
        show_usage_and_die()

    @asyncio.coroutine
    def handler(msg):
        yield from nc.publish(msg.reply, b'')

    yield from nc.subscribe(args.subject, cb=handler)

    # Start the benchmark
    start = time.monotonic()
    to_send = args.iterations

    print("Sending {0} request/responses on [{1}]".format(
        args.iterations, args.subject))
    while to_send > 0:
        to_send -= 1
        if to_send == 0:
            break

        yield from nc.timed_request(args.subject, b'')
        if (to_send % HASH_MODULO) == 0:
            sys.stdout.write("#")
            sys.stdout.flush()

    duration = time.monotonic() - start
    ms = "%.3f" % ((duration / args.iterations) * 1000)
    print("\nTest completed : {0} ms avg request/response latency".format(ms))
    yield from nc.close()
예제 #8
0
def run(loop):
    nc = NATS()

    yield from nc.connect(io_loop=loop)

    @asyncio.coroutine
    def message_handler(msg):
        subject = msg.subject
        reply = msg.reply
        data = msg.data.decode()
        print("Received a message on '{subject} {reply}': {data}".format(
            subject=subject, reply=reply, data=data))

    # Simple publisher and async subscriber via coroutine.
    sid = yield from nc.subscribe("foo", cb=message_handler)

    # Stop receiving after 2 messages.
    yield from nc.auto_unsubscribe(sid, 2)
    yield from nc.publish("foo", b'Hello')
    yield from nc.publish("foo", b'World')
    yield from nc.publish("foo", b'!!!!!')

    @asyncio.coroutine
    def help_request(msg):
        subject = msg.subject
        reply = msg.reply
        data = msg.data.decode()
        print("Received a message on '{subject} {reply}': {data}".format(
            subject=subject, reply=reply, data=data))
        yield from nc.publish(reply, b'I can help')

    # Use queue named 'workers' for distributing requests
    # among subscribers.
    yield from nc.subscribe("help", "workers", help_request)

    # Send a request and expect a single response
    # and trigger timeout if not faster than 50 ms.
    try:
        response = yield from nc.timed_request("help", b'help me', 0.050)
        print("Received response: {message}".format(
            message=response.data.decode()))
    except ErrTimeout:
        print("Request timed out")

    yield from asyncio.sleep(1, loop=loop)
    yield from nc.close()
예제 #9
0
파일: basic.py 프로젝트: Gr1N/asyncio-nats
def run(loop):
  nc = NATS()

  yield from nc.connect(io_loop=loop)

  @asyncio.coroutine
  def message_handler(msg):
    subject = msg.subject
    reply = msg.reply
    data = msg.data.decode()
    print("Received a message on '{subject} {reply}': {data}".format(
      subject=subject, reply=reply, data=data))

  # Simple publisher and async subscriber via coroutine.
  sid = yield from nc.subscribe("foo", cb=message_handler)

  # Stop receiving after 2 messages.
  yield from nc.auto_unsubscribe(sid, 2)
  yield from nc.publish("foo", b'Hello')
  yield from nc.publish("foo", b'World')
  yield from nc.publish("foo", b'!!!!!')

  @asyncio.coroutine
  def help_request(msg):
    subject = msg.subject
    reply = msg.reply
    data = msg.data.decode()
    print("Received a message on '{subject} {reply}': {data}".format(
      subject=subject, reply=reply, data=data))
    yield from nc.publish(reply, b'I can help')

  # Use queue named 'workers' for distributing requests
  # among subscribers.
  yield from nc.subscribe("help", "workers", help_request)

  # Send a request and expect a single response
  # and trigger timeout if not faster than 50 ms.
  try:
    response = yield from nc.timed_request("help", b'help me', 0.050)
    print("Received response: {message}".format(message=response.data.decode()))
  except ErrTimeout:
    print("Request timed out")

  yield from asyncio.sleep(1, loop=loop)
  yield from nc.close()
예제 #10
0
def main(loop):
  parser = argparse.ArgumentParser()
  parser.add_argument('-n', '--iterations', default=DEFAULT_ITERATIONS, type=int)
  parser.add_argument('-S', '--subject', default='test')
  parser.add_argument('--servers', default=[], action='append')
  args = parser.parse_args()

  servers = args.servers
  if len(args.servers) < 1:
    servers = ["nats://127.0.0.1:4222"]
  opts = { "servers": servers }

  # Make sure we're connected to a server first...
  nc = NATS()
  try:
    yield from nc.connect(**opts)
  except Exception as e:
    sys.stderr.write("ERROR: {0}".format(e))
    show_usage_and_die()

  @asyncio.coroutine
  def handler(msg):
    yield from nc.publish(msg.reply, b'')
  yield from nc.subscribe(args.subject, cb=handler)

  # Start the benchmark
  start = time.monotonic()
  to_send = args.iterations

  print("Sending {0} request/responses on [{1}]".format(
      args.iterations, args.subject))
  while to_send > 0:
    to_send -= 1
    if to_send == 0:
      break

    yield from nc.timed_request(args.subject, b'')
    if (to_send % HASH_MODULO) == 0:
      sys.stdout.write("#")
      sys.stdout.flush()

  duration = time.monotonic() - start
  ms = "%.3f" % ((duration/args.iterations) * 1000)
  print("\nTest completed : {0} ms avg request/response latency".format(ms))
  yield from nc.close()
예제 #11
0
    def test_reconnect_with_auth_token(self):
        nc = NATS()

        disconnected_count = 0
        reconnected_count = 0
        closed_count = 0
        err_count = 0

        @asyncio.coroutine
        def disconnected_cb():
            nonlocal disconnected_count
            disconnected_count += 1

        @asyncio.coroutine
        def reconnected_cb():
            nonlocal reconnected_count
            reconnected_count += 1

        @asyncio.coroutine
        def closed_cb():
            nonlocal closed_count
            closed_count += 1

        counter = 0

        @asyncio.coroutine
        def worker_handler(msg):
            nonlocal counter
            counter += 1
            if msg.reply != "":
                yield from nc.publish(msg.reply,
                                      'Reply:{}'.format(counter).encode())

        options = {
            'servers': [
                "nats://[email protected]:4223",
                "nats://[email protected]:4224",
            ],
            'disconnected_cb':
            disconnected_cb,
            'closed_cb':
            closed_cb,
            'reconnected_cb':
            reconnected_cb,
            'dont_randomize':
            True,
            'io_loop':
            self.loop
        }
        yield from nc.connect(**options)
        yield from nc.subscribe("test", cb=worker_handler)
        self.assertIn('auth_required', nc._server_info)
        self.assertTrue(nc.is_connected)

        # Trigger a reconnnect
        yield from self.loop.run_in_executor(None, self.server_pool[0].stop)
        yield from asyncio.sleep(1, loop=self.loop)

        yield from nc.subscribe("test", cb=worker_handler)
        response = yield from nc.timed_request("test", b'data', timeout=1)
        self.assertEqual(b'Reply:1', response.data)

        yield from nc.close()
        self.assertTrue(nc.is_closed)
        self.assertFalse(nc.is_connected)
        self.assertEqual(1, closed_count)
        self.assertEqual(2, disconnected_count)
        self.assertEqual(1, reconnected_count)
예제 #12
0
    def test_auth_reconnect(self):
        nc = NATS()
        disconnected_count = 0
        reconnected_count = 0
        closed_count = 0
        err_count = 0

        @asyncio.coroutine
        def disconnected_cb():
            nonlocal disconnected_count
            disconnected_count += 1

        @asyncio.coroutine
        def reconnected_cb():
            nonlocal reconnected_count
            reconnected_count += 1

        @asyncio.coroutine
        def closed_cb():
            nonlocal closed_count
            closed_count += 1

        @asyncio.coroutine
        def err_cb(e):
            nonlocal err_count
            err_count += 1

        counter = 0

        @asyncio.coroutine
        def worker_handler(msg):
            nonlocal counter
            counter += 1
            if msg.reply != "":
                yield from nc.publish(msg.reply,
                                      'Reply:{}'.format(counter).encode())

        options = {
            'servers': [
                "nats://*****:*****@127.0.0.1:4223",
                "nats://*****:*****@127.0.0.1:4224"
            ],
            'io_loop':
            self.loop,
            'disconnected_cb':
            disconnected_cb,
            'closed_cb':
            closed_cb,
            'reconnected_cb':
            reconnected_cb,
            'error_cb':
            err_cb,
            'dont_randomize':
            True,
        }
        yield from nc.connect(**options)
        self.assertTrue(nc.is_connected)

        yield from nc.subscribe("one", cb=worker_handler)
        yield from nc.subscribe("two", cb=worker_handler)
        yield from nc.subscribe("three", cb=worker_handler)

        response = yield from nc.timed_request("one", b'Help!', timeout=1)
        self.assertEqual(b'Reply:1', response.data)

        # Stop the first server and connect to another one asap.
        yield from self.loop.run_in_executor(None, self.server_pool[0].stop)

        # FIXME: Find better way to wait for the server to be stopped.
        yield from asyncio.sleep(0.5, loop=self.loop)

        response = yield from nc.timed_request("three", b'Help!', timeout=1)
        self.assertEqual('Reply:2'.encode(), response.data)
        yield from asyncio.sleep(0.5, loop=self.loop)
        yield from nc.close()
        self.assertEqual(1, nc.stats['reconnects'])
        self.assertEqual(1, closed_count)
        self.assertEqual(2, disconnected_count)
        self.assertEqual(1, reconnected_count)
        self.assertEqual(1, err_count)
예제 #13
0
    def test_tls_reconnect(self):

        nc = NATS()
        disconnected_count = 0
        reconnected_count = 0
        closed_count = 0
        err_count = 0

        @asyncio.coroutine
        def disconnected_cb():
            nonlocal disconnected_count
            disconnected_count += 1

        @asyncio.coroutine
        def reconnected_cb():
            nonlocal reconnected_count
            reconnected_count += 1

        @asyncio.coroutine
        def closed_cb():
            nonlocal closed_count
            closed_count += 1

        @asyncio.coroutine
        def err_cb(e):
            nonlocal err_count
            err_count += 1

        counter = 0

        @asyncio.coroutine
        def worker_handler(msg):
            nonlocal counter
            counter += 1
            if msg.reply != "":
                yield from nc.publish(msg.reply,
                                      'Reply:{}'.format(counter).encode())

        options = {
            'servers': [
                "nats://*****:*****@localhost:4223",
                "nats://*****:*****@localhost:4224"
            ],
            'io_loop':
            self.loop,
            'disconnected_cb':
            disconnected_cb,
            'closed_cb':
            closed_cb,
            'reconnected_cb':
            reconnected_cb,
            'error_cb':
            err_cb,
            'dont_randomize':
            True,
            'tls':
            self.ssl_ctx
        }
        yield from nc.connect(**options)
        self.assertTrue(nc.is_connected)

        yield from nc.subscribe("example", cb=worker_handler)
        response = yield from nc.timed_request("example", b'Help!', timeout=1)
        self.assertEqual(b'Reply:1', response.data)

        # Trigger a reconnnect and should be fine
        yield from self.loop.run_in_executor(None, self.server_pool[0].stop)
        yield from asyncio.sleep(1, loop=self.loop)

        yield from nc.subscribe("example", cb=worker_handler)
        response = yield from nc.timed_request("example", b'Help!', timeout=1)
        self.assertEqual(b'Reply:2', response.data)

        yield from nc.close()
        self.assertTrue(nc.is_closed)
        self.assertFalse(nc.is_connected)
        self.assertEqual(1, nc.stats['reconnects'])
        self.assertEqual(1, closed_count)
        self.assertEqual(2, disconnected_count)
        self.assertEqual(1, reconnected_count)
        self.assertEqual(1, err_count)
예제 #14
0
파일: natsio.py 프로젝트: jplf/jplab
class NatsIo(object):
    """
    asyncio NATS client

    """
    def __init__(self,
                 host='127.0.0.1',
                 port='4222',
                 streaming_id=None,
                 cluster='svom-cluster'):
        self.nc = NATS()
        self.server = host
        self.is_connected = False
        self.streaming_id = streaming_id
        self.cluster = cluster
        self.sc = None
        self.loop = None
        try:
            self.loop = asyncio.get_event_loop()
        except RuntimeError:
            LOG.info(
                'Failed to retrieve asyncio event loop. Creating a new one...')
            self.loop = asyncio.new_event_loop()

        self.loop.run_until_complete(self._connect(servers=[self.server]))
        if streaming_id is not None:
            if has_streaming is True:
                self.sc = STAN()
                self.loop.run_until_complete(self._stan_connect())
            else:
                LOG.error("Can't run client without asyncio-nats-streaming")
                sys.exit(1)

        self.nats_server = NATSClient(self.nc, self.loop)
        self.nats_server.start()

    def is_streaming(self):
        return True if self.streaming_id is not None else False

    def _connect(self, servers):
        """connect"""
        while not self.is_connected:
            try:
                LOG.info('Attempting connection to nats server ' + servers[0])
                yield from self.nc.connect(servers=servers, io_loop=self.loop)
                yield from self.nc.flush()
            except Exception:
                LOG.exception('Connection failed.')
                LOG.info('Retrying connection in 5s.')
                yield from asyncio.sleep(5)
            else:
                self.is_connected = True
                LOG.info('Connected.')

        if self.streaming_id is not None:
            self.is_connected = False

    @asyncio.coroutine
    def _stan_connect(self):
        """connect"""
        while not self.is_connected:
            try:
                LOG.info('Attempting connection to server cluster \'' +
                         self.cluster + '\' with clientID \'' +
                         self.streaming_id + '\'')
                yield from self.sc.connect(self.cluster,
                                           self.streaming_id,
                                           nats=self.nc)
            except Exception:
                LOG.exception('Connection failed.')
                LOG.info('Retrying streaming server connection in 5s.')
                yield from asyncio.sleep(5)
            else:
                self.is_connected = True
                LOG.info('Connected to streaming server.')

    def subscribe(self, subject, handler=None):
        """launch subscription as async task"""
        if not self.is_connected:
            LOG.info("Awaiting to be connected to subscribe")
            self.loop.call_later(5, self.subscribe, subject, handler)
        if handler is None:
            handler = self._default_handler
        if self.streaming_id is None:
            asyncio.run_coroutine_threadsafe(self._subscribe(subject, handler),
                                             loop=self.loop)
        else:
            asyncio.run_coroutine_threadsafe(self._stan_subscribe(
                subject, handler),
                                             loop=self.loop)

    @asyncio.coroutine
    def _subscribe(self, subject, handler):
        """new subscription or handler change"""
        LOG.info('Subscribing to subject \'' + subject + '\'')
        try:
            yield from self.nc.subscribe(subject, cb=handler)
        except Exception:
            LOG.exception('Subscription failed.')
        else:
            LOG.info('Subscribed to subject  \'' + subject + '\'')

    @asyncio.coroutine
    def _stan_subscribe(self, subject, handler):
        """new subscription or handler change"""
        LOG.info('Subscribing to subject \'' + subject + '\'')
        try:
            # No need to custom durable name since 'clientID+durable name' is checked
            yield from self.sc.subscribe(subject,
                                         durable_name=handler.__name__,
                                         cb=handler)
        except Exception as e:
            LOG.exception('Subscription to \'%s\' failed' % subject)
        else:
            LOG.info('Handler \'%s\' subscribed to subject \'%s\'' %
                     (handler.__name__, subject))

    def publish(self, subject, data, with_reply=False):
        """launch publish as async task"""
        if isinstance(data, str):
            data = data.encode()
        if with_reply is False:
            if self.streaming_id is None:
                asyncio.run_coroutine_threadsafe(self._publish(subject, data),
                                                 loop=self.loop)
            else:
                asyncio.run_coroutine_threadsafe(self._stan_publish(subject,\
                                                 data), loop=self.loop)
        else:
            if self.streaming_id is None:
                future = asyncio.run_coroutine_threadsafe(\
                    self._publish(subject,\
                    data, with_reply=True), loop=self.loop)
                try:
                    result = future.result(1)
                    if result is None:
                        LOG.error('Message received no response')
                        return None
                except Exception:
                    LOG.exception('Timed request publishing exception')
                else:
                    return result
            else:
                LOG.error('NATS Streaming publish cannot handle replies')

    @asyncio.coroutine
    def _publish(self, subject, data, with_reply=False):
        """Nats transport data : bytes or str"""
        try:
            if with_reply is False:
                yield from self.nc.publish(subject, data)
            else:
                yield from self.nc.timed_request(subject, data)
        except Exception as e:
            LOG.exception('Publication failed.')

    @asyncio.coroutine
    def _stan_publish(self, subject, data):
        """Nats transport data : bytes or str"""
        try:
            yield from self.sc.publish(subject,\
                                     data, ack_handler=self._ack_handler)
        except Exception as e:
            LOG.exception('Publication failed, is \'' + \
                           subject + '\' a valid channel?')

    @asyncio.coroutine
    def _default_handler(self, msg):
        """Application handler data : str"""
        LOG.debug("--- Received: " + msg.subject + msg.data.decode())
        if self.streaming_id is not None:
            yield from self.sc.ack(msg)

    @asyncio.coroutine
    def ack(self, msg):
        yield from self.sc.ack(msg)

    @asyncio.coroutine
    def _ack_handler(self, ack):
        LOG.debug('Delivery ack received: {}'.format(ack.guid))

    def stop(self):
        LOG.debug('Trying to stop properly NatsIo: ')
        asyncio.run_coroutine_threadsafe(self.nc.flush(), loop=self.loop)
        asyncio.run_coroutine_threadsafe(self.nc.close(), loop=self.loop)
        try:
            time.sleep(1)
            self.loop.call_soon_threadsafe(self.loop.stop)
        except Exception as e:
            LOG.debug(e)
        try:
            time.sleep(1)
            if self.loop.is_running():
                LOG.debug('loop.is_running: ' + str(self.loop.is_running()))
                self.loop.call_soon_threadsafe(self.loop.close())
        except Exception as e:
            LOG.debug(e)
        self.nats_server.join()
예제 #15
0
  def test_auth_reconnect(self):
    nc = NATS()
    disconnected_count = 0
    reconnected_count = 0
    closed_count = 0
    err_count = 0

    @asyncio.coroutine
    def disconnected_cb():
      nonlocal disconnected_count
      disconnected_count += 1

    @asyncio.coroutine
    def reconnected_cb():
      nonlocal reconnected_count
      reconnected_count += 1

    @asyncio.coroutine
    def closed_cb():
      nonlocal closed_count
      closed_count += 1

    @asyncio.coroutine
    def err_cb():
      nonlocal err_count
      err_count += 1

    counter = 0
    @asyncio.coroutine
    def worker_handler(msg):
      nonlocal counter
      counter += 1
      if msg.reply != "":
        yield from nc.publish(msg.reply, 'Reply:{}'.format(counter).encode())

    options = {
      'servers': [
        "nats://*****:*****@127.0.0.1:4223",
        "nats://*****:*****@127.0.0.1:4224"
        ],
      'io_loop': self.loop,
      'disconnected_cb': disconnected_cb,
      'closed_cb': closed_cb,
      'reconnected_cb': reconnected_cb,
      'error_cb': err_cb,
      'dont_randomize': True,
      }
    yield from nc.connect(**options)
    self.assertTrue(nc.is_connected)

    yield from nc.subscribe("one", cb=worker_handler)
    yield from nc.subscribe("two", cb=worker_handler)
    yield from nc.subscribe("three", cb=worker_handler)

    response = yield from nc.timed_request("one", b'Help!', timeout=1)
    self.assertEqual(b'Reply:1', response.data)

    # Stop the first server and connect to another one asap.
    yield from self.loop.run_in_executor(None, self.server_pool[0].stop)

    # FIXME: Find better way to wait for the server to be stopped.
    yield from asyncio.sleep(0.5, loop=self.loop)

    response = yield from nc.timed_request("three", b'Help!', timeout=1)
    self.assertEqual('Reply:2'.encode(), response.data)
    yield from asyncio.sleep(0.5, loop=self.loop)
    yield from nc.close()
    self.assertEqual(1, nc.stats['reconnects'])
    self.assertEqual(1, closed_count)
    self.assertEqual(2, disconnected_count)
    self.assertEqual(1, reconnected_count)
    self.assertEqual(0, err_count)
예제 #16
0
def go(loop):
    nc = NATS()

    try:
        yield from nc.connect(io_loop=loop)
    except:
        pass

    @asyncio.coroutine
    def message_handler(msg):
        print("[Received on '{}']: {}".format(msg.subject, msg.data.decode()))

    try:
        # Interested in receiving 2 messages from the 'discover' subject.
        sid = yield from nc.subscribe("discover", "", message_handler)
        yield from nc.auto_unsubscribe(sid, 2)

        yield from nc.publish("discover", b'hello')
        yield from nc.publish("discover", b'world')

        # Following 2 messages won't be received.
        yield from nc.publish("discover", b'again')
        yield from nc.publish("discover", b'!!!!!')
    except ErrConnectionClosed:
        print("Connection closed prematurely")

    @asyncio.coroutine
    def request_handler(msg):
        print("[Request on '{} {}']: {}".format(msg.subject, msg.reply,
                                                msg.data.decode()))
        yield from nc.publish(msg.reply, b'OK')

    if nc.is_connected:

        # Subscription using a 'workers' queue so that only a single subscriber
        # gets a request at a time.
        yield from nc.subscribe("help", "workers", cb=request_handler)

        try:
            # Make a request expecting a single response within 500 ms,
            # otherwise raising a timeout error.
            msg = yield from nc.timed_request("help", b'help please', 0.500)
            print("[Response]: {}".format(msg.data))

            # Make a roundtrip to the server to ensure messages
            # that sent messages have been processed already.
            yield from nc.flush(0.500)
        except ErrTimeout:
            print("[Error] Timeout!")

        # Wait a bit for message to be dispatched...
        yield from asyncio.sleep(1, loop=loop)

        # Detach from the server.
        yield from nc.close()

    if nc.last_error is not None:
        print("Last Error: {}".format(nc.last_error))

    if nc.is_closed:
        print("Disconnected.")