Нашёл решение. Я отказался от использования executor совсем и сделал следующее:
async def coro_func1():
# здесь вызов обычной функции для обновления контента
async def coro_func2():
# тут расписана асинхронная функция
async def сoro_func3():
# тут ещё одна асинхронная функция
async def poller_coro():
await dp.start_polling()
async def main():
asyncio.create_task(poller_coro())
while True:
asyncio.create_task(coro_func1())
asyncio.create_task(coro_func2())
asyncio.create_task(coro_func3())
await asyncio.sleep(1)
if __name__ == '__main__':
asyncio.run(main())
В таком виде всё работает именно так как мне нужно. Бот проверяет и моментально отвечает на входящие сообщения, при этом выполняются другие функции. asyncio.run(main()) вызывает асинхронную функцию main, в которой создается задача poller_coro() (проверка входящих сообщений), а затем в цикле крутятся остальные задачи. При этом await dp.start_polling() из poller_coro() не прекращает выполняться.