\

Show HN: FastScheduler – Decorator-first Python task scheduler, async support

45 points - yesterday at 2:45 PM


Hi! I've built this because I kept reaching for Celery for simple scheduled tasks and it felt like overkill. I just needed "run this function every hour" or "daily at 9am", not distributed workers.

So it's decorators for scheduling (@scheduler.every(5).minutes, @scheduler.daily.at("09:00")), state saves to JSON so jobs survive restarts, and there's an optional FastAPI dashboard if you want to see what's running.

No Redis, no message broker, runs in-process with your app. Trade-off is it's single process only β€” if you need distributed workers, stick with Celery.

Source
  • languagehacker

    yesterday at 9:48 PM

    If Celery seems like overkill for your process, and you're really just looking to execute basic cron functioanlity, then why not just use crontab to invoke your Python script?

    I can think of two major ways to operationalize a Python script that needs to run continuously. One is with containerization, which usually means Kubernetes, which already has a perfectly fine resource definition for cronjobs. The other approach is to run the script in a bare metal or VM, which would mean defining a service to ensure that the process can be managed appropriately, restarted if it dies, and the like. In other words, defining a service is about just as much effort as defining a cronjob, and there's no escape from some amount of "ops work" that isn't encapsulated in a Python script.

    So why not just use the tried-and-true prior art than worry about building and supporting your own secret third thing that others would need to learn, support, maintain, and keep in mind when debugging a problem?

      • michielme

        today at 4:13 AM

        Fair point. Cron works fine for standalone scripts. This is more for when you want scheduled tasks inside an existing Python app without spinning up separate infrastructure.

    • antonbassyk

      yesterday at 7:13 PM

      Looks interesting. Wondering how this is different from the more established https://github.com/agronholm/apscheduler ?

        • michielme

          yesterday at 7:50 PM

          APScheduler is solid and more mature. Main difference is the API β€” FastScheduler is decorator-first so you get @scheduler.daily.at("09:00") instead of configuring triggers, executors, and job stores separately. Also has a built-in FastAPI dashboard.

            • atoav

              today at 8:44 AM

              Maybe I forgot about this, but how would you secure the scheduler api/dashboard from unauthorized access? This might be a good point to add to the readme.

                • michielme

                  today at 8:57 AM

                  Good point. Right now it relies on FastAPI's dependency injection β€” you can wrap the router with your own auth middleware or add dependencies when including it. But I should add an example to the docs. Thanks for the nudge.

      • techjamie

        yesterday at 6:20 PM

        This is really cool, and I could see myself using this. Sometimes I need functionality like this, but can't be bothered to build up the infrastructure around it. This is perfect for that use case.

          • michielme

            yesterday at 6:38 PM

            Thanks! Yeah that's exactly the use case β€” when you just need something scheduled without setting up a whole stack.

        • fucalost

          yesterday at 6:18 PM

          This looks great OP. Do you have anything on the roadmap that you’d be open to receiving PRs for? I noticed there weren’t any issues in the repo and would be keen to lend a hand!

            • michielme

              yesterday at 6:39 PM

              Definitely open to PRs! Still early days so lots of room for improvement. Feel free to open an issue if you have ideas.

          • bityard

            yesterday at 10:51 PM

            I would deploy this today to run my backups if jobs could be defined in the UI as well.

              • michielme

                today at 4:29 AM

                Interesting idea. Right now jobs are code-only which keeps it simple, but a UI for defining basic jobs could work. I'll think about it.

                  • evolve-maz

                    today at 6:01 AM

                    FYI I had a similar problem to yours in terms of having jobs I wanted to run on a schedule. I also had an extra layer where I wanted to let users to define jobs with their own special parameters etc. Maybe what I did is helpful for you:

                    - Form submission in front-end admin panel for users, for "new scheduled job"

                    - Form allows defining a job name, job type (while I let users define jobs, I limit it to a subset of python functions that I trust but are still general enough), job parameters (just a json blob for kwargs for the python func), frequency, and timeout.

                    - For the whitelisting of functions it's easiest to have a directory in your src which has the different python functions that are usable, and when you do a "get" for the form you populate the dropdown with the scripts from that directory / some metadata.

                    - The backend (fastAPI) saves the details in a DB and creates a CRON file for the job, to add to the crontab. I basically have a template bash statement with the timeout built in and logging hooked up to it. And when python functions are called I have a helper which grabs the JSON kwargs from the DB or a filecache (if remote DB and I don't want to hit it every minute or something) to avoid cmd line injection.

                    - Also have an "edit scheduled job" which opens the same form view but with items pre-populated, and the submit going to a patch endpoint instead of a post.

                    It's stupid simple but lets users define a range of jobs. Things like having daily backups, where to send the backups, pulling things from / pushing things to an API frequently, etc.

                      • michielme

                        today at 6:19 AM

                        Really appreciate you sharing this setup. The cron file generation for persistence is clever, and the whitelisting approach for user-defined jobs makes a lot of sense. Might borrow some of these ideas if I add a UI for job creation. Thanks!