示例#1
0
    def __init__(self, name, schedule, threadpool, ioloop=None):
        '''
        Create a new task based on a schedule in ioloop (default to current).

        The schedule configuration accepts:

        - startup: True to run at startup, '*' to run on every config change
        - minutes, hours, dates, months, weekdays, years: cron schedule
        - thread: True to run in a separate thread
        '''
        self.name = name
        self.utc = schedule.get('utc', False)
        self.thread = schedule.get('thread', False)
        if 'function' not in schedule:
            raise ValueError('schedule %s has no function:' % name)
        if callable(schedule['function']):
            self.function = schedule['function']
        else:
            self.function = build_transform(schedule,
                                            vars={},
                                            filename='schedule:%s' % name)
        self.ioloop = ioloop or tornado.ioloop.IOLoop.current()
        self._call_later(None)

        if self.thread:
            fn = self.function

            def on_done(future):
                exception = future.exception(timeout=0)
                if exception:
                    app_log.error('%s (thread): %s', name, exception)

            def run_function(*args, **kwargs):
                future = threadpool.submit(fn, *args, **kwargs)
                future.add_done_callback(on_done)
                return future

            self.function = run_function

        # Run on schedule if any of the schedule periods are specified
        periods = 'minutes hours dates months weekdays years'.split()
        if any(schedule.get(key) for key in periods):
            # Convert all valid values into strings (e.g. 30 => '30'), and ignore any spaces
            cron = (str(schedule.get(key, '*')).replace(' ', '')
                    for key in periods)
            self.cron_str = ' '.join(cron)
            self.cron = CronTab(self.cron_str)
            self.call_later()
        elif not schedule.get('startup'):
            app_log.warning('schedule:%s has no schedule nor startup', name)

        # Run now if the task is to be run on startup. Don't re-run if the config was reloaded
        startup = schedule.get('startup')
        if startup == '*' or (startup is True
                              and not ioloop_running(self.ioloop)):
            self.function()
示例#2
0
        def callback():
            '''Called after all services are started. Opens browser if required'''
            if ioloop_running(ioloop):
                return

            # If enterprise version is installed, user must accept license
            try:
                import gramexenterprise  # noqa
                gramex.license.accept()
            except ImportError:
                pass

            app_log.info('Listening on port %d', conf.listen.port)
            app_log_extra['port'] = conf.listen.port

            # browser: True opens the application home page on localhost.
            # browser: url opens the application to a specific URL
            url = 'http://127.0.0.1:%d/' % conf.listen.port
            if conf.browser:
                if isinstance(conf.browser, str):
                    url = urlparse.urljoin(url, conf.browser)
                try:
                    browser = webbrowser.get()
                    app_log.info('Opening %s in %s browser', url,
                                 browser.__class__.__name__)
                    browser.open(url)
                except webbrowser.Error:
                    app_log.info('Unable to open browser')
            else:
                app_log.info(
                    '<Ctrl-B> opens the browser. <Ctrl-D> starts the debugger.'
                )

            # Ensure that we call shutdown() on Ctrl-C.
            # On Windows, Tornado does not exit on Ctrl-C. This also fixes that.
            # When Ctrl-C is pressed, signal_handler() sets _exit to [True].
            # check_exit() periodically watches and calls shutdown().
            # But signal handlers can only be set in the main thread.
            # So ignore if we're not in the main thread (e.g. for nosetests, Windows service)
            #
            # Note: The PeriodicCallback takes up a small amount of CPU time.
            # Note: getch() doesn't handle keyboard buffer queue.
            # Note: This is no guarantee that shutdown() will be called.
            if isinstance(threading.current_thread(), threading._MainThread):
                exit = [False]

                def check_exit():
                    if exit[0] is True:
                        shutdown()
                    # If Ctrl-D is pressed, run the Python debugger
                    char = debug.getch()
                    if char == b'\x04':
                        import ipdb as pdb  # noqa
                        pdb.set_trace()  # noqa
                    # If Ctrl-B is pressed, start the browser
                    if char == b'\x02':
                        browser = webbrowser.get()
                        browser.open(url)

                def signal_handler(signum, frame):
                    exit[0] = True

                try:
                    signal.signal(signal.SIGINT, signal_handler)
                except ValueError:
                    # When running as a Windows Service (winservice.py), python
                    # itself is on a thread, I think. So ignore the
                    # ValueError: signal only works in main thread.
                    pass
                else:
                    tornado.ioloop.PeriodicCallback(check_exit,
                                                    callback_time=500).start()

            info._main_ioloop = ioloop
            ioloop.start()
示例#3
0
def shutdown():
    '''Shut down this instance'''
    ioloop = tornado.ioloop.IOLoop.current()
    if ioloop_running(ioloop):
        app_log.info('Shutting down Gramex...')
        ioloop.stop()
示例#4
0
def app(conf):
    '''Set up tornado.web.Application() -- only if the ioloop hasn't started'''
    import tornado.ioloop

    ioloop = tornado.ioloop.IOLoop.current()
    if ioloop_running(ioloop):
        app_log.warning('Ignoring app config change when running')
    else:
        info.app = GramexApp(**conf.settings)
        try:
            info.app.listen(**conf.listen)
        except socket.error as e:
            port_used_codes = dict(windows=10048, linux=98)
            if e.errno not in port_used_codes.values():
                raise
            logging.error(
                'Port %d is busy. Use --listen.port= for a different port',
                conf.listen.port)
            sys.exit(1)

        def callback():
            '''Called after all services are started. Opens browser if required'''
            if ioloop_running(ioloop):
                return

            gramex.license.accept()

            app_log.info('Listening on port %d', conf.listen.port)
            app_log_extra['port'] = conf.listen.port

            # browser: True opens the application home page on localhost.
            # browser: url opens the application to a specific URL
            url = 'http://127.0.0.1:%d/' % conf.listen.port
            if conf.browser:
                if isinstance(conf.browser, str):
                    url = urlparse.urljoin(url, conf.browser)
                try:
                    browser = webbrowser.get()
                    app_log.info('Opening %s in %s browser', url,
                                 browser.__class__.__name__)
                    browser.open(url)
                except webbrowser.Error:
                    app_log.info('Unable to open browser')
            else:
                app_log.info(
                    '<Ctrl-B> opens the browser. <Ctrl-D> starts the debugger.'
                )

            # Ensure that we call shutdown() on Ctrl-C.
            # On Windows, Tornado does not exit on Ctrl-C. This also fixes that.
            # When Ctrl-C is pressed, signal_handler() sets _exit to [True].
            # check_exit() periodically watches and calls shutdown().
            # But signal handlers can only be set in the main thread.
            # So ignore if we're not in the main thread (e.g. for nosetests, Windows service)
            #
            # Note: The PeriodicCallback takes up a small amount of CPU time.
            # Note: getch() doesn't handle keyboard buffer queue.
            # Note: This is no guarantee that shutdown() will be called.
            if isinstance(threading.current_thread(), threading._MainThread):
                exit = [False]

                def check_exit():
                    if exit[0] is True:
                        shutdown()
                    # If Ctrl-D is pressed, run the Python debugger
                    char = debug.getch()
                    if char == b'\x04':
                        import ipdb as pdb  # noqa
                        pdb.set_trace()  # noqa
                    # If Ctrl-B is pressed, start the browser
                    if char == b'\x02':
                        browser = webbrowser.get()
                        browser.open(url)

                def signal_handler(signum, frame):
                    exit[0] = True

                try:
                    signal.signal(signal.SIGINT, signal_handler)
                except ValueError:
                    # When running as a Windows Service (winservice.py), python
                    # itself is on a thread, I think. So ignore the
                    # ValueError: signal only works in main thread.
                    pass
                else:
                    tornado.ioloop.PeriodicCallback(check_exit,
                                                    callback_time=500).start()

            ioloop.start()

        return callback