agronholm / apscheduler

Task scheduling library for Python
MIT License
6.18k stars 704 forks source link

TypeError: RetryMixin._retry.<locals>.after_attempt() missing 1 required positional argument: 'retry_state' #879

Closed bachya closed 6 months ago

bachya commented 6 months ago

Things to check first

Version

4.0.0a4

What happened?

Using the simple FastAPI-centered example below, I get the following error:

[22:47:55] error: Traceback (most recent call last):
  File "/app/.venv/lib/python3.12/site-packages/apscheduler/_schedulers/async_.py", line 133, in __aenter__
    await self._ensure_services_initialized(exit_stack)
  File "/app/.venv/lib/python3.12/site-packages/apscheduler/_schedulers/async_.py", line 160, in _ensure_services_initialized
    await self.event_broker.start(exit_stack, self.logger)
  File "/app/.venv/lib/python3.12/site-packages/apscheduler/eventbrokers/asyncpg.py", line 114, in start
    await self._task_group.start(self._listen_notifications),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/app/.venv/lib/python3.12/site-packages/anyio/_backends/_asyncio.py", line 782, in start
    return await future
           ^^^^^^^^^^^^
  File "/app/.venv/lib/python3.12/site-packages/apscheduler/eventbrokers/asyncpg.py", line 142, in _listen_notifications
    async for attempt in self._retry():
  File "/app/.venv/lib/python3.12/site-packages/tenacity/_asyncio.py", line 71, in __anext__
    do = self.iter(retry_state=self._retry_state)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/app/.venv/lib/python3.12/site-packages/tenacity/__init__.py", line 317, in iter
    self.after(retry_state)
TypeError: RetryMixin._retry.<locals>.after_attempt() missing 1 required positional argument: 'retry_state'

During handling of the above exception, another exception occurred:

  + Exception Group Traceback (most recent call last):
  |   File "/app/.venv/lib/python3.12/site-packages/starlette/routing.py", line 734, in lifespan
  |     async with self.lifespan_context(app) as maybe_state:
  |   File "/usr/local/lib/python3.12/contextlib.py", line 210, in __aenter__
  |     return await anext(self.gen)
  |            ^^^^^^^^^^^^^^^^^^^^^
  |   File "/app/src/app.py", line 137, in lifespan
  |     async with scheduler:
  |   File "/app/.venv/lib/python3.12/site-packages/apscheduler/_schedulers/async_.py", line 132, in __aenter__
  |     async with AsyncExitStack() as exit_stack:
  |   File "/usr/local/lib/python3.12/contextlib.py", line 754, in __aexit__
  |     raise exc_details[1]
  |   File "/usr/local/lib/python3.12/contextlib.py", line 737, in __aexit__
  |     cb_suppress = await cb(*exc_details)
  |                   ^^^^^^^^^^^^^^^^^^^^^^
  |   File "/app/.venv/lib/python3.12/site-packages/anyio/_backends/_asyncio.py", line 678, in __aexit__
  |     raise BaseExceptionGroup(
  | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
  +-+---------------- 1 ----------------
    | Traceback (most recent call last):
    |   File "/app/.venv/lib/python3.12/site-packages/apscheduler/_schedulers/async_.py", line 133, in __aenter__
    |     await self._ensure_services_initialized(exit_stack)
    |   File "/app/.venv/lib/python3.12/site-packages/apscheduler/_schedulers/async_.py", line 160, in _ensure_services_initialized
    |     await self.event_broker.start(exit_stack, self.logger)
    |   File "/app/.venv/lib/python3.12/site-packages/apscheduler/eventbrokers/asyncpg.py", line 114, in start
    |     await self._task_group.start(self._listen_notifications),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/app/.venv/lib/python3.12/site-packages/anyio/_backends/_asyncio.py", line 782, in start
    |     return await future
    |            ^^^^^^^^^^^^
    |   File "/app/.venv/lib/python3.12/site-packages/apscheduler/eventbrokers/asyncpg.py", line 142, in _listen_notifications
    |     async for attempt in self._retry():
    |   File "/app/.venv/lib/python3.12/site-packages/tenacity/_asyncio.py", line 71, in __anext__
    |     do = self.iter(retry_state=self._retry_state)
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "/app/.venv/lib/python3.12/site-packages/tenacity/__init__.py", line 317, in iter
    |     self.after(retry_state)
    | TypeError: RetryMixin._retry.<locals>.after_attempt() missing 1 required positional argument: 'retry_state'
    +------------------------------------

[22:47:55] error: Application startup failed. Exiting.

How can we reproduce the bug?

Simple example to reproduce:

from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
from datetime import UTC, datetime
from typing import Final

from apscheduler import AsyncScheduler
from apscheduler.datastores.sqlalchemy import SQLAlchemyDataStore
from apscheduler.eventbrokers.asyncpg import AsyncpgEventBroker
from apscheduler.triggers.interval import IntervalTrigger
from fastapi import FastAPI
from sqlalchemy.ext.asyncio import create_async_engine

def tick() -> None:
    """Print the time."""
    print("Tick! The time is now %s", datetime.now(tz=UTC))

@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
    """Define actions to take on startup."""
    db_engine = create_async_engine(config.database_url)
    scheduler = app.state.scheduler = AsyncScheduler(
        data_store=SQLAlchemyDataStore(db_engine),
        event_broker=AsyncpgEventBroker.from_async_sqla_engine(db_engine),
    )

    async with scheduler:
        await scheduler.add_schedule(tick, IntervalTrigger(seconds=1), id="tick")
        await scheduler.start_in_background()
        yield

app: Final[FastAPI] = FastAPI(lifespan=lifespan)
bachya commented 6 months ago

This looks like a similar error to https://github.com/agronholm/apscheduler/issues/759.