mirror of https://github.com/interlegis/sigi.git
Sesóstris Vieira
10 months ago
15 changed files with 574 additions and 12 deletions
@ -0,0 +1,90 @@ |
|||||
|
from django_extensions.management.jobs import BaseJob |
||||
|
from django_extensions.management.jobs import get_jobs |
||||
|
from django.utils import timezone |
||||
|
from django.utils.formats import localize |
||||
|
from django.utils.translation import gettext as _ |
||||
|
from sigi.apps.utils.models import Cronjob, JobSchedule |
||||
|
|
||||
|
WHEN_SETS = { |
||||
|
"daily": "0 0 * * *", |
||||
|
"hourly": "0 * * * *", |
||||
|
"monthly": "0 0 1 * *", |
||||
|
"weekly": "0 0 * * 0", |
||||
|
"yearly": "0 0 1 1 *", |
||||
|
"minutely": "* * * * *", |
||||
|
} |
||||
|
|
||||
|
|
||||
|
class Job(BaseJob): |
||||
|
help = "Controlador de cronjobs do SIGI." |
||||
|
|
||||
|
def execute(self): |
||||
|
print("Rodando controlador de jobs...") |
||||
|
self.remove_old_jobs() |
||||
|
self.sync_new_jobs() |
||||
|
self.run_scheduled() |
||||
|
self.schedule_jobs() |
||||
|
|
||||
|
def remove_old_jobs(self): |
||||
|
"""Remover das tabelas os jobs que foram removidos do código""" |
||||
|
print("\tRemover das tabelas os jobs que foram removidos do código...") |
||||
|
all_jobs = get_jobs() |
||||
|
excludes = Cronjob.objects.all() |
||||
|
for app_name, job_name in all_jobs.keys(): |
||||
|
excludes = excludes.exclude(app_name=app_name, job_name=job_name) |
||||
|
print("\t\t", excludes.delete()) |
||||
|
|
||||
|
def sync_new_jobs(self): |
||||
|
""" |
||||
|
Atualizar a tabela de JOBS com os novos JOBS que tenham sido criados |
||||
|
""" |
||||
|
print( |
||||
|
"\tAtualizar a tabela de JOBS com os novos JOBS que tenham " |
||||
|
"sido criados..." |
||||
|
) |
||||
|
all_jobs = get_jobs() |
||||
|
for (app_name, job_name), JobClass in all_jobs.items(): |
||||
|
if app_name == "sigi.apps.utils" and job_name == "job_controller": |
||||
|
# Ignorar job_controller |
||||
|
continue |
||||
|
try: |
||||
|
job = Cronjob.objects.get(app_name=app_name, job_name=job_name) |
||||
|
except Cronjob.DoesNotExist: |
||||
|
# Inserir o JOB na tabela de JOBS # |
||||
|
job_obj = JobClass() |
||||
|
if job_obj.when in WHEN_SETS: |
||||
|
expressao_cron = WHEN_SETS[job_obj.when] |
||||
|
else: |
||||
|
expressao_cron = WHEN_SETS["daily"] # Default |
||||
|
job = Cronjob( |
||||
|
app_name=app_name, |
||||
|
job_name=job_name, |
||||
|
expressao_cron=expressao_cron, |
||||
|
) |
||||
|
job.save() |
||||
|
print(f"\t\tNovo job encontrado: {job_name}: {job_obj.help}") |
||||
|
|
||||
|
def run_scheduled(self): |
||||
|
"""Executa os jobs que estão agendados""" |
||||
|
print("\tExecutar os jobs que estão agendados...") |
||||
|
for sched in JobSchedule.objects.filter( |
||||
|
status=JobSchedule.STATUS_AGENDADO |
||||
|
): |
||||
|
agora = timezone.localtime() |
||||
|
if sched.iniciar <= agora: |
||||
|
sched.run_job() |
||||
|
|
||||
|
def schedule_jobs(self): |
||||
|
"""Criar agenda para próxima execução""" |
||||
|
print("\tCriar agenda para próxima execução...") |
||||
|
for job in Cronjob.objects.exclude( |
||||
|
jobschedule__status__in=[ |
||||
|
JobSchedule.STATUS_AGENDADO, |
||||
|
JobSchedule.STATUS_EXECUTANDO, |
||||
|
] |
||||
|
): |
||||
|
sched = job.next_schedule() |
||||
|
print( |
||||
|
f"\t\tAgendado job {sched.job.job_name} " |
||||
|
f"para {localize(sched.iniciar)}" |
||||
|
) |
@ -0,0 +1,45 @@ |
|||||
|
# Generated by Django 4.2.7 on 2024-02-26 12:53 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('utils', '0001_initial'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.CreateModel( |
||||
|
name='Cronjob', |
||||
|
fields=[ |
||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
|
('app_name', models.CharField(editable=False, max_length=100, verbose_name='app')), |
||||
|
('job_name', models.CharField(editable=False, max_length=100, verbose_name='job')), |
||||
|
('expressao_cron', models.CharField(default='* * * * *', help_text="Usar expressoões no formato padrão de CRON: 'minute hour day month day-of-week'. Mais detalhes: <a href='https://help.ubuntu.com/community/CronHowto'>CronHowTo</a>", max_length=100, verbose_name='expressão CRON')), |
||||
|
], |
||||
|
options={ |
||||
|
'verbose_name': 'Cron job', |
||||
|
'verbose_name_plural': 'Cron jobs', |
||||
|
'ordering': ('app_name', 'job_name'), |
||||
|
}, |
||||
|
), |
||||
|
migrations.CreateModel( |
||||
|
name='JobSchedule', |
||||
|
fields=[ |
||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
|
('iniciar', models.DateTimeField(verbose_name='Iniciar em')), |
||||
|
('iniciado', models.DateTimeField(blank=True, null=True, verbose_name='Iniciado em')), |
||||
|
('status', models.CharField(choices=[('A', 'Agendado'), ('E', 'Executando'), ('C', 'Concluído')], default='A', max_length=1, verbose_name='estado')), |
||||
|
('tempo_gasto', models.DurationField(blank=True, editable=False, null=True, verbose_name='tempo gasto')), |
||||
|
('resultado', models.TextField(blank=True, editable=False, verbose_name='resultado da execução')), |
||||
|
('job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='utils.cronjob', verbose_name='Cron job')), |
||||
|
], |
||||
|
options={ |
||||
|
'verbose_name': 'Agenda de execução', |
||||
|
'verbose_name_plural': 'Agenda de execuções', |
||||
|
'ordering': ('iniciar',), |
||||
|
}, |
||||
|
), |
||||
|
] |
@ -0,0 +1,33 @@ |
|||||
|
{% extends "admin/change_form.html" %} |
||||
|
{% load static i18n %} |
||||
|
|
||||
|
{% block extrastyle %} |
||||
|
{{ block.super }} |
||||
|
<style type="text/css"> |
||||
|
.display { |
||||
|
flex: 1; |
||||
|
} |
||||
|
h1 { |
||||
|
font-size: 2.5rem; |
||||
|
} |
||||
|
h2 { |
||||
|
font-size: 2rem; |
||||
|
} |
||||
|
h3 { |
||||
|
font-size: 1.5rem; |
||||
|
} |
||||
|
</style> |
||||
|
{% endblock %} |
||||
|
|
||||
|
{% block after_field_sets %} |
||||
|
<fieldset class="module aligned "> |
||||
|
<div class="form-row field-resultado"> |
||||
|
<div class="input-field"> |
||||
|
<div class="readonly-label"><label>Resultado:</label></div> |
||||
|
<div class="readonly"> |
||||
|
<pre>{{ original.resultado }}</pre> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</fieldset> |
||||
|
{% endblock %} |
Loading…
Reference in new issue