Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Notification to Admins for Ingestor Failure #387

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions django_project/core/celery.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@
# Run everyday at 00:15 UTC
'schedule': crontab(minute='15', hour='00'),
},
"monitor-ingestor-failures": {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't need to define as periodic task as it is triggered manually.

"task": "notify_ingestor_failure",
"schedule": crontab(minute="10", hour="3"),
"args": (None, "Scheduled failure check"),
},
}


Expand Down
78 changes: 76 additions & 2 deletions django_project/gap/tasks/ingestor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,17 @@

from celery.utils.log import get_task_logger

from django.core.mail import send_mail
from django.conf import settings
from django.contrib.auth import get_user_model
from django.utils import timezone

from core.celery import app
from gap.models.ingestor import IngestorSession, IngestorType
from core.models import BackgroundTask
from gap.models.ingestor import (
IngestorSession, IngestorType,
IngestorSessionStatus
)

logger = get_task_logger(__name__)

Expand All @@ -20,7 +29,11 @@
session = IngestorSession.objects.get(id=_id)
session.run()
except IngestorSession.DoesNotExist:
logger.error('Ingestor Session {} does not exists'.format(_id))
logger.error(f"Ingestor Session {_id} does not exist")
notify_ingestor_failure.delay(_id, "Session not found")
except Exception as e:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also trigger the task when CollectionSession runs with an error.

We could also run the task when the task fails unexpectedly in this BackgroundTask.task_on_errors:
https://github.com/kartoza/tomorrownow_gap/blob/main/django_project/core/models/background_task.py#L260

To run the notify task in BackgroundTask.task_on_errors, you need to check the task name whether it is ingestor session or collector session.

logger.error(f"Error in Ingestor Session {_id}: {str(e)}")
notify_ingestor_failure.delay(_id, str(e))

Check warning on line 36 in django_project/gap/tasks/ingestor.py

View check run for this annotation

Codecov / codecov/patch

django_project/gap/tasks/ingestor.py#L32-L36

Added lines #L32 - L36 were not covered by tests


@app.task(name='run_daily_ingestor')
Expand All @@ -41,3 +54,64 @@
else:
# When not created, it is run manually
session.run()


@app.task(name="notify_ingestor_failure")
def notify_ingestor_failure(session_id: int, exception: str):
"""
Celery task to notify admins if an ingestor session fails.

:param session_id: ID of the IngestorSession
:param exception: Exception message describing the failure
"""
logger.error(f"Ingestor Session {session_id} failed: {exception}")

Check warning on line 67 in django_project/gap/tasks/ingestor.py

View check run for this annotation

Codecov / codecov/patch

django_project/gap/tasks/ingestor.py#L67

Added line #L67 was not covered by tests
# Get celery task ID
task_id = notify_ingestor_failure.request.id

Check warning on line 69 in django_project/gap/tasks/ingestor.py

View check run for this annotation

Codecov / codecov/patch

django_project/gap/tasks/ingestor.py#L69

Added line #L69 was not covered by tests

# Retrieve the ingestor session
try:
session = IngestorSession.objects.get(id=session_id)
session.status = IngestorSessionStatus.FAILED
session.save()
except IngestorSession.DoesNotExist:
logger.warning(f"IngestorSession {session_id} not found.")
return

Check warning on line 78 in django_project/gap/tasks/ingestor.py

View check run for this annotation

Codecov / codecov/patch

django_project/gap/tasks/ingestor.py#L72-L78

Added lines #L72 - L78 were not covered by tests

# Log failure in BackgroundTask
BackgroundTask.objects.get_or_create(

Check warning on line 81 in django_project/gap/tasks/ingestor.py

View check run for this annotation

Codecov / codecov/patch

django_project/gap/tasks/ingestor.py#L81

Added line #L81 was not covered by tests
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BackgroundTask is automatically created when a task is triggered, so we don't need to create one in here. Each IngestorSession task has background task record. We can query by task name and context_id (value is IngestorSessionId).

task_id=task_id,
defaults={
"task_name": "notify_ingestor_failure",
"status": "FAILED",
"parameters": f"Ingestor ID: {session_id}",
"errors": exception,
"last_update": timezone.now(),
},
)

# Send an email notification to admins
# Get admin emails from the database
User = get_user_model()
admin_emails = list(

Check warning on line 95 in django_project/gap/tasks/ingestor.py

View check run for this annotation

Codecov / codecov/patch

django_project/gap/tasks/ingestor.py#L94-L95

Added lines #L94 - L95 were not covered by tests
User.objects.filter(
is_superuser=True).values_list('email', flat=True)
)
if admin_emails:
send_mail(

Check warning on line 100 in django_project/gap/tasks/ingestor.py

View check run for this annotation

Codecov / codecov/patch

django_project/gap/tasks/ingestor.py#L99-L100

Added lines #L99 - L100 were not covered by tests
subject="Ingestor Failure Alert",
message=(
f"Ingestor Session {session_id} has failed.\n\n"
f"Error: {exception}\n\n"
"Please check the logs for more details."
),
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[admin_emails],
fail_silently=False,
)
logger.info(f"Sent ingestor failure email to {admin_emails}")

Check warning on line 111 in django_project/gap/tasks/ingestor.py

View check run for this annotation

Codecov / codecov/patch

django_project/gap/tasks/ingestor.py#L111

Added line #L111 was not covered by tests
else:
logger.warning("No admin email found in settings.ADMINS")

Check warning on line 113 in django_project/gap/tasks/ingestor.py

View check run for this annotation

Codecov / codecov/patch

django_project/gap/tasks/ingestor.py#L113

Added line #L113 was not covered by tests

return (

Check warning on line 115 in django_project/gap/tasks/ingestor.py

View check run for this annotation

Codecov / codecov/patch

django_project/gap/tasks/ingestor.py#L115

Added line #L115 was not covered by tests
f"Logged ingestor failure for session {session_id} and notified admins"
)
Loading