From c4509fdb36ba4fe7c5150a9a22011db7b9a8df1e Mon Sep 17 00:00:00 2001 From: IonesioJunior Date: Tue, 10 Sep 2024 14:30:56 -0300 Subject: [PATCH 1/5] ADD new Failed Job Email Template - ADD new FailedJobEmailTemplate - Create a new notification when a Job fails --- .../service/notification/email_templates.py | 102 ++++++++++++++++++ packages/syft/src/syft/service/queue/queue.py | 25 +++++ 2 files changed, 127 insertions(+) diff --git a/packages/syft/src/syft/service/notification/email_templates.py b/packages/syft/src/syft/service/notification/email_templates.py index 2a17a662086..63fe5361ab7 100644 --- a/packages/syft/src/syft/service/notification/email_templates.py +++ b/packages/syft/src/syft/service/notification/email_templates.py @@ -23,6 +23,108 @@ def email_body(notification: "Notification", context: AuthedServiceContext) -> s return "" +@serializable(canonical_name="FailedJobTemplate", version=1) +class FailedJobTemplate(EmailTemplate): + @staticmethod + def email_title(notification: "Notification", context: AuthedServiceContext) -> str: + return "Job Failed Notification" + + @staticmethod + def email_body(notification: "Notification", context: AuthedServiceContext) -> str: + notification.linked_obj = cast(LinkedObject, notification.linked_obj) + queueitem_obj = notification.linked_obj.resolve_with_context( + context=context + ).unwrap() + + worker_pool_obj = queueitem_obj.worker_pool.resolve_with_context( + context=context + ).unwrap() + method = queueitem_obj.method + if queueitem_obj.service == "apiservice": + method = queueitem_obj.kwargs.pop("path", "") + queueitem_obj.kwargs.pop("log_id") + + head = """ + + + + Job Failed Notification + + + """ + body = f""" + +
+

Job Failed Notification

+

Hello,

+

We regret to inform you that your function job has encountered an + unexpected error and could not be completed successfully.

+ +
+

Job Details

+

Job ID: {queueitem_obj.job_id}

+

Worker Pool: {worker_pool_obj.name}

+

Method: {method}

+

Service: {queueitem_obj.service}

+

Arguments (args): {queueitem_obj.args}

+

Keyword Arguments (kwargs): {queueitem_obj.kwargs}

+
+ + + +
+ + """ + return f"""{head} {body}""" + + @serializable(canonical_name="PasswordResetTemplate", version=1) class PasswordResetTemplate(EmailTemplate): @staticmethod diff --git a/packages/syft/src/syft/service/queue/queue.py b/packages/syft/src/syft/service/queue/queue.py index da1ded8bd70..e6a6b479dc6 100644 --- a/packages/syft/src/syft/service/queue/queue.py +++ b/packages/syft/src/syft/service/queue/queue.py @@ -16,11 +16,17 @@ from ...server.worker_settings import WorkerSettings from ...service.context import AuthedServiceContext from ...store.document_store import NewBaseStash +from ...store.linked_obj import LinkedObject from ...types.datetime import DateTime from ...types.errors import SyftException from ...types.uid import UID from ..job.job_stash import Job from ..job.job_stash import JobStatus +from ..notification.email_templates import FailedJobTemplate +from ..notification.notification_service import CreateNotification +from ..notification.notification_service import NotificationService +from ..notifier.notifier_enums import NOTIFIERS +from ..queue.queue_service import QueueService from ..response import SyftError from ..response import SyftSuccess from ..worker.worker_stash import WorkerStash @@ -210,6 +216,25 @@ def handle_message_multiprocessing( status = Status.COMPLETED job_status = JobStatus.COMPLETED except Exception as e: + root_context = AuthedServiceContext( + server=context.server, + credentials=worker.signing_key.verify_key, # type: ignore + ) + link = LinkedObject.with_context( + queue_item, context=root_context, service_type=QueueService + ) + message = CreateNotification( + subject=f"Job {queue_item.job_id} failed!", + from_user_verify_key=worker.signing_key.verify_key, # type: ignore + to_user_verify_key=credentials, + linked_obj=link, + notifier_types=[NOTIFIERS.EMAIL], + email_template=FailedJobTemplate, + ) + + method = worker.get_service_method(NotificationService.send) + result = method(context=root_context, notification=message) + status = Status.ERRORED job_status = JobStatus.ERRORED logger.exception("Unhandled error in handle_message_multiprocessing") From 197960aec5535fc8265d4554bb0a4e44fa17e008 Mon Sep 17 00:00:00 2001 From: IonesioJunior Date: Tue, 10 Sep 2024 14:58:20 -0300 Subject: [PATCH 2/5] Add a small failed job email check in scenarios/bigquery notebook --- notebooks/scenarios/bigquery/02-configure-api.ipynb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/notebooks/scenarios/bigquery/02-configure-api.ipynb b/notebooks/scenarios/bigquery/02-configure-api.ipynb index 9f0051c141c..f864f9537e3 100644 --- a/notebooks/scenarios/bigquery/02-configure-api.ipynb +++ b/notebooks/scenarios/bigquery/02-configure-api.ipynb @@ -454,7 +454,10 @@ "metadata": {}, "outputs": [], "source": [ - "email_server.get_emails_for_user(user_email=ADMIN_EMAIL)" + "assert (\n", + " \"Job Failed\"\n", + " in email_server.get_emails_for_user(user_email=ADMIN_EMAIL)[0].email_content\n", + ")" ] }, { @@ -529,6 +532,11 @@ } ], "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, "language_info": { "codemirror_mode": { "name": "ipython", From c38b90e395be8721080e7a6a12d34f20dc97aacd Mon Sep 17 00:00:00 2001 From: IonesioJunior Date: Tue, 10 Sep 2024 15:04:00 -0300 Subject: [PATCH 3/5] Remove placeholder paragraph --- packages/syft/src/syft/service/notification/email_templates.py | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/syft/src/syft/service/notification/email_templates.py b/packages/syft/src/syft/service/notification/email_templates.py index c0118912930..2ebc0908a88 100644 --- a/packages/syft/src/syft/service/notification/email_templates.py +++ b/packages/syft/src/syft/service/notification/email_templates.py @@ -118,7 +118,6 @@ def email_body(notification: "Notification", context: AuthedServiceContext) -> s - """ From 9dc189d66e6fa84db2a4db1b7f2449a3d20e8ff6 Mon Sep 17 00:00:00 2001 From: IonesioJunior Date: Wed, 11 Sep 2024 08:33:16 -0300 Subject: [PATCH 4/5] Change the method used to retrieve a service method --- packages/syft/src/syft/service/queue/queue.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/syft/src/syft/service/queue/queue.py b/packages/syft/src/syft/service/queue/queue.py index a468035be9c..cd754eb7d37 100644 --- a/packages/syft/src/syft/service/queue/queue.py +++ b/packages/syft/src/syft/service/queue/queue.py @@ -239,8 +239,7 @@ def handle_message_multiprocessing( notifier_types=[NOTIFIERS.EMAIL], email_template=FailedJobTemplate, ) - - method = worker.get_service_method(NotificationService.send) + method = worker.services.notification.send result = method(context=root_context, notification=message) status = Status.ERRORED From f647e7195bef0e92f9b32d5e71a0f62c9c628716 Mon Sep 17 00:00:00 2001 From: IonesioJunior Date: Wed, 11 Sep 2024 08:35:43 -0300 Subject: [PATCH 5/5] Remove unused import --- packages/syft/src/syft/service/queue/queue.py | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/syft/src/syft/service/queue/queue.py b/packages/syft/src/syft/service/queue/queue.py index cd754eb7d37..ae170cad95b 100644 --- a/packages/syft/src/syft/service/queue/queue.py +++ b/packages/syft/src/syft/service/queue/queue.py @@ -25,7 +25,6 @@ from ..job.job_stash import JobStatus from ..notification.email_templates import FailedJobTemplate from ..notification.notification_service import CreateNotification -from ..notification.notification_service import NotificationService from ..notifier.notifier_enums import NOTIFIERS from ..queue.queue_service import QueueService from ..response import SyftError