How to run python script as daemon/cronjob in Django?

176 views Asked by At

I have developped a Django app and try to solve what should be simple... but more I read about this and more it seems to be complicated.

I want an email to be send to new user each time new user account is created in auth_user. I first thought about signals and it works but not when I execute a sql script to create user account.

So, I thought about using trigger and Postgresql LISTEN/NOTIFY. I have created a trigger on auth_user insert and a function executed with this trigger that NOTIFY this event using perform pg_notify('new_user', NEW.username);

Then, I have a python script that LISTEN new_user signal and send email.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# https://www.depesz.com/2012/06/13/how-to-send-mail-from-database/
# https://www.psycopg.org/docs/connection.html
# https://www.psycopg.org/docs/advanced.html#async-notify

import select
import psycopg2
import psycopg2.extensions
from django.core.mail import send_mail
import random, string
from django.contrib.auth.hashers import make_password

dbc = psycopg2.connect(database='db', host='localhost', port=5433, user='user', password='user')
dbc.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
cur = dbc.cursor()
cur.execute('LISTEN new_user_handle')

while 1:
    if not select.select([dbc], [], [], 5) == ([], [], []):
        dbc.poll()
        while dbc.notifies:
            notify = dbc.notifies.pop()
            user_email = []
            password = generer_mot_de_passe(8)
            user_email.append('[email protected]')
            email = email_compte(user_email,notify.payload,password.get("plaintext"))


    def generer_mot_de_passe(length):
        """Générer une chaîne aléatoire de longueur fixe"""
        motDePasse = {}
        str = string.hexdigits
        password_plaintext = ''.join(random.choice(str) for i in range(length))
        password_crypt = make_password(password_plaintext)
        motDePasse['plaintext'] = password_plaintext
        motDePasse['pbkdf2'] = password_crypt
        return motDePasse


    # envoi d'email lors de la création d'un compte utilisateur
    def email_compte(user_email,identifiant,password): 

        subject = '[Moderato] Application Randomisation - Compte utilisateur '
        message = 'Test'
        email_from = '[email protected]'

        email = send_mail(subject, message, email_from , user_email)

        return None

This works, but I read that it was not the good way as PostgreSQL will queue all NOTIFYs that weren't yet handled by all LISTENING processes it will not queue them if nothing is listening. So – if your listener will die – all notifications that happened in the time between its death and restart are gone.

Some recommand to use a queue. So I have a process_queue table that is updated each time a user account is created. And now, I need to "scan" this process_queue table in a "background task" (daemon or cronjob) that is executed in a regular time basis to send email...

and do not know how to do this?

1

There are 1 answers

2
Raghav Sharma On

I recommend using celery if their is a need of cronjobs/periodic tasks or asynchronous tasks in django. check celery-django