skip to Main Content

I have a Django app setup with some scheduled tasks. The app is deployed on Heroku with Redis. The task runs if invoked synchronously in the console, or locally when I also have redis and celery running. However, the scheduled jobs are not running on Heroku.

My task:

@shared_task(name="send_emails")
def send_emails():
.....

celery.py:

from __future__ import absolute_import, unicode_literals

import os
from celery import Celery
from celery.schedules import crontab

# set the default Django settings module for the 'celery' program.
# this is also used in manage.py
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'my_app.settings')

# Get the base REDIS URL, default to redis' default
BASE_REDIS_URL = os.environ.get('REDIS_URL', 'redis://localhost:6379')

app = Celery('my_app')

# Using a string here means the worker don't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
#   should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')

# Load task modules from all registered Django app configs.
app.autodiscover_tasks()

app.conf.broker_url = BASE_REDIS_URL

# this allows you to schedule items in the Django admin.
app.conf.beat_scheduler = 'django_celery_beat.schedulers.DatabaseScheduler'

# These are the scheduled jobs
app.conf.beat_schedule = {
    'send_emails_crontab': {
        'task': 'send_emails',
        'schedule': crontab(hour=9, minute=0),
        'args': (),
    }
}

In Procfile:
worker: celery -A my_app worker --beat -S django -l info

I’ve spun up the worker with heroku ps:scale worker=1 -a my-app.
I can see the registered tasks under [tasks] in the worker logs.
However, the scheduled tasks are not running at their scheduled time. Calling send_emails.delay() in the production console does work.
How do I get the worker to stay alive and / or run the job at the scheduled time?

I have a workaround using a command and heroku scheduler. Just unsure if that’s the best way to do it.

2

Answers


  1. If you’re on free demo, you should know that heroku server sleeps and if your scheduled task becomes due when your server is sleeping, it won’t run.

    Login or Signup to reply.
  2. I share you any ideas.

    1. Run console and get the datetime of Dyno. The Dyno use a localtime US.

    2. The DynoFree sleeps each 30 minutes and only 450 hours/month.

    3. Try change celery to BackgroundScheduler,
      you need add a script clock.py as:

       from myapp import myfunction
       from datetime import datetime
       from apscheduler.schedulers.background import BackgroundScheduler
       from apscheduler.schedulers.blocking import BlockingScheduler
       from time import monotonic, sleep, ctime
       import os
      
       sched = BlockingScheduler()
       hour = int(os.environ.get("SEARCH_HOUR"))
       minutes = int(os.environ.get("SEARCH_MINUTES"))
      
       @sched.scheduled_job('cron', day_of_week='mon-sun', hour=hour, minute = minutes)
       def scheduled_job():
           print('This job: Execute myfunction every at ', hour, ':', minutes)        
           #My function
           myfunction()
      
       sched.start(
      

    )

    In Procfile:

    clock: python clock.py
    

    and run:

    heroku ps:scale clock=1 --app thenameapp
    

    Regards.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search