Beispiel #1
0
def test_modules_status():
    exc_info = []
    io_loop = IOLoop()

    @gen.coroutine
    def collect_modules_status(cls):
        cls._modules_status = [{'a': 'a'}]

    @gen.coroutine
    def check_modules_status():
        yield gen.sleep(0.01)
        try:
            module_status = yield StatusScheduler.get_modules_status()
            assert module_status == [{'a': 'a'}]
        except Exception as e:
            exc_info.append(e)
        finally:
            io_loop.stop()

    scheduler = StatusScheduler()
    StatusScheduler.collect_modules_status = classmethod(
        collect_modules_status)

    with config.mock({'heartbeat': 0.01}):
        io_loop.spawn_callback(scheduler.eventloop)
        io_loop.spawn_callback(check_modules_status)
        io_loop.start()

    if exc_info:
        raise exc_info[0]
Beispiel #2
0
    def handle_process(self, queue):
        """It handles a new process by calling a specific IOLoop and starting it with a callback.

        Args:
            queue (Queue): A queue object.

        """

        # Creates an IOLoop object
        loop = IOLoop()

        # Spawns the callback function
        loop.spawn_callback(self.worker, queue)

        # Starts the loop
        loop.start()
Beispiel #3
0
def test_heartbeat():
    io_loop = IOLoop()

    class MockedTransfer(object):
        @gen.coroutine
        def send(self, msg):
            assert len(msg['id']) == 32
            assert msg['type'] == MessageType.HEARTBEAT
            assert 'id' in msg['body']
            assert 'rss' in msg['body']
            assert 'vms' in msg['body']
            assert 'cpu' in msg['body']
            io_loop.stop()

    transfer = MockedTransfer()
    scheduler = HeartbeatScheduler()

    with config.mock({'heartbeat': 0.01}):
        with mock_transfer(transfer):
            io_loop.spawn_callback(scheduler.eventloop)
            io_loop.start()
Beispiel #4
0
class SwimpyProcess(multiprocessing.Process):
    def __init__(self, routes, node, pipe, *args, **kwargs):
        super(self.__class__, self).__init__(*args, **kwargs)
        self.routes = routes
        self.node = node
        self.pipe = pipe

        self.bind_addr = node.addr
        self.bind_port = node.port

        # We don't want to initialize these until after we fork
        self.ioloop = None
        self.server = None
        self.app = None

    def _handle_pipe_messages(self, *args, **kwargs):
        message = self.pipe.recv()
        unpacked_message = msgpack.unpackb(message)
        message_type = unpacked_message.pop('type')
        if message_type == Sync.MESSAGE_TYPE:
            self.pipe.send(self.app.nodes)

    def run(self):
        signal.signal(signal.SIGTERM, self.shutdown_sig_handler)
        signal.signal(signal.SIGINT, self.shutdown_sig_handler)

        from tornado.ioloop import IOLoop
        self.ioloop = IOLoop().current()  # get a reference to the IOLoop post-fork

        LOGGER.info('Starting server on tcp://{}:{}'.format(self.bind_addr, self.bind_port))
        self.app = Application(routes=self.routes, node=self.node, pipe=self.pipe)
        self.server = Server(message_handler=self.app.route_stream_message)
        self.server.listen(self.bind_port, address=self.bind_addr)

        self.ioloop.add_handler(self.pipe, self._handle_pipe_messages, self.ioloop.READ)
        self.ioloop.spawn_callback(self.app.send_buffered_gossip)

        # Ping a random node every PING_INVERVAL seconds, +/- 10%
        # This jitter should reduce the average aggregate peak network throughput
        # when running with large cluster sized
        PeriodicCallbackWithSplay(self.app.ping_random_node,
                                  PING_INTERVAL * 1000,
                                  splay_pct=10).start()

        LOGGER.info('Starting ioloop')
        self.ioloop.start()

    def stop(self, shutdown_timeout=SHUTDOWN_TIMEOUT, graceful=True):
        """
        Trigger a graceful stop of the server and the server's ioloop, allowing in-flight
        connections to finish

        Fall back to a "less graceful" stop when stop is reached
        """
        def poll_stop():
            # Tornado uses a "waker" handler internally that we'd like to ignore here
            remaining_handlers = {
                k: v
                for k, v in self.ioloop._handlers.iteritems()
                if k != self.ioloop._waker.fileno()
            }

            # Poll for any remaining connections
            remaining_count = len(remaining_handlers)

            # Once all handlers have been removed, we can stop safely
            if remaining_count == 0:
                LOGGER.info('All finished! Graceful stop complete')
                self.ioloop.stop()
            else:
                LOGGER.info('Waiting on IO handlers ({} remaining). '
                            'Handlers: {!r}'.format(remaining_count,
                                                    remaining_handlers))

        self.ioloop.remove_handler(self.pipe)
        self.server.shutdown()
        self.server.stop()

        if graceful:
            # Poll the IOLoop's handlers until they all shut down.
            poller = PeriodicCallback(poll_stop, 500, io_loop=self.ioloop)
            poller.start()
            self.ioloop.add_timeout(self.ioloop.time() + shutdown_timeout,
                                    self.ioloop.stop)
        else:
            self.ioloop.stop()

    def shutdown_sig_handler(self, sig, frame):
        """
        Signal handler for "stop" signals (SIGTERM, SIGINT)
        """
        LOGGER.warning('{!r} caught signal {!r}! Shutting down'.format(self, sig))

        try:
            self.ioloop.add_callback_from_signal(self.stop)
        except Exception as e:
            LOGGER.error(
                'Encountered exception while shutting down: {}'.format(e)
            )
            sys.exit(1)