示例#1
0
    def post(self, request):
        import sys
        from otree.common import dump_db

        if '--inside-zipserver' in sys.argv:

            dump_db()
            sys.exit(0)
示例#2
0
    def handle(self, *args, **options):
        self.verbosity = options.get("verbosity", 1)

        if not settings.DEBUG:
            # this tends to cause confusion. people don't know why they get server 500 error,
            # and it's worse with zipserver, where it is not possible to run collectstatic.
            sys.exit(
                'Error: devserver & zipserver cannot be used in production mode. '
                'Ensure that your settings.py does not contain a DEBUG setting, '
                'and that the OTREE_PRODUCTION env var is not set.')

        # for performance,
        # only run checks when the server starts, not when it reloads
        # (RUN_MAIN is set by Django autoreloader).
        if not os.environ.get('RUN_MAIN'):

            try:
                # don't suppress output. it's good to know that check is
                # not failing silently or not being run.
                # also, intercepting stdout doesn't even seem to work here.
                self.check(display_num_errors=True)

            except Exception as exc:
                otree_startup.print_colored_traceback_and_exit(exc)

            # better to do this here, because:
            # (1) it's redundant to do it on every reload
            # (2) we can exit if we run this before the autoreloader is started
            if TMP_MIGRATIONS_DIR.exists() and (
                    not VERSION_FILE.exists()
                    or VERSION_FILE.read_text() != CURRENT_VERSION):
                # - Don't delete the DB, because it might have important data
                # - Don't delete __temp_migrations, because then we erase the knowledge that
                # oTree was updated. If the user starts the server at a later time, we can't remind them
                # that they needed to delete the DB. So, the two things must be deleted together.
                self.stdout.write(MSG_OTREE_UPDATE_DELETE_DB)
                sys.exit(0)
            TMP_MIGRATIONS_DIR.mkdir(exist_ok=True)
            VERSION_FILE.write_text(CURRENT_VERSION)
            TMP_MIGRATIONS_DIR.joinpath('__init__.py').touch(exist_ok=True)
            # python docs say: invalidate_cache must be called after creating new modules
            # i suspect invalidate_cache is needed to avoid this issue:
            # https://groups.google.com/d/msg/otree/d3fOpKCgLWo/-TSiZHy5CAAJ
            # because it only happened on mac and was sporadic like a race condition
            # seems to have no impact on perf
            importlib.invalidate_caches()

        is_reloader_process = options['use_reloader'] and not os.environ.get(
            'RUN_MAIN')
        if not is_reloader_process:
            # this handles restarts due Ctrl+C

            # can't handle this signal in the autoreloader process,
            # since the DB is stored in the main django process's memory.

            # i guess the child process receives the SIGINT
            # from the parent autoreloader process.
            signal.signal(signal.SIGINT, dump_db_and_exit)

        try:
            super().handle(*args, **options)
        except SystemExit as exc:
            # this is designed to handle the sys.exit(3) that is fired
            # by the child process file-watcher thread, when a file is changed.
            # it needs to be here rather than inner_run because that is only
            # run by the child process main_func thread.

            # this also gets run if using zipserver and a sys.exit occurs.

            # if an exception occurs inside the main_func thread that executes inner_run,
            # it will just print the TB and hang, as usual. Then the user presses Ctrl+C,
            # which triggers the SIGINT handler above.
            # if the main_func thread calls sys.exit that is not a concern here
            # because that will just exit that thread and not bubble up here.
            if not is_reloader_process:
                dump_db()
            raise