public static function instance($fast = false) {
        global $CFG;

        // One per request, this should be purged during testing.
        if (static::$instance !== null) {
            return static::$instance;
        }

        if (empty($CFG->searchengine)) {
            throw new \core_search\engine_exception('enginenotselected', 'search');
        }

        if (!$engine = static::search_engine_instance()) {
            throw new \core_search\engine_exception('enginenotfound', 'search', '', $CFG->searchengine);
        }

        // Get time now and at last schema check.
        $now = (int)self::get_current_time();
        $lastschemacheck = get_config($engine->get_plugin_name(), 'lastschemacheck');

        // On pages where performance matters, tell the engine to skip schema checks.
        $skipcheck = false;
        if ($fast && $now < $lastschemacheck + self::SCHEMA_CHECK_REQUIRED_EVERY) {
            $skipcheck = true;
            $engine->skip_schema_check();
        }

        if (!$engine->is_installed()) {
            throw new \core_search\engine_exception('enginenotinstalled', 'search', '', $CFG->searchengine);
        }

        $serverstatus = $engine->is_server_ready();
        if ($serverstatus !== true) {
            // Skip this error in Behat when faking seach results.
            if (!defined('BEHAT_SITE_RUNNING') || !get_config('core_search', 'behat_fakeresult')) {
                // Clear the record of successful schema checks since it might have failed.
                unset_config('lastschemacheck', $engine->get_plugin_name());
                // Error message with no details as this is an exception that any user may find if the server crashes.
                throw new \core_search\engine_exception('engineserverstatus', 'search');
            }
        }

        // If we did a successful schema check, record this, but not more than once per 10 minutes
        // (to avoid updating the config db table/cache too often in case it gets called frequently).
        if (!$skipcheck && $now >= $lastschemacheck + self::SCHEMA_CHECK_TRACKING_DELAY) {
            set_config('lastschemacheck', $now, $engine->get_plugin_name());
        }

        static::$instance = new \core_search\manager($engine);
        return static::$instance;
    }