Thanks @lsabi for questions. With them I figured out, that BackgroundTasks
instance not attachable to app instance. It only worked in routes, because of it mechanism: starlette runs such tasks after response (src).
So, I've done the following things:
- Used
apscheduler
module with AsyncIOScheduler
to manage tasks.
- Still used
BackgroundTasks
in routes to create tasks in response, and not in route method body.
on events
are the following:
@mp_task_router.on_event('startup')
def start_reminder_jobs():
fcm = FCM() # push notification class
with Session() as session:
reminders_to_notify = ... # session query
for reminder in filter(is_reminder_notifiable, reminders_to_notify):
if not (next_date := reminder.next_date):
continue
pet_name: str = ... # scalar session query
scheduler.add_job(
background_reminder_notify,
'date',
run_date=next_date - relativedelta(seconds=3), # dateutil.relativedelta class
kwargs=dict(
fcm=fcm,
next_date=next_date,
reminder=reminder,
pet_name=pet_name,
),
)
scheduler.start()
@mp_task_router.on_event('shutdown')
def stop_scheduler():
scheduler.remove_all_jobs()
scheduler.shutdown(wait=False)
example of using BackgroundTasks
in routes with apscheduler
:
@mp_task_router.get('', ...)
def example(background_tasks: BackgroundTasks):
# get all needed data.
...
background_tasks.add_task(
scheduler.add_job,
background_reminder_notify,
'date',
run_date=reminder.next_date - relativedelta(seconds=5),
kwargs=dict(
fcm=fcm,
next_date=next_date,
reminder=reminder,
pet_name=pet_name,
),
)
return {'detail': 'example'}