def test_main_io_loop_is_not_changed(): threadloop = ThreadLoop() threadloop.start() # The ThreadLoop's IOLoop should not be the 'current' IOLoop in the main # thread. tl_loop = threadloop.submit(ioloop.IOLoop.current).result() assert ioloop.IOLoop.current() is not tl_loop
def test_ioloop_is_not_already_running(): threadloop = ThreadLoop() threadloop.start() @gen.coroutine def f(): yield threadloop.submit(gen.sleep, 0.1) ioloop.IOLoop.current().run_sync(f)
def test_block_until_thread_is_ready(): threadloop = ThreadLoop() assert not threadloop.is_ready() threadloop.start() assert threadloop.is_ready()
class TChannelSyncClient(object): """Make synchronous TChannel requests. This client does not support incoming connections or requests- this is a uni-directional client only. The client is implemented on top of the Tornado-based implementation and starts and stops IOLoops on-demand. .. code-block:: python client = TChannelSyncClient() response = client.request( hostport='localhost:4040', service='HelloService', ).send( 'hello', None, json.dumps({"name": "World"}) ) """ def __init__(self, name, process_name=None, known_peers=None, trace=False): """Initialize a new TChannelClient. :param process_name: Name of the calling process. Used for logging purposes only. """ self.async_client = async.TChannel( name, hostport=glossary.EPHEMERAL_HOSTPORT, process_name=process_name, known_peers=known_peers, trace=trace ) self.threadloop = ThreadLoop() self.threadloop.start() def request(self, *args, **kwargs): """Initiate a new request to a peer. :param hostport: If specified, requests will be sent to the specific host. Otherwise, a known peer will be picked at random. :param service: Name of the service being called. Defaults to an empty string. :param service_threshold: If ``hostport`` was not specified, this specifies the score threshold at or below which peers will be ignored. :returns SyncClientOperation: An object with a ``send(arg1, arg2, arg3)`` operation. """ operation = self.async_client.request(*args, **kwargs) operation = SyncClientOperation(operation, self.threadloop) return operation
class LocalAgentSender(TBufferedTransport): """ LocalAgentSender implements everything necessary to communicate with local jaeger-agent. This class is designed to work in tornado and non-tornado environments. If in torndado, pass in the ioloop, if not then LocalAgentSender will create one for itself. NOTE: LocalAgentSender derives from TBufferedTransport. This will buffer up all written data until flush() is called. Flush gets called at the end of the batch span submission call. """ def __init__(self, host, sampling_port, reporting_port, io_loop=None, throttling_port=None): # IOLoop self._thread_loop = None self.io_loop = io_loop or self._create_new_thread_loop() # HTTP sampling self.local_agent_http = LocalAgentHTTP(host, sampling_port) # HTTP throttling if throttling_port: self.throttling_http = LocalAgentHTTP(host, throttling_port) # UDP reporting - this will only get written to after our flush() call. # We are buffering things up because we are a TBufferedTransport. udp = TUDPTransport(host, reporting_port) TBufferedTransport.__init__(self, udp) def _create_new_thread_loop(self): """ Create a daemonized thread that will run Tornado IOLoop. :return: the IOLoop backed by the new thread. """ self._thread_loop = ThreadLoop() if not self._thread_loop.is_ready(): self._thread_loop.start() return self._thread_loop._io_loop def readFrame(self): """Empty read frame that is never ready""" return Future() # Pass-through for HTTP sampling strategies request. def request_sampling_strategy(self, *args, **kwargs): return self.local_agent_http.request_sampling_strategy(*args, **kwargs) # Pass-through for HTTP throttling credit request. def request_throttling_credits(self, *args, **kwargs): return self.throttling_http.request_throttling_credits(*args, **kwargs)
class Sender(object): def __init__(self, host, port, io_loop=None): self.host = host self.port = port self.io_loop = io_loop or self._create_new_thread_loop() def send(self, batch): raise NotImplementedError( 'This method should be implemented by subclasses') def _create_new_thread_loop(self): """ Create a daemonized thread that will run Tornado IOLoop. :return: the IOLoop backed by the new thread. """ self._thread_loop = ThreadLoop() if not self._thread_loop.is_ready(): self._thread_loop.start() return self._thread_loop._io_loop
class LocalAgentSender(TBufferedTransport): """ LocalAgentSender implements a everything necessary to communicate with local jaeger-agent. This class is designed to work in tornado and non-tornado environments. If in torndado, pass in the ioloop, if not then LocalAgentSender will create one for itself. NOTE: LocalAgentSender derives from TBufferedTransport. This will buffer up all written data until flush() is called. Flush gets called at the end of the batch span submission call. """ def __init__(self, host, sampling_port, reporting_port, ioloop=None): # ioloop if ioloop is None: self.create_new_threadloop() else: self.io_loop = ioloop # http sampling self.local_agent_http = LocalAgentHTTP(host, sampling_port) # udp reporting - this will only get written to after our flush() call. # We are buffering things up because we are a TBufferedTransport. udp = TUDPTransport(host, reporting_port) TBufferedTransport.__init__(self, udp) def create_new_threadloop(self): self._threadloop = ThreadLoop() if not self._threadloop.is_ready(): self._threadloop.start() self.io_loop = ioloop_util.get_io_loop(self) def readFrame(self): """Empty read frame that is never ready""" return Future() # Passthroughs for the http def request_sampling_strategy(self, service_name, timeout): return self.local_agent_http.request_sampling_strategy(service_name, timeout)
class TChannelSyncClient(object): """Make synchronous TChannel requests. This client does not support incoming connections or requests- this is a uni-directional client only. The client is implemented on top of the Tornado-based implementation and starts and stops IOLoops on-demand. .. code-block:: python client = TChannelSyncClient() response = client.request( hostport='localhost:4040', service='HelloService', ).send( 'hello', None, json.dumps({"name": "World"}) ) """ def __init__(self, name, process_name=None, known_peers=None, trace=False): """Initialize a new TChannelClient. :param process_name: Name of the calling process. Used for logging purposes only. """ self._async_client = async.TChannel(name, process_name=process_name, known_peers=known_peers, trace=trace) self._threadloop = ThreadLoop() self._threadloop.start() def request(self, *args, **kwargs): """Initiate a new request to a peer. :param hostport: If specified, requests will be sent to the specific host. Otherwise, a known peer will be picked at random. :param service: Name of the service being called. Defaults to an empty string. :param service_threshold: If ``hostport`` was not specified, this specifies the score threshold at or below which peers will be ignored. :returns SyncClientOperation: An object with a ``send(arg1, arg2, arg3)`` operation. """ operation = self._async_client.request(*args, **kwargs) operation = SyncClientOperation(operation, self._threadloop) return operation def advertise(self, routers, name=None, timeout=None): """Advertise with Hyperbahn. :param routers: list of hyperbahn addresses to advertise to. :param name: service name to advertise with. :param timeout: backoff period for failed requests. :returns: first advertise result. :raises AdvertiseError: when unable to begin advertising. """ @gen.coroutine def make_request(): response = yield self._async_client.advertise(routers=routers, name=name, timeout=timeout) header = yield response.get_header() body = yield response.get_body() result = Response(header, body) raise gen.Return(result) future = self._threadloop.submit(make_request) # we're going to wait 1s longer than advertises # timeout mechanism, so it has a chance to timeout wait_until = timeout or FIRST_ADVERTISE_TIME wait_until += 1 # block for advertise's first response, # using wait_until as a fallback timeout mechanism try: result = future.result(wait_until) except TimeoutError: raise AdvertiseError("Failed to register with Hyperbahn.") return result
class TChannelSyncClient(object): """Make synchronous TChannel requests. This client does not support incoming connections or requests- this is a uni-directional client only. The client is implemented on top of the Tornado-based implementation and starts and stops IOLoops on-demand. .. code-block:: python client = TChannelSyncClient() response = client.request( hostport='localhost:4040', service='HelloService', ).send( 'hello', None, json.dumps({"name": "World"}) ) """ def __init__(self, name, process_name=None, known_peers=None, trace=False): """Initialize a new TChannelClient. :param process_name: Name of the calling process. Used for logging purposes only. """ self._async_client = async .TChannel(name, process_name=process_name, known_peers=known_peers, trace=trace) self._threadloop = ThreadLoop() self._threadloop.start() def request(self, *args, **kwargs): """Initiate a new request to a peer. :param hostport: If specified, requests will be sent to the specific host. Otherwise, a known peer will be picked at random. :param service: Name of the service being called. Defaults to an empty string. :param service_threshold: If ``hostport`` was not specified, this specifies the score threshold at or below which peers will be ignored. :returns SyncClientOperation: An object with a ``send(arg1, arg2, arg3)`` operation. """ operation = self._async_client.request(*args, **kwargs) operation = SyncClientOperation(operation, self._threadloop) return operation def advertise(self, routers, name=None, timeout=None): """Advertise with Hyperbahn. :param routers: list of hyperbahn addresses to advertise to. :param name: service name to advertise with. :param timeout: backoff period for failed requests. :returns: first advertise result. :raises AdvertiseError: when unable to begin advertising. """ @gen.coroutine def make_request(): response = yield self._async_client.advertise( routers=routers, name=name, timeout=timeout, ) header = yield response.get_header() body = yield response.get_body() result = Response(header, body) raise gen.Return(result) future = self._threadloop.submit(make_request) # we're going to wait 1s longer than advertises # timeout mechanism, so it has a chance to timeout wait_until = timeout or FIRST_ADVERTISE_TIME wait_until += 1 # block for advertise's first response, # using wait_until as a fallback timeout mechanism try: result = future.result(wait_until) except TimeoutError: raise AdvertiseError("Failed to register with Hyperbahn.") return result