From ec7feb1a3c3a43b92df3234969170ca4e116c48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Thu, 5 Feb 2015 11:12:03 +0100 Subject: [PATCH 1/2] Possible workaround for OctoPrint stalling when a clock change happens while it is running --- setup.py | 4 ++++ src/octoprint/server/__init__.py | 13 +++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 17549a0e..ecb80ffe 100644 --- a/setup.py +++ b/setup.py @@ -289,6 +289,10 @@ def params(): zip_safe = False install_requires = open("requirements.txt").read().split("\n") + import sys + if sys.platform in ("linux2", "darwin"): + install_requires += ["monotime"] + entry_points = { "console_scripts": [ "octoprint = octoprint:main" diff --git a/src/octoprint/server/__init__.py b/src/octoprint/server/__init__.py index 7e701b5a..098f9512 100644 --- a/src/octoprint/server/__init__.py +++ b/src/octoprint/server/__init__.py @@ -575,6 +575,17 @@ class Server(): app.register_blueprint(blueprint, url_prefix=url_prefix) logger.debug("Registered API of plugin {name} under URL prefix {url_prefix}".format(name=name, url_prefix=url_prefix)) + ## Tornado initialization starts here + + try: + import monotime + import time + ioloop = IOLoop(time_func=time.monotonic) + except: + import time + ioloop = IOLoop(time_func=time.time) + ioloop.install() + self._router = SockJSRouter(self._createSocketConnection, "/sockjs") upload_suffixes = dict(name=settings().get(["server", "uploads", "nameSuffix"]), path=settings().get(["server", "uploads", "pathSuffix"])) @@ -604,8 +615,6 @@ class Server(): observer.schedule(util.watchdog.GcodeWatchdogHandler(fileManager, printer), settings().getBaseFolder("watched")) observer.start() - ioloop = IOLoop.instance() - # run our startup plugins octoprint.plugin.call_plugin(octoprint.plugin.StartupPlugin, "on_startup", From 57de36a9d3fdded45329d02a6567eff7976ebd47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Mon, 16 Mar 2015 10:19:03 +0100 Subject: [PATCH 2/2] Monkey patching tornado to backport tornadoweb/tornado#1290 Should hopefully help with freezing/blocking issues upon first connect with the net on the Pi, more tests needed. --- src/octoprint/server/__init__.py | 9 ++------- src/octoprint/server/util/tornado.py | 30 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/octoprint/server/__init__.py b/src/octoprint/server/__init__.py index 28ef95cb..92b5329d 100644 --- a/src/octoprint/server/__init__.py +++ b/src/octoprint/server/__init__.py @@ -58,6 +58,7 @@ import octoprint.filemanager.analysis import octoprint.slicing from . import util +util.tornado.fix_ioloop_scheduling() UI_API_KEY = ''.join('%02X' % ord(z) for z in uuid.uuid4().bytes) @@ -656,13 +657,7 @@ class Server(): ## Tornado initialization starts here - try: - import monotime - import time - ioloop = IOLoop(time_func=time.monotonic) - except: - import time - ioloop = IOLoop(time_func=time.time) + ioloop = IOLoop() ioloop.install() self._router = SockJSRouter(self._createSocketConnection, "/sockjs") diff --git a/src/octoprint/server/util/tornado.py b/src/octoprint/server/util/tornado.py index 18e7281a..399dd4d7 100644 --- a/src/octoprint/server/util/tornado.py +++ b/src/octoprint/server/util/tornado.py @@ -29,6 +29,36 @@ import tornado.util import octoprint.util +#~~ Monkey patching + + +def fix_ioloop_scheduling(): + """ + This monkey patches tornado's :meth:`tornado.ioloop.PeriodicCallback._schedule_next` method so it no longer + blocks for long times on slow machines (RPi) when the system time happens to change by a large amount (e.g. due to + the first ever contact to an NTP server). + + Patch by @nosyjoe on Github. See this PR against tornado: https://github.com/tornadoweb/tornado/pull/1290 + """ + + import math + + # patched implementation taken from PR + def _schedule_next(self): + if self._running: + current_time = self.io_loop.time() + + if self._next_timeout <= current_time: + callback_time_sec = self.callback_time / 1000.0 + self._next_timeout += (math.floor((current_time - self._next_timeout) / callback_time_sec) + 1) * callback_time_sec + + self._timeout = self.io_loop.add_timeout(self._next_timeout, self._run) + + # replace original implementation with patched version + import tornado.ioloop + tornado.ioloop.PeriodicCallback._schedule_next = _schedule_next + + #~~ WSGI middleware