def timed_request(self, subject, payload, timeout=0.5): """ Implements the request/response pattern via pub/sub using an ephemeral subscription which will be published with a limited interest of 1 reply returning the response or raising a Timeout error. ->> SUB _INBOX.2007314fe0fcb2cdc2a2914c1 90 ->> UNSUB 90 1 ->> PUB hello _INBOX.2007314fe0fcb2cdc2a2914c1 5 ->> MSG_PAYLOAD: world <<- MSG hello 2 _INBOX.2007314fe0fcb2cdc2a2914c1 5 """ inbox = new_inbox() future = asyncio.Future(loop=self._loop) sid = yield from self.subscribe(inbox, future=future, max_msgs=1) yield from self.auto_unsubscribe(sid, 1) yield from self.publish_request(subject, inbox, payload) try: msg = yield from asyncio.wait_for(future, timeout, loop=self._loop) return msg except asyncio.TimeoutError: future.cancel() raise ErrTimeout
def __init__(self, nats_client: Client, subject: str, inbox=''): super().__init__(request_size_limit=_NATS_MAX_MESSAGE_SIZE) self._nats_client = nats_client self._subject = subject self._inbox = inbox or new_inbox() self._is_open = False self._sub_id = None
def _sub_to_heartbeat(self): # Setup the heartbeat inbox self.heart_beat_inbox = new_inbox() self.heart_beat_sub = yield from self.nc.subscribe( self.heart_beat_inbox, cb=self._process_heartbeat, is_async=True )
async def example(): # [begin subscribe_w_reply] nc = NATS() await nc.connect(servers=["nats://demo.nats.io:4222"]) future = asyncio.Future() async def cb(msg): nonlocal future future.set_result(msg) await nc.subscribe("time", cb=cb) await nc.publish_request("time", new_inbox(), b'What is the time?') await nc.flush() # Read the message msg = await asyncio.wait_for(future, 1) # Send the time time_as_bytes = "{}".format(datetime.now()).encode() await nc.publish(msg.reply, time_as_bytes) # [end subscribe_w_reply] await nc.close()
def __init__( self, sc, subject, message_cb, queue_name='', durable_name='', max_inflight=DEFAULT_MAX_INFLIGHT, ack_wait=DEFAULT_ACK_WAIT, start_position=NEW_ONLY, start_sequence=None, start_time=None, manual_acks=False, ): """ A nice little wrapper around subscribing. :type sc StreamClient :type subject basestring :type message_cb callable(msg: Msg) :type queue_name basestring :type max_inflight int :type ack_wait: int :type start_position: int :type start_sequence: int :type start_time datetime.datetime :type manual_acks bool """ self.sc = sc self.subject = subject self.queue_name = queue_name self.message_cb = message_cb self.durable_name = durable_name self.max_inflight = max_inflight self.ack_wait = ack_wait self.start_position = start_position self.start_sequence = start_sequence # sequence to start at self.start_time = start_time # datetime to start at self.start_at = None if start_time and start_sequence: raise NATS.ErrBadSubscription( "Cannot start at sequence and time! Pick either time or sequence." ) if start_time: self.start_at = pb.TimeDeltaStart() self.start_at = int( (time.time() - self.start_time.timestamp()) / 1e-9) # nano? self.manual_acks = manual_acks self.inbox = new_inbox() self.inbox_sub = None self.ack_inbox = None
def request(self, subject, payload, expected=1, cb=None): """ Implements the request/response pattern via pub/sub using an ephemeral subscription which will be published with customizable limited interest. ->> SUB _INBOX.2007314fe0fcb2cdc2a2914c1 90 ->> UNSUB 90 1 ->> PUB hello _INBOX.2007314fe0fcb2cdc2a2914c1 5 ->> MSG_PAYLOAD: world <<- MSG hello 2 _INBOX.2007314fe0fcb2cdc2a2914c1 5 """ inbox = new_inbox() sid = yield from self.subscribe(inbox, cb=cb) yield from self.auto_unsubscribe(sid, expected) yield from self.publish_request(subject, inbox, payload) return sid
async def example(): # [begin publish_with_reply] nc = NATS() future = asyncio.Future() async def sub(msg): nonlocal future future.set_result(msg) await nc.connect(servers=["nats://demo.nats.io:4222"]) await nc.subscribe("time", cb=sub) unique_reply_to = new_inbox() await nc.publish_request("time", unique_reply_to, b'') # Use the response msg = await asyncio.wait_for(future, 1) print("Reply:", msg) # [end publish_with_reply] await nc.close()
def tests_generate_new_inbox(self): inbox = new_inbox() self.assertTrue(inbox.startswith(INBOX_PREFIX)) min_expected_len = len(INBOX_PREFIX) self.assertTrue(len(inbox) > min_expected_len)
def __init__(self, my_args=None, connection_args=None): """ NATS requester constructor :param my_args: dict like {connection, request_q} :param connection_args: dict like {user, password, host[, port, client_properties]} :return: self """ LOGGER.debug("natsd.Requester.__init__") if my_args is None: raise exceptions.ArianeConfError("requestor arguments") if 'request_q' not in my_args or my_args['request_q'] is None or not my_args['request_q']: raise exceptions.ArianeConfError("request_q") if 'fire_and_forget' not in my_args or my_args['fire_and_forget'] is None or not my_args['fire_and_forget']: self.fire_and_forget = False else: self.fire_and_forget = True if 'rpc_timeout' not in connection_args or connection_args['rpc_timeout'] is None or \ not connection_args['rpc_timeout']: # default timeout = no timeout self.rpc_timeout = 0 else: self.rpc_timeout = connection_args['rpc_timeout'] if 'rpc_timeout_err_count_max' not in connection_args or connection_args['rpc_timeout_err_count_max'] is None \ or not connection_args['rpc_timeout_err_count_max']: self.rpc_retry_timeout_err_count_max = 3 else: self.rpc_retry_timeout_err_count_max = connection_args['rpc_timeout_err_count_max'] self.rpc_retry_timeout_err_count = 0 if 'rpc_retry' not in connection_args or connection_args['rpc_retry'] is None or \ not connection_args['rpc_retry']: # default retry = no retry self.rpc_retry = 0 else: self.rpc_retry = connection_args['rpc_retry'] Driver.validate_driver_conf(connection_args) super(Requester, self).__init__() self.connection_args = copy.deepcopy(connection_args) self.servers = [ "nats://" + connection_args['user'] + ":" + connection_args['password'] + "@" + connection_args['host']+":"+str(connection_args['port']) ] self.name = self.connection_args['client_properties']['ariane.app'] + "@" + socket.gethostname() + \ " - requestor on " + my_args['request_q'] self.loop = None self.options = None self.service = None self.nc = Client() self.requestQ = my_args['request_q'] self.responseQ = None self.responseQS = None self.response = None self.split_responses = None self.split_responses_mid = None self.is_started = False self.trace = False self.max_payload = 0 if not self.fire_and_forget: self.responseQ = new_inbox() self.response = None self.corr_id = None