scheduler.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. # SPDX-License-Identifier: AGPL-3.0-or-later
  2. # lint: pylint
  3. # pylint: disable=missing-module-docstring
  4. """Lame scheduler which use Redis as a source of truth:
  5. * the Redis key SearXNG_checker_next_call_ts contains the next time the embedded checker should run.
  6. * to avoid lock, a unique Redis script reads and updates the Redis key SearXNG_checker_next_call_ts.
  7. * this Redis script returns a list of two elements:
  8. * the first one is a boolean. If True, the embedded checker must run now in this worker.
  9. * the second element is the delay in second to wait before the next call to the Redis script.
  10. This scheduler is not generic on purpose: if more feature are required, a dedicate scheduler must be used
  11. (= a better scheduler should not use the web workers)
  12. """
  13. import logging
  14. import time
  15. import importlib
  16. from typing import Callable
  17. from searx.redisdb import client as get_redis_client
  18. from searx.redislib import lua_script_storage
  19. logger = logging.getLogger('searx.search.checker')
  20. def scheduler_function(start_after_from: int, start_after_to: int, every_from: int, every_to: int, callback: Callable):
  21. """Run the checker periodically. The function never returns.
  22. Parameters:
  23. * start_after_from and start_after_to: when to call "callback" for the first on the Redis instance
  24. * every_from and every_to: after the first call, how often to call "callback"
  25. There is no issue:
  26. * to call this function is multiple workers
  27. * to kill workers at any time as long there is one at least one worker
  28. """
  29. scheduler_now_script = importlib.resources.read_text(__package__, "scheduler.lua")
  30. while True:
  31. # ask the Redis script what to do
  32. # the script says
  33. # * if the checker must run now.
  34. # * how to long to way before calling the script again (it can be call earlier, but not later).
  35. script = lua_script_storage(get_redis_client(), scheduler_now_script)
  36. call_now, wait_time = script(args=[start_after_from, start_after_to, every_from, every_to])
  37. # does the worker run the checker now?
  38. if call_now:
  39. # run the checker
  40. try:
  41. callback()
  42. except Exception: # pylint: disable=broad-except
  43. logger.exception("Error calling the embedded checker")
  44. # only worker display the wait_time
  45. logger.info("Next call to the checker in %s seconds", wait_time)
  46. # wait until the next call
  47. time.sleep(wait_time)