RuntimeError: There is no current event loop in thread in async + apscheduler

In your def demo_async(urls), try to replace:

loop = asyncio.get_event_loop()

with:

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)

The important thing that hasn't been mentioned is why the error occurs. For me personally, knowing why the error occurs is as important as solving the actual problem.

Let's take a look at the implementation of the get_event_loop of BaseDefaultEventLoopPolicy:

class BaseDefaultEventLoopPolicy(AbstractEventLoopPolicy):
    ...

    def get_event_loop(self):
        """Get the event loop.

        This may be None or an instance of EventLoop.
        """
        if (self._local._loop is None and
            not self._local._set_called and
            isinstance(threading.current_thread(), threading._MainThread)):
            self.set_event_loop(self.new_event_loop())
        if self._local._loop is None:
            raise RuntimeError('There is no current event loop in thread %r.'
                               % threading.current_thread().name)
        return self._local._loop

You can see that the self.set_event_loop(self.new_event_loop()) is only executed if all of the below conditions are met:

  • self._local._loop is None - _local._loop is not set
  • not self._local._set_called - set_event_loop hasn't been called yet
  • isinstance(threading.current_thread(), threading._MainThread) - current thread is the main one (this is not True in your case)

Therefore the exception is raised, because no loop is set in the current thread:

if self._local._loop is None:
    raise RuntimeError('There is no current event loop in thread %r.'
                       % threading.current_thread().name)

Just pass fetch_all to scheduler.add_job() directly. The asyncio scheduler supports coroutine functions as job targets.

If the target callable is not a coroutine function, it will be run in a worker thread (due to historical reasons), hence the exception.