Skip to content

Commit

Permalink
Merge pull request #398 from hibare/dev
Browse files Browse the repository at this point in the history
Dev merge
  • Loading branch information
hibare authored Jul 1, 2023
2 parents 8a1f2a5 + e03024c commit 1565a17
Show file tree
Hide file tree
Showing 44 changed files with 1,321 additions and 991 deletions.
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ DJANGO_SU_USERNAME=<VALUE>
DJANGO_SU_PASSWORD=<VALUE>
SCHEDULER_MISFIRE_GRACETIME=<VALUE>
SCHEDULER_JOB_MAX_INSTANCES=<VALUE>
SCHEDULER_JOB_REPLACE_EXISTING=<VALUE>
SCHEDULER_JOB_REPLACE_EXISTING=<VALUE>
JOB_HISTORY_PURGE_AGE=<VALUE>
NOTIFIER_HISTORY_PURGE_AGE=<VALUE>
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.11.3-slim as base
FROM python:3.11.4-slim as base

LABEL Github="hibare"

Expand Down
7 changes: 6 additions & 1 deletion backend/jobs/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.db import models
from django.contrib.postgres.fields import ArrayField
from model_utils import FieldTracker
from moni.utils.favicon import Favicon
from moni.utils.funcs import get_str_uuid
from notifiers.models import Notifiers

Expand Down Expand Up @@ -51,6 +52,10 @@ class Meta:
def __str__(self) -> str:
return self.uuid

def update_favicon_url(self):
self.favicon_url = Favicon.get_favicon_url(self.url)
self.save()


class JobsHistoryManager(models.Manager):
"""Job history manager"""
Expand All @@ -59,7 +64,7 @@ def delete_old_history(self, max_age: int) -> None:
"""Delete job history from database"""

self.filter(timestamp__lte=timezone.now() -
timedelta(seconds=max_age)).delete()
timedelta(days=max_age)).delete()


class JobsHistory(models.Model):
Expand Down
25 changes: 25 additions & 0 deletions backend/jobs/scheduler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""Schedule jobs"""

from django_apscheduler.models import DjangoJobExecution
from django.conf import settings
from jobs.models import Jobs
from jobs.models import JobsHistory


def delete_old_job_executions(max_age=604_800):
"""This job deletes all apscheduler job executions older than `max_age` (in seconds) from the database."""

DjangoJobExecution.objects.delete_old_job_executions(max_age)


def delete_old_job_history():
"""This job deletes all job history records older than `settings.JOB_HISTORY_PURGE_AGE` (in days) from the database."""

JobsHistory.objects.delete_old_history(settings.JOB_HISTORY_PURGE_AGE)


def update_favicon_url() -> None:
"""Update favicons of all registered jobs"""

for job in Jobs.objects.all():
job.update_favicon_url()
16 changes: 1 addition & 15 deletions backend/jobs/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import logging
from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver
from django_apscheduler.models import DjangoJobExecution
from jobs.models import Jobs
from jobs.operations import JobOps
from moni.utils.favicon import Favicon
Expand All @@ -24,9 +23,7 @@ def job_post_save(sender, instance, created, **kwargs):

if created:
JobOps.add(instance.uuid)

favicon_url = Favicon.get_favicon_url(instance.url)
Jobs.objects.filter(uuid=instance.uuid).update(favicon_url=favicon_url)
instance.update_favicon_url()
else:
if instance.tracker.has_changed('state'):
if instance.state:
Expand All @@ -46,14 +43,3 @@ def job_post_delete(sender, instance, **kwargs):
"""Delete scheduled job when the job record is deleted"""

JobOps.remove(instance.uuid)


@receiver(post_save, sender=DjangoJobExecution)
def delete_execution_record(sender, instance, created, **kwargs):
"""
Django APScheduler stores execution reccords in DB. As app is storing custom execution records, this is no longer needed.
Delete the record as soon as it is saved.
"""

if created:
instance.delete()
72 changes: 72 additions & 0 deletions backend/moni/openapi-schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,66 @@ paths:
description: "Invalid notifier / No jobs found"
tags:
- Notifiers
/api/v1/notifiers/{uuid}/pause/:
post:
operationId: Pause a Notifier
description: Pause a Notifier
parameters:
- name: uuid
in: path
required: true
description: A unique value identifying this Notifiers.
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/Pause"
description: ""
"401":
$ref: "#/components/responses/UnauthorizedError"
"404":
description: "No such Notifier"
"409":
content:
application/json:
schema:
$ref: "#/components/schemas/Pause"
description: "Conflict with the state"
tags:
- Notifiers
/api/v1/notifiers/{uuid}/resume/:
post:
operationId: Resume a Notifier
description: Resume a Notifier
parameters:
- name: uuid
in: path
required: true
description: A unique value identifying this Notifiers.
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/Resume"
description: ""
"401":
$ref: "#/components/responses/UnauthorizedError"
"404":
description: "No such Notifier"
"409":
content:
application/json:
schema:
$ref: "#/components/schemas/Resume"
description: "Conflict with the state"
tags:
- Notifiers
/api/v1/notifiers/history/:
get:
operationId: List notificaitons history
Expand Down Expand Up @@ -1244,3 +1304,15 @@ components:
error:
type: string
readOnly: true
Pause:
type: object
properties:
details:
type: string
readOnly: true
Resume:
type: object
properties:
details:
type: string
readOnly: true
104 changes: 41 additions & 63 deletions backend/moni/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,15 @@
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
from django_apscheduler.jobstores import register_events
from django_apscheduler.models import DjangoJobExecution
from jobs.models import JobsHistory
from notifiers.models import NotifiersHistory
from jobs.scheduler import delete_old_job_executions, delete_old_job_history, update_favicon_url
from notifiers.scheduler import delete_old_notifier_history

logger = logging.getLogger(__name__)

# Create scheduler to run in a thread inside the application process
scheduler = BackgroundScheduler(settings.SCHEDULER_CONFIG)


def delete_old_job_executions(max_age=604_800):
"""This job deletes all apscheduler job executions older than `max_age` from the database."""
DjangoJobExecution.objects.delete_old_job_executions(max_age)


def delete_old_job_history(max_age=604800):
"""This job deletes all job history records older than `max_age` from the database."""

JobsHistory.objects.delete_old_history(max_age)


def delete_old_notifier_history(max_age=604800):
"""This job delete all notifier history older than `max_age` from the database"""

NotifiersHistory.objects.delete_old_history(max_age)


def start(default_jobs=True):
"""Start Scheduler"""

Expand All @@ -40,54 +22,50 @@ def start(default_jobs=True):
logging.basicConfig()
logging.getLogger('apscheduler').setLevel(logging.DEBUG)

if default_jobs:
scheduler.add_job(
delete_old_job_executions,
trigger=CronTrigger(
hour="00", minute="00"
), # Everyday midnight
id="delete_old_job_executions",
max_instances=settings.SCHEDULER_JOB_MAX_INSTANCES,
replace_existing=settings.SCHEDULER_JOB_REPLACE_EXISTING,
misfire_grace_time=settings.SCHEDULER_JOB_MISFIRE_GRACETIME
)
logger.info(
"Added daily job: 'delete_old_job_executions'."
)

scheduler.add_job(
delete_old_job_history,
trigger=CronTrigger(
hour="00", minute="00"
), # Everyday midnight
id="delete_old_job_history",
max_instances=settings.SCHEDULER_JOB_MAX_INSTANCES,
replace_existing=settings.SCHEDULER_JOB_REPLACE_EXISTING,
misfire_grace_time=settings.SCHEDULER_JOB_MISFIRE_GRACETIME
)
logger.info(
"Added daily job: 'delete_old_job_history'."
)

scheduler.add_job(
delete_old_notifier_history,
trigger=CronTrigger(
hour="00", minute="00"
), # Everyday midnight
id="delete_old_notifier_history",
max_instances=settings.SCHEDULER_JOB_MAX_INSTANCES,
replace_existing=settings.SCHEDULER_JOB_REPLACE_EXISTING,
misfire_grace_time=settings.SCHEDULER_JOB_MISFIRE_GRACETIME
)
logger.info(
"Added daily job: 'delete_old_notifier_history'."
)

# Add the scheduled jobs to the Django admin interface
register_events(scheduler)

scheduler.start()

default_jobs_func = {
"delete_old_job_executions": {
"func": delete_old_job_executions,
"trigger": CronTrigger(
hour="00", minute="00"
)
},
"delete_old_job_history": {
"func": delete_old_job_history,
"trigger": CronTrigger(
hour="00", minute="00"
)
},
"delete_old_notifier_history": {
"func": delete_old_notifier_history,
"trigger": CronTrigger(
hour="00", minute="00"
)
},
"update_favicon_url": {
"func": update_favicon_url,
"trigger": CronTrigger(
hour="00", minute="00"
)
}
}

if default_jobs:
for id, det in default_jobs_func.items():
scheduler.add_job(
det['func'],
trigger=det['trigger'],
id=id,
max_instances=settings.SCHEDULER_JOB_MAX_INSTANCES,
replace_existing=settings.SCHEDULER_JOB_REPLACE_EXISTING,
misfire_grace_time=settings.SCHEDULER_JOB_MISFIRE_GRACETIME
)
logger.info("Added daily job: '%s'.", id)


def shutdown():
"""Shutdown scheduler"""
Expand Down
4 changes: 4 additions & 0 deletions backend/moni/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,3 +232,7 @@
# App info
VERSION = get_version()
TITLE = get_title()

JOB_HISTORY_PURGE_AGE = config('JOB_HISTORY_PURGE_AGE', default=30, cast=int)
NOTIFIER_HISTORY_PURGE_AGE = config(
'NOTIFIER_HISTORY_PURGE_AGE', default=30, cast=int)
4 changes: 2 additions & 2 deletions backend/notifiers/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ class NotifiersAdmin(admin.ModelAdmin):
"""Notifiers admin class"""

empty_value_display = '-empty-'
list_display = ['uuid', 'url', 'type',
list_display = ['uuid', 'state', 'url', 'type',
'description']
list_filter = ['type']
list_filter = ['type', 'state']

def has_add_permission(self, request: HttpRequest) -> bool:
return False
Expand Down
18 changes: 18 additions & 0 deletions backend/notifiers/migrations/0007_notifiers_state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.1 on 2023-06-08 14:22

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('notifiers', '0006_alter_notifiers_description'),
]

operations = [
migrations.AddField(
model_name='notifiers',
name='state',
field=models.BooleanField(default=True),
),
]
3 changes: 2 additions & 1 deletion backend/notifiers/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class Notifiers(models.Model):
type = models.CharField(max_length=10, choices=NOTIFIER_TYPES)
title = models.CharField(max_length=15)
description = models.TextField(default="", blank=True)
state = models.BooleanField(default=True)

class Meta:
indexes = [
Expand All @@ -44,7 +45,7 @@ def delete_old_history(self, max_age: int) -> None:
"""Delete notifiers history from database"""

self.filter(timestamp__lte=timezone.now() -
timedelta(seconds=max_age)).delete()
timedelta(days=max_age)).delete()


class NotifiersHistory(models.Model):
Expand Down
11 changes: 11 additions & 0 deletions backend/notifiers/scheduler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""Schedule notifier jobs"""

from django.conf import settings
from notifiers.models import NotifiersHistory


def delete_old_notifier_history():
"""This job delete all notifier history older than `settings.NOTIFIER_HISTORY_PURGE_AGE` (in days) from the database"""

NotifiersHistory.objects.delete_old_history(
settings.NOTIFIER_HISTORY_PURGE_AGE)
Loading

0 comments on commit 1565a17

Please sign in to comment.