For me, this problem is already solved using always-on tasks.
You can setup an APScheduler script that makes REST requests to your webapp. Secure it using token or other.
Then any task that could be kicked off by a user could also be kicked off by that request on a schedule. You can also do things like retries, store tasks in db, etc. You could also do logic like : if webappA returns false, run request Y on webapp b.
This was difficult/impossible to do before by using scheduled tasks, because they would only run at certain times, not more than once an hour.
Celery is fine, but it can be overkill unless you really need distributed tasks.