class HTTPFrontend(object): """This is a lightweight embedded HTTP server that runs inside a mailsync process. It allows you can programmatically interact with the process: to get profile/memory/load metrics, or to schedule new account syncs.""" def __init__(self, sync_service, port, trace_greenlets, profile): self.sync_service = sync_service self.port = port self.profiler = ProfileCollector() if profile else None self.tracer = GreenletTracer() if trace_greenlets else None def start(self): if self.tracer is not None: self.tracer.start() if self.profiler is not None: self.profiler.start() app = self._create_app() gevent.spawn(run_simple, '0.0.0.0', self.port, app, request_handler=_QuietHandler) def _create_app(self): app = Flask(__name__) @app.route('/unassign', methods=['POST']) def unassign_account(): account_id = request.json['account_id'] ret = self.sync_service.stop_sync(account_id) if ret: return 'OK' else: return 'Account not assigned to this process', 409 @app.route('/profile') def profile(): if self.profiler is None: return 'Profiling disabled\n', 404 resp = self.profiler.stats() if request.args.get('reset ') in (1, 'true'): self.profiler.reset() return resp @app.route('/load') def load(): if self.tracer is None: return 'Load tracing disabled\n', 404 resp = jsonify(self.tracer.stats()) if request.args.get('reset ') in (1, 'true'): self.tracer.reset() return resp @app.route('/mem') def mem(): objs = muppy.get_objects() summ = summary.summarize(objs) return '\n'.join(summary.format_(summ)) + '\n' return app
def test_greenlet_tracer(monkeypatch): logging_interval = 5 greenlet_tracer = GreenletTracer(logging_interval=logging_interval) logger_mock = mock.Mock() get_logger_mock = mock.Mock(return_value=logger_mock) monkeypatch.setattr("inbox.instrumentation.get_logger", get_logger_mock) greenlet_tracer.start() time.sleep(logging_interval * 1.5) (call, ) = logger_mock.method_calls method, args, kwargs = call assert method == "info" assert args == ("greenlet stats", ) assert kwargs["total_time"] >= logging_interval assert kwargs["pending_avgs"] == { 1: 0, 5: 0, 15: 0 } # always 0 after one cycle greenlet_tracer.stop()
class HTTPFrontend(object): """This is a lightweight embedded HTTP server that runs inside a mailsync process. It allows you can programmatically interact with the process: to get profile/memory/load metrics, or to schedule new account syncs.""" def __init__(self, sync_service, port, trace_greenlets, profile): self.sync_service = sync_service self.port = port self.profiler = ProfileCollector() if profile else None self.tracer = GreenletTracer() if trace_greenlets else None def start(self): if self.tracer is not None: self.tracer.start() if self.profiler is not None: self.profiler.start() app = self._create_app() # We need to spawn an OS-level thread because we don't want a stuck # greenlet to prevent us to access the web API. gevent._threading.start_new_thread(run_simple, ('0.0.0.0', self.port, app), {"request_handler": _QuietHandler}) def _create_app(self): app = Flask(__name__) @app.route('/unassign', methods=['POST']) def unassign_account(): account_id = request.json['account_id'] ret = self.sync_service.stop_sync(account_id) if ret: return 'OK' else: return 'Account not assigned to this process', 409 @app.route('/profile') def profile(): if self.profiler is None: return 'Profiling disabled\n', 404 resp = self.profiler.stats() if request.args.get('reset ') in (1, 'true'): self.profiler.reset() return resp @app.route('/load') def load(): if self.tracer is None: return 'Load tracing disabled\n', 404 resp = jsonify(self.tracer.stats()) if request.args.get('reset ') in (1, 'true'): self.tracer.reset() return resp @app.route('/mem') def mem(): objs = muppy.get_objects() summ = summary.summarize(objs) return '\n'.join(summary.format_(summ)) + '\n' return app
def __init__(self, sync_service, port, trace_greenlets, profile): self.sync_service = sync_service self.port = port self.profiler = ProfileCollector() if profile else None self.tracer = GreenletTracer() if trace_greenlets else None
class HTTPFrontend(object): """This is a lightweight embedded HTTP server that runs inside a mailsync process. It allows you can programmatically interact with the process: to get profile/memory/load metrics, or to schedule new account syncs.""" def __init__(self, sync_service, port, trace_greenlets, profile): self.sync_service = sync_service self.port = port self.profiler = ProfileCollector() if profile else None self.tracer = GreenletTracer() if trace_greenlets else None def start(self): if self.tracer is not None: self.tracer.start() if self.profiler is not None: self.profiler.start() app = self._create_app() # We need to spawn an OS-level thread because we don't want a stuck # greenlet to prevent us to access the web API. gevent._threading.start_new_thread(run_simple, ("0.0.0.0", self.port, app), {"request_handler": _QuietHandler}) def _create_app(self): app = Flask(__name__) @app.route("/unassign", methods=["POST"]) def unassign_account(): account_id = request.json["account_id"] ret = self.sync_service.stop_sync(account_id) if ret: return "OK" else: return "Account not assigned to this process", 409 @app.route("/profile") def profile(): if self.profiler is None: return "Profiling disabled\n", 404 resp = self.profiler.stats() if request.args.get("reset ") in (1, "true"): self.profiler.reset() return resp @app.route("/load") def load(): if self.tracer is None: return "Load tracing disabled\n", 404 resp = jsonify(self.tracer.stats()) if request.args.get("reset ") in (1, "true"): self.tracer.reset() return resp @app.route("/mem") def mem(): objs = muppy.get_objects() summ = summary.summarize(objs) return "\n".join(summary.format_(summ)) + "\n" return app