How to send push notifications from a Lambda function

In this article, I’ll show you a simple and efficient way to send push notifications using AWS Lambda and ntfy.

To illustrate that, we will create a Lambda function that sends a notification every time a SageMaker notebook is left running for too long (which happens more often than I would like to admit 😅).

There are several methods for sending notifications to mobile devices. For enterprise-level applications, I would typically opt for an integration using AWS SNS, along with either an application-to-person or application-to-application solution. However, since I’m implementing this for my personal AWS account, I’ve chosen a simpler solution: ntfy.

ntfy

ntfy (pronounced notify) is a free and versatile notification service that enables you to send notifications to various devices via a REST API.

To consume the notifications, ntfy offers a mobile app for both Android and iOS, desktop applications, and a web app accessible at https://ntfy.sh/app (no login required 😉).

What I personally liked about ntfy is its simplicity. There’s no need to create an account or to learn obscure APIs. Simply visit their website, pick a topic name, subscribe to it from a client, and you are ready to start sending notifications via post requests.

How to use ntfy

To start, choose a client application - in my case, I installed the iOS app. Next, subscribe to a specific topic; for this example, I used blogpostdemo. Once your client application is set up, you can start sending push notifications using POST requests. The examples below demonstrate how to send these requests using curl and Python.

curl:

curl -d "Any message you want 😀" ntfy.sh/blogpostdemo

Python:

from urllib import request

data = "Any message you want 😀".encode('utf-8')
req = request.Request("https://ntfy.sh/blogpostdemo", data=data)
request.urlopen(req) # Sends the request

All topics are public, consider a complex name to avoid conflicts. Or self-host ntfy.

After sending the post request, you should receive a notification like the one below.

Push notification triggered by ntfy.

You can also add other types of media to your notification such as images, icons and other attachments. The maximum size for any attachment is 15MB. You can find more detailed information here.

Architecture

The architecture is quite straightforward. A Lambda function is triggered by EventBridge every hour and checks for any SageMaker notebooks running for more than three hours. These time values can be adjusted as needed. If a long-running notebook is detected, the Lambda function sends a notification to a ntfy topic. ntfy then pushes this notification to the client applications.

The architecture diagram for the integration using AWS Lambda and ntfy.

Implementation

Lambda function

For the runtime, I’ll be using Python 3.12, but other recent versions should be compatible too. This implementation doesn’t require any additional modules beyond the standard Python library. You can see the full code for the lambda in the section below.

from urllib import request
import boto3
from datetime import timedelta, datetime, timezone

sagemaker_client = boto3.client("sagemaker")


def lambda_handler(event, context):
    hours_delta = 3
    topic_name = "savemaker"
    current_time = datetime.now()

    # Define the time delta of X hours.
    x_hs_ago = current_time - timedelta(hours=hours_delta)

    # Iterate over all notebooks and filter the ones running longer than 3 hours
    n_long_running_instances = 0

    for nb in sagemaker_client.list_notebook_instances()["NotebookInstances"]:
        nb_in_service = nb["NotebookInstanceStatus"] == "InService"
        nb_running_too_long = nb["LastModifiedTime"].replace(tzinfo=None) < x_hs_ago

        if nb_in_service and nb_running_too_long:
            n_long_running_instances += 1

    if n_long_running_instances:
        message = f"You have {n_long_running_instances} instance(s) running 💸"

        # Prepare the request
        req = request.Request(
            f"https://ntfy.sh/{topic_name}",
            headers={"Title": "SaveMaker"},
            data=message.encode("utf-8"),
        )

        # Send the request
        request.urlopen(req)

It is important to make sure the IAM (Identity and Access Management) role used by the lambda function can list and describe the SageMaker notebooks. To allow this, I added the following permissions to the lambda’s IAM role.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "SageMakerNotebookInstanceReadOnlyAccess",
      "Effect": "Allow",
      "Action": [
          "sagemaker:ListNotebookInstances",
          "sagemaker:DescribeNotebookInstance"
      ],
      "Resource": "*"
    }
  ]
}

EventBridge rule to trigger the lambda

The final step is to set up an EventBridge rule in AWS to schedule your Lambda function. First, go to the AWS EventBridge console and create a new rule. In the Event Source section, choose Schedule. I configured my rule to trigger every hour using the following cron expression 0 * * * ? *, which means at the start of every hour.

Next, in the Targets section, select Lambda function and choose the Lambda function you created earlier. You can find the official documentation for this setup here. The image below illustrates how the review page should look like.

Click here to see the image.
EventBridge rule configuration.


Testing

To test the integration, I created a SageMaker notebook and left it running for more than 3 hours. After that, I received the following notification on my phone.

Push notification triggered by ntfy.

Note that the notification title is set to SaveMaker. That was set using the Title header in the request. You can find instructions on how the different headers work here.

Conclusion and considerations

In this post, we explored how to send push notifications using ntfy from an AWS Lambda function. We delved into the integration of this setup with AWS SageMaker, specifically focusing on setting up alerts for notebooks that are running for too long.

An important consideration is the risk associated with using the free version of ntfy for sensitive information, as any user can subscribe to a topic and receive the notifications. For transmitting sensitive data, consider the self-hosted version of ntfy, which offers more privacy and control. Or maybe another services such as Amazon SNS for scalable messaging, Amazon Pinpoint for customer engagement or Amazon SES for email sending.

I hope you enjoyed this post. See you in the next one 👋.