summaryrefslogtreecommitdiff
path: root/searx/search/checker/scheduler.py
blob: cc3bb738029f549ef106b13877ec41b8db37e9e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# SPDX-License-Identifier: AGPL-3.0-or-later
# lint: pylint
# pylint: disable=missing-module-docstring
"""Lame scheduler which use Redis as a source of truth:
* the Redis key SearXNG_checker_next_call_ts contains the next time the embedded checker should run.
* to avoid lock, a unique Redis script reads and updates the Redis key SearXNG_checker_next_call_ts.
* this Redis script returns a list of two elements:
   * the first one is a boolean. If True, the embedded checker must run now in this worker.
   * the second element is the delay in second to wait before the next call to the Redis script.

This scheduler is not generic on purpose: if more feature are required, a dedicate scheduler must be used
(= a better scheduler should not use the web workers)
"""

import logging
import time
import importlib
from typing import Callable

from searx.redisdb import client as get_redis_client
from searx.redislib import lua_script_storage


logger = logging.getLogger('searx.search.checker')


def scheduler_function(start_after_from: int, start_after_to: int, every_from: int, every_to: int, callback: Callable):
    """Run the checker periodically. The function never returns.

    Parameters:
    * start_after_from and start_after_to: when to call "callback" for the first on the Redis instance
    * every_from and every_to: after the first call, how often to call "callback"

    There is no issue:
    * to call this function is multiple workers
    * to kill workers at any time as long there is one at least one worker
    """
    scheduler_now_script = importlib.resources.read_text(__package__, "scheduler.lua")
    while True:
        # ask the Redis script what to do
        # the script says
        # * if the checker must run now.
        # * how to long to way before calling the script again (it can be call earlier, but not later).
        script = lua_script_storage(get_redis_client(), scheduler_now_script)
        call_now, wait_time = script(args=[start_after_from, start_after_to, every_from, every_to])

        # does the worker run the checker now?
        if call_now:
            # run the checker
            try:
                callback()
            except Exception:  # pylint: disable=broad-except
                logger.exception("Error calling the embedded checker")
            # only worker display the wait_time
            logger.info("Next call to the checker in %s seconds", wait_time)
        # wait until the next call
        time.sleep(wait_time)