{"id":8088,"library":"django-apscheduler","title":"Django APScheduler","description":"django-apscheduler is a Django application that provides a lightweight wrapper around APScheduler, enabling the scheduling and persistence of background jobs within a Django project using its ORM. It allows for managing scheduled tasks directly through the Django admin interface and is suitable for applications requiring basic scheduling features without external task queues like Celery. The current version is 0.7.0, and releases occur as needed to support newer Django/Python versions and address fixes.","status":"active","version":"0.7.0","language":"python","source_language":"en","source_url":"https://github.com/jcass77/django-apscheduler","tags":["django","scheduler","background tasks","jobs","apscheduler"],"install":[{"cmd":"pip install django-apscheduler","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core scheduling library. django-apscheduler provides a wrapper for it.","package":"APScheduler","optional":false},{"reason":"Web framework that django-apscheduler integrates with.","package":"Django","optional":false}],"imports":[{"wrong":"from django_apscheduler.jobstores import DjangoJobStore","symbol":"default_app_config","correct":"from django_apscheduler import default_app_config"}],"quickstart":{"code":"import logging\nfrom django.conf import settings\nfrom apscheduler.schedulers.blocking import BlockingScheduler\nfrom apscheduler.triggers.cron import CronTrigger\nfrom django.core.management.base import BaseCommand\nfrom django_apscheduler.jobstores import DjangoJobStore\nfrom django_apscheduler.models import DjangoJobExecution\nfrom django_apscheduler import util\n\nlogger = logging.getLogger(__name__)\n\ndef my_job():\n    # Your job processing logic here...\n    logger.info(\"My job is running!\")\n\n# The `close_old_connections` decorator ensures that database connections that have become\n# unusable or are obsolete are closed before and after your job has run. You should use it\n# to wrap any jobs that you schedule that access the Django database in any way.\n@util.close_old_connections\ndef delete_old_job_executions(max_age=604_800):\n    \"\"\"This job deletes APScheduler job execution entries older than `max_age` from the database.\"\"\"\n    logger.info(\n        \"Deleting old job executions... (anything older than %s seconds)\", max_age\n    )\n    DjangoJobExecution.objects.delete_old_job_executions(max_age)\n\nclass Command(BaseCommand):\n    help = \"Runs APScheduler.\"\n\n    def handle(self, *args, **options):\n        scheduler = BlockingScheduler(timezone=settings.TIME_ZONE)\n        scheduler.add_jobstore(DjangoJobStore(), \"default\")\n\n        scheduler.add_job(\n            my_job,\n            trigger=CronTrigger(second=\"*/10\"),  # Every 10 seconds\n            id=\"my_job\",  # The `id` assigned to each job MUST be unique\n            max_instances=1,\n            replace_existing=True,\n        )\n        logger.info(\"Added job 'my_job'.\")\n\n        scheduler.add_job(\n            delete_old_job_executions,\n            trigger=CronTrigger(day_of_week=\"mon\", hour=\"00\", minute=\"00\"),  # Midnight on Monday\n            id=\"delete_old_job_executions\",\n            max_instances=1,\n            replace_existing=True,\n        )\n        logger.info(\n            \"Added daily job: 'delete_old_job_executions'.\"\n        )\n\n        # Add a listener to log job executions and errors\n        # register_events(scheduler)\n\n        scheduler.start()\n        logger.info(\"Scheduler started. Press Ctrl+C to exit.\")\n\n# To run this, save it as `your_project_name/management/commands/runapscheduler.py`\n# Then, in your Django settings.py, add 'django_apscheduler' to INSTALLED_APPS.\n# Run migrations: `python manage.py migrate`\n# Start the scheduler: `python manage.py runapscheduler` (preferably in a dedicated process)","lang":"python","description":"To set up `django-apscheduler`, first add `django_apscheduler` to your `INSTALLED_APPS`. Then, create a custom Django management command (e.g., `your_project_name/management/commands/runapscheduler.py`) to initialize and start the scheduler with the `DjangoJobStore`. This approach is recommended to ensure a single scheduler instance runs in a dedicated process, avoiding duplicate job executions in multi-process web server environments. Finally, run `python manage.py migrate` and then execute your custom command, typically managed by a process supervisor like systemd or Supervisor."},"warnings":[{"fix":"Upgrade Python to 3.9+ and Django to 4.2+.","message":"Version 0.7.0 dropped support for Python 3.8 and Django 3.2. Ensure your environment meets the new minimum requirements.","severity":"breaking","affected_versions":"0.7.0+"},{"fix":"Run the scheduler in a single, dedicated process using a custom Django management command (e.g., `python manage.py runapscheduler`), managed by a process supervisor like systemd or Supervisor. Do not start the scheduler directly in `apps.py`'s `ready()` method or `urls.py` if running with multiple web server workers. [1, 7, 8, 13, 16]","message":"Running `django-apscheduler` within a multi-process web server (e.g., Gunicorn with multiple workers) can lead to jobs running multiple times or being missed, as APScheduler lacks inter-process synchronization. It does not support shared job stores across multiple active schedulers.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Use `scheduler.add_job()` or `@scheduled_job` instead of `@register_job` for scheduling tasks.","message":"The `@register_job` decorator was deprecated in favor of APScheduler's native `add_job()` method or `@scheduled_job` decorator.","severity":"deprecated","affected_versions":"0.5.0+"},{"fix":"Apply the `@util.close_old_connections` decorator to any scheduled job function that interacts with the Django ORM. For persistent issues, consider implementing a database connection pooler (e.g., PgBouncer for PostgreSQL) as part of your deployment strategy. [8, 13]","message":"Jobs that access the Django database (ORM) can suffer from 'lost connection' errors or timeouts. Django's database connection management is typically designed for short-lived HTTP requests.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure `django-apscheduler`'s `APScheduler` dependency is `<4.0` unless an explicit update to `django-apscheduler` for `APScheduler` 4.0+ is released. While v0.7.0 bumps dependencies, APScheduler 4.0 requires deep integration changes not just a version bump. [3, 7, 13, 14]","message":"APScheduler 4.0 introduced significant architectural changes (e.g., new job store design, event brokers, new terminology). `django-apscheduler` versions prior to one explicitly stating APScheduler 4.0 compatibility may not work correctly with `APScheduler` 4.x.","severity":"breaking","affected_versions":"< 0.7.0 (likely continues for future 3.x APScheduler versions compatible with django-apscheduler 0.7.0)"}],"env_vars":null,"search_vec":"'0.7.0':63 'address':75 'admin':42 'allow':33 'applic':9,48 'apschedul':2,5,16,82 'around':15 'background':23,79 'basic':50 'celeri':58 'current':60 'direct':38 'django':1,4,8,27,41,77 'django-apschedul':3 'django/python':72 'enabl':17 'extern':54 'featur':52 'fix':76 'interfac':43 'job':24,81 'lightweight':13 'like':57 'manag':35 'need':68 'newer':71 'occur':66 'orm':31 'persist':21 'project':28 'provid':11 'queue':56 'releas':65 'requir':49 'schedul':19,36,51,78 'suitabl':46 'support':70 'task':37,55,80 'use':29 'version':61,73 'within':25 'without':53 'wrapper':14","created_at":"2026-04-16T17:00:21.657051+00:00","updated_at":"2026-04-16T17:00:21.657051+00:00","problems":null,"ecosystem":"pypi","meta_description":null,"install_score":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":"0.7.0","cli_name":"","cli_version":null,"type":"library","homepage":null,"github":"http://github.com/jcass77/django-apscheduler","docs":null,"changelog":null,"pypi":"https://pypi.org/project/django-apscheduler/","npm":null,"openapi_spec":null,"status_page":null,"smithery":null,"categories":["web-framework","database","workflow"],"base_url":null,"auth_type":null,"provenance":{"verified_status":"passing","verified_at":"2026-06-30","last_verified":"2026-06-30","next_check":"2026-07-30","install_tag":null}}