docs: def call_repeatedly(func, interval, *args, **kwargs):
      """
      Call a function at interval
      Returns both the thread object and the loop stopper Event.
      """
      main_thead = threading.current_thread()
      stopped = threading.Event()
  
      def loop():
          while not stopped.wait(interval) and main_thead.is_alive():  # the first call is in `interval` secs
              func(*args, **kwargs)
  
          return
  
      timer_thread = threading.Thread(target=loop, daemon=True)
      timer_thread.start()
  
      atexit.register(stopped.set)
  
      return timer_thread, stopped.set