242 lines
7.9 KiB
Python
242 lines
7.9 KiB
Python
"""
|
|
Commande Django pour exécuter les tâches planifiées.
|
|
|
|
Cette commande doit être appelée régulièrement (par exemple via cron toutes les heures).
|
|
Elle vérifie quelles tâches doivent être exécutées et les lance.
|
|
|
|
Usage:
|
|
python manage.py run_scheduled_commands
|
|
"""
|
|
|
|
from django.core.management.base import BaseCommand
|
|
from django.core.management import call_command
|
|
from django.utils import timezone
|
|
from django.core.mail import EmailMessage
|
|
from django.conf import settings
|
|
from common.models_scheduled_tasks import ScheduledCommand, CommandExecutionLog
|
|
from io import StringIO
|
|
import sys
|
|
import traceback
|
|
import os
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = 'Exécute les commandes planifiées qui doivent être exécutées'
|
|
|
|
def handle(self, *args, **options):
|
|
self.stdout.write(self.style.WARNING(f'\n=== Vérification des tâches planifiées - {timezone.now()} ===\n'))
|
|
|
|
# Récupérer toutes les tâches actives qui doivent être exécutées
|
|
tasks = ScheduledCommand.objects.filter(is_active=True)
|
|
|
|
if not tasks.exists():
|
|
self.stdout.write(self.style.WARNING('Aucune tâche planifiée active trouvée.'))
|
|
return
|
|
|
|
self.stdout.write(f'Nombre de tâches actives: {tasks.count()}')
|
|
|
|
tasks_to_run = []
|
|
for task in tasks:
|
|
if task.should_run_now():
|
|
tasks_to_run.append(task)
|
|
self.stdout.write(self.style.SUCCESS(f' ✓ {task.name} doit être exécutée'))
|
|
else:
|
|
next_run = task.next_run.strftime('%Y-%m-%d %H:%M') if task.next_run else 'Non planifiée'
|
|
self.stdout.write(f' - {task.name} : prochaine exécution le {next_run}')
|
|
|
|
if not tasks_to_run:
|
|
self.stdout.write(self.style.WARNING('\nAucune tâche à exécuter maintenant.'))
|
|
return
|
|
|
|
self.stdout.write(self.style.SUCCESS(f'\n{len(tasks_to_run)} tâche(s) à exécuter\n'))
|
|
|
|
# Exécuter chaque tâche
|
|
for task in tasks_to_run:
|
|
self.execute_task(task)
|
|
|
|
self.stdout.write(self.style.SUCCESS('\n=== Vérification terminée ===\n'))
|
|
|
|
def execute_task(self, task):
|
|
"""
|
|
Exécute une tâche planifiée.
|
|
"""
|
|
self.stdout.write(self.style.WARNING(f'\n>>> Exécution de: {task.name}'))
|
|
self.stdout.write(f' Commande: {task.command_name}')
|
|
self.stdout.write(f' Arguments: {task.command_args}')
|
|
|
|
# Créer un log d'exécution
|
|
log = CommandExecutionLog.objects.create(
|
|
scheduled_command=task,
|
|
status='running'
|
|
)
|
|
|
|
# Capturer la sortie
|
|
output = StringIO()
|
|
error_output = StringIO()
|
|
|
|
old_stdout = sys.stdout
|
|
old_stderr = sys.stderr
|
|
|
|
try:
|
|
# Rediriger stdout et stderr
|
|
sys.stdout = output
|
|
sys.stderr = error_output
|
|
|
|
# Exécuter la commande
|
|
call_command(task.command_name, **task.command_args)
|
|
|
|
# Restaurer stdout/stderr
|
|
sys.stdout = old_stdout
|
|
sys.stderr = old_stderr
|
|
|
|
# Marquer comme succès
|
|
log.status = 'success'
|
|
log.output = output.getvalue()
|
|
log.finished_at = timezone.now()
|
|
log.calculate_duration()
|
|
log.save()
|
|
|
|
# Mettre à jour la tâche
|
|
task.last_run = timezone.now()
|
|
task.next_run = task.calculate_next_run()
|
|
task.save()
|
|
|
|
self.stdout.write(self.style.SUCCESS(f' ✓ Succès (durée: {log.duration_seconds:.1f}s)'))
|
|
|
|
# Envoyer l'email si configuré
|
|
if task.send_email and task.email_recipients:
|
|
self.send_success_email(task, log)
|
|
|
|
except Exception as e:
|
|
# Restaurer stdout/stderr
|
|
sys.stdout = old_stdout
|
|
sys.stderr = old_stderr
|
|
|
|
# Marquer comme erreur
|
|
log.status = 'error'
|
|
log.output = output.getvalue()
|
|
log.error_message = f"{str(e)}\n\n{traceback.format_exc()}\n\n{error_output.getvalue()}"
|
|
log.finished_at = timezone.now()
|
|
log.calculate_duration()
|
|
log.save()
|
|
|
|
# Mettre à jour la tâche quand même
|
|
task.last_run = timezone.now()
|
|
task.next_run = task.calculate_next_run()
|
|
task.save()
|
|
|
|
self.stdout.write(self.style.ERROR(f' ✗ Erreur: {str(e)}'))
|
|
|
|
# Envoyer l'email d'erreur si configuré
|
|
if task.send_email and task.email_recipients:
|
|
self.send_error_email(task, log)
|
|
|
|
def send_success_email(self, task, log):
|
|
"""
|
|
Envoie un email de succès.
|
|
"""
|
|
try:
|
|
subject = task.email_subject or f"[StreetUp] Tâche planifiée réussie: {task.name}"
|
|
|
|
# Vérifier si un fichier a été généré
|
|
output_file = task.command_args.get('output', '')
|
|
|
|
body = f"""
|
|
Bonjour,
|
|
|
|
La tâche planifiée "{task.name}" s'est exécutée avec succès.
|
|
|
|
Détails:
|
|
- Commande: {task.command_name}
|
|
- Démarré: {log.started_at.strftime('%Y-%m-%d %H:%M:%S')}
|
|
- Terminé: {log.finished_at.strftime('%Y-%m-%d %H:%M:%S')}
|
|
- Durée: {log.duration_seconds:.1f} secondes
|
|
|
|
Prochaine exécution: {task.next_run.strftime('%Y-%m-%d %H:%M') if task.next_run else 'Non planifiée'}
|
|
|
|
---
|
|
Sortie de la commande:
|
|
{log.output}
|
|
|
|
---
|
|
Cordialement,
|
|
StreetUp - Système de tâches planifiées
|
|
"""
|
|
|
|
recipients = [email.strip() for email in task.email_recipients.split(',')]
|
|
|
|
email = EmailMessage(
|
|
subject=subject,
|
|
body=body,
|
|
from_email=settings.DEFAULT_FROM_EMAIL,
|
|
to=recipients,
|
|
)
|
|
|
|
# Attacher le fichier si il existe
|
|
if output_file and os.path.exists(output_file):
|
|
email.attach_file(output_file)
|
|
self.stdout.write(self.style.SUCCESS(f' ✓ Fichier attaché: {output_file}'))
|
|
|
|
email.send(fail_silently=False)
|
|
|
|
log.email_sent = True
|
|
log.save(update_fields=['email_sent'])
|
|
|
|
self.stdout.write(self.style.SUCCESS(f' ✓ Email envoyé à: {", ".join(recipients)}'))
|
|
|
|
except Exception as e:
|
|
self.stdout.write(self.style.ERROR(f' ✗ Erreur lors de l\'envoi de l\'email: {str(e)}'))
|
|
|
|
def send_error_email(self, task, log):
|
|
"""
|
|
Envoie un email d'erreur.
|
|
"""
|
|
try:
|
|
subject = f"[StreetUp] ERREUR - Tâche planifiée: {task.name}"
|
|
|
|
body = f"""
|
|
Bonjour,
|
|
|
|
La tâche planifiée "{task.name}" a rencontré une erreur lors de son exécution.
|
|
|
|
Détails:
|
|
- Commande: {task.command_name}
|
|
- Démarré: {log.started_at.strftime('%Y-%m-%d %H:%M:%S')}
|
|
- Terminé: {log.finished_at.strftime('%Y-%m-%d %H:%M:%S')}
|
|
- Durée: {log.duration_seconds:.1f} secondes
|
|
|
|
Prochaine exécution: {task.next_run.strftime('%Y-%m-%d %H:%M') if task.next_run else 'Non planifiée'}
|
|
|
|
---
|
|
Message d'erreur:
|
|
{log.error_message}
|
|
|
|
---
|
|
Sortie de la commande:
|
|
{log.output}
|
|
|
|
---
|
|
Veuillez vérifier les logs dans l'administration Django pour plus de détails.
|
|
|
|
Cordialement,
|
|
StreetUp - Système de tâches planifiées
|
|
"""
|
|
|
|
recipients = [email.strip() for email in task.email_recipients.split(',')]
|
|
|
|
email = EmailMessage(
|
|
subject=subject,
|
|
body=body,
|
|
from_email=settings.DEFAULT_FROM_EMAIL,
|
|
to=recipients,
|
|
)
|
|
|
|
email.send(fail_silently=False)
|
|
|
|
log.email_sent = True
|
|
log.save(update_fields=['email_sent'])
|
|
|
|
self.stdout.write(self.style.WARNING(f' ! Email d\'erreur envoyé à: {", ".join(recipients)}'))
|
|
|
|
except Exception as e:
|
|
self.stdout.write(self.style.ERROR(f' ✗ Erreur lors de l\'envoi de l\'email d\'erreur: {str(e)}'))
|