Celery beat cannot update currency exchange rates with django-money

70 views Asked by At

I use django-money, then I ran celery beat to update currency exchange rates every 60 minutes with the code below. *I followed django-money doc:

# "core/celery.py"

import os

from celery import Celery

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')

app = Celery('core')

app.config_from_object('django.conf:settings', namespace='CELERY')

app.autodiscover_tasks()

@app.task(bind=True)
def debug_task(self):
    print(f'Request: {self.request!r}')
# "core/tasks.py"

from celery import shared_task
from djmoney import settings
from django.utils.module_loading import import_string

@shared_task
def update_rates(backend=settings.EXCHANGE_BACKEND, **kwargs):
    backend = import_string(backend)()
    backend.update_rates(**kwargs)
    print("Successfully updated")
# "core/settings.py"

from celery.schedules import crontab

OPEN_EXCHANGE_RATES_APP_ID = '5507ba2d9b8f4c46adca3169aef9c281' # Here

CELERY_BEAT_SCHEDULE = {
    'update_rates': {
        'task': 'core.tasks.update_rates',
        'schedule': crontab(minute='*/60'),
        'kwargs': {}  # For custom arguments
    }
}

But, I got the error below even though I set OPEN_EXCHANGE_RATES_APP_ID in settings.py as shown above:

django.core.exceptions.ImproperlyConfigured: settings.OPEN_EXCHANGE_RATES_APP_ID should be set to use OpenExchangeRatesBackend

So, how can I solve the error to update currency exchange rates every 60 minutes with celery beat?

1

There are 1 answers

0
Super Kai - Kazuya Ito On

You need to pass OPEN_EXCHANGE_RATES_APP_ID to update_rates task with 'args' in settings.py as shown below. *Actually, the celery beat example to update currency exchange rates in django-money doc is old:

# "core/settings.py"

from celery.schedules import crontab

OPEN_EXCHANGE_RATES_APP_ID = '5507ba2d9b8f4c46adca3169aef9c281' # Here

CELERY_BEAT_SCHEDULE = {
    'update_rates': {
        'task': 'core.tasks.update_rates',
        'schedule': crontab(minute='*/60'),
        'args': [OPEN_EXCHANGE_RATES_APP_ID],
    }
}

Then, update_rates task needs to receive OPEN_EXCHANGE_RATES_APP_ID with app_id, then assign it to access_key in tasks.py as shown below, then you can solve the error, then update currency exchange rates every 60 minutes with celery beat. *You can see openexchangerates.py on GitHub to know why OPEN_EXCHANGE_RATES_APP_ID needs to be assigned to access_key:

# "core/tasks.py"

from celery import shared_task
from djmoney import settings
from django.utils.module_loading import import_string

@shared_task     # Here
def update_rates(app_id):
    backend = import_string(settings.EXCHANGE_BACKEND)(
        access_key=app_id # Here
    )
    backend.update_rates()
    print("Successfully updated")

In addition, OPEN_EXCHANGE_RATES_APP_ID can be defined after the celery beat code in settings.py as shown below without any errors and I recommend to import crontab just before the celery beat code as shown below so that no errors occur:

# "core/settings.py"

from celery.schedules import crontab # Here

CELERY_BEAT_SCHEDULE = {
    'update_rates': {
        'task': 'core.tasks.update_rates',
        'schedule': crontab(minute='*/60'),
        'args': [OPEN_EXCHANGE_RATES_APP_ID],
    }
}

OPEN_EXCHANGE_RATES_APP_ID = '5507ba2d9b8f4c46adca3169aef9c281' # Here

And, you can use the new celery beat code on settings.py as shown below. *app and update_rates task need to be imported from core/celery.py and core/tasks.py respectively as shown below and I recommend to import crontab, app and update_rates just before the new celery beat code as shown below so that no errors occur:

# "core/settings.py"

from celery.schedules import crontab # Here
from .celery import app # Here
from .tasks import update_rates # Here

@app.on_after_configure.connect # Here
def setup_periodic_tasks(sender, **kwargs):
    sender.add_periodic_task(
        crontab(minute='*/1'),
        update_rates.s(OPEN_EXCHANGE_RATES_APP_ID), 
        name='update_rates'
    )

OPEN_EXCHANGE_RATES_APP_ID = '5507ba2d9b8f4c46adca3169aef9c281'