12 Jours de DigitalOcean (Jour 4) – Déploiement des Notifications d’Anniversaire avec les Fonctions DigitalOcean

Bienvenue au Jour 4 de 12 Jours de DigitalOcean ! Hier, nous avons ajouté des notifications SMS Twilio à notre Service de Rappel d’Anniversaire, le rendant capable d’envoyer des messages texte pour les anniversaires d’aujourd’hui. 🎂

Aujourd’hui, nous allons passer à la vitesse supérieure en déployant notre script sur DigitalOcean Functions. Cela permet à notre service de fonctionner dans le cloud sans avoir besoin d’un serveur dédié, rendant notre application légère, évolutive et prête pour l’automatisation.

Avec cette configuration, vous recevrez des rappels d’anniversaire même lorsque votre ordinateur est éteint ou non connecté à Internet — plus besoin d’exécuter le script manuellement sur votre machine. 🎉

Pourquoi DigitalOcean Functions ?

Parfois, tout ce dont vous avez besoin est un simple script qui s’exécute occasionnellement. Gérer l’infrastructure pour quelque chose comme ça peut être excessif. C’est là que Functions entre en jeu. C’est une plateforme sans serveur, ce qui signifie que vous pouvez déployer du code qui s’exécute uniquement lorsque cela est nécessaire, et vous ne payez que pour ce que vous utilisez. Parfait pour notre cas d’utilisation : vérifier les anniversaires et envoyer des rappels chaque jour.

🚀 Ce que vous apprendrez

À la fin de la journée, vous saurez comment :

  1. Configurer l’outil doctl CLI de DigitalOcean.
  2. Créer et se connecter à un namespace sans serveur (la façon de DigitalOcean de garder les fonctions organisées).
  3. Emballer et déployer votre service de rappel d’anniversaire sur DigitalOcean Functions.
  4. Tester votre fonction déployée dans le cloud.

🛠 Ce dont vous aurez besoin

Avant de commencer, assurez-vous d’avoir :

🧑‍🍳 Recette pour le Jour 4 : Déploiement sur DigitalOcean Functions

Étape 1 : Configurer le CLI doctl

Si vous avez déjà configuré doctl sur votre machine, vous pouvez sauter cette étape. Pour ceux qui doivent le configurer, suivez ces instructions :

Avant de commencer, parlons rapidement de doctl. C’est l’outil officiel d’interface en ligne de commande de DigitalOcean qui vous permet de gérer vos ressources cloud directement depuis votre terminal. Nous l’utiliserons pour créer un espace de noms (un dossier pour nos fonctions sans serveur), déployer notre script Python et tester la fonction.

La configuration est simple :

  1. Installez doctl : Suivez le guide d’installation pour votre système d’exploitation.

  2. Authentifiez doctl : Connectez-le à votre compte DigitalOcean en exécutant :

    doctl auth init
    
  3. Vérifiez l’installation : Assurez-vous que tout fonctionne en exécutant :

    doctl account get
    

Si cela réussit, cette commande renverra des détails sur votre compte DigitalOcean, comme votre email et votre identifiant de compte.

Étape 2 : Installer le logiciel Serverless

DigitalOcean Functions nécessite un logiciel de support serverless, que vous devrez installer. C’est une configuration unique, donc une fois installé, vous n’aurez plus besoin de le faire pour les projets futurs.

Exécutez la commande suivante :

doctl serverless install

Vous pouvez vérifier l’état de l’installation avec :

doctl serverless status

Si vous voyez une erreur comme :

Error: serverless support is installed but not connected to a functions namespace

Ne vous inquiétez pas, cela signifie simplement que nous n’avons pas encore créé ou connecté à un espace de noms. Nous allons nous en occuper à l’étape suivante.

Étape 3 : Créer et se connecter à un espace de noms

Les espaces de noms sont comme des dossiers pour organiser les fonctions sans serveur. Créons-en un pour notre Service de Rappel d’Anniversaire :

  1. Créer un nouvel espace de noms :

    doctl serverless namespaces create --label "mon-espace-de-noms-rappel-anniversaire" --region "nyc1"
    

  2. Se connecter à l’espace de noms :

    doctl serverless connect mon-rappel-d'anniversaire-namespace
    

  3. Vérifier la connexion :

    doctl serverless status
    

Vous devriez maintenant voir une confirmation que vous êtes connecté à l’espace de noms.

Conseil Pro : Pour voir une liste de tous les espaces de noms disponibles, utilisez la commande suivante :

doctl serverless namespaces list

Cela peut être utile si vous gérez plusieurs projets ou si vous souhaitez vérifier l’espace de noms que vous venez de créer.

Étape 4 : Initialiser et configurer la structure du projet

Les Fonctions DigitalOcean attendent une structure de projet spécifique pour les déploiements sans serveur. Vous pouvez démarrer cette structure en utilisant doctl serverless init, la créer manuellement ou même cloner un dépôt de démarrage. Pour garder les choses simples, nous allons la configurer en utilisant doctl serverless init :

  1. Exécutez la commande suivante pour initialiser le projet:

    doctl serverless init --language python birthday-reminder-service
    

    Cela crée un répertoire de projet local nommé my-birthday-reminder-service avec la structure par défaut suivante :

    my-birthday-reminder-service/
    ├── packages
    │   └── sample
    │       └── hello
    │           └── hello.py
    └── project.yml
    

  2. Accédez au répertoire du projet:

    cd mon-rappel-d'anniversaire-service
    
  3. Renommez les dossiers pour correspondre à notre cas d’utilisation:

    mv packages/exemple packages/rappels
    mv packages/rappels/bonjour packages/rappels/anniversaires
    mv packages/rappels/anniversaires/bonjour.py packages/rappels/anniversaires/__main__.py
    
  4. Créer les fichiers nécessaires:

    • Créer un fichier .env vide à la racine du projet :
    touch .env
    

    Cela contiendra vos identifiants de base de données et Twilio. Le fichier sera situé à la racine du dossier my-birthday-reminder-service.

    • Créer un fichier requirements.txt dans le dossier birthdays :
    touch packages/reminders/birthdays/requirements.txt
    

    Ce fichier listera les dépendances Python nécessaires pour votre fonction. Il sera situé sous packages/reminders/birthdays.

    • Créer un fichier build.sh dans le dossier birthdays :
    touch packages/reminders/birthdays/build.sh
    chmod +x packages/reminders/birthdays/build.sh
    

    Le script build.sh est nécessaire pour déployer des fonctions avec des dépendances externes. La commande chmod garantit que le script est exécutable sur les systèmes Mac/Linux.

Structure mise à jour : Après avoir complété ces étapes, la structure de votre projet devrait ressembler à ceci :

my-birthday-reminder-service/
├── project.yml
├── .env
├── packages
│   └── reminders
│       └── birthdays
│           ├── __main__.py
│           ├── requirements.txt
│           ├── build.sh
├── .gitignore

Astuce Pro : Si vous renommez accidentellement un dossier, vous pouvez exécuter à nouveau la commande ou le renommer manuellement dans votre explorateur de fichiers.

Étape 5 : Mettre à jour les fichiers

Maintenant que la structure est en place, remplissons-la avec les fichiers nécessaires. Ouvrez le répertoire my-birthday-reminder-service dans votre éditeur de code préféré.

1. Mettez à jour project.yml

Le fichier project.yml est un fichier de configuration qui définit la structure de votre projet sans serveur, les variables d’environnement et les fonctions. Remplacez son contenu par :

packages:
  - name: reminders
    shared: false
    environment:
      DO_DB_NAME: "${DB_NAME}"
      DO_DB_USER: "${DB_USER}"
      DO_DB_PASSWORD: "${DB_PASSWORD}"
      DO_DB_HOST: "${DB_HOST}"
      DO_DB_PORT: "${DB_PORT}"
      TWILIO_ACCOUNT_SID: "${TWILIO_ACCOUNT_SID}"
      TWILIO_AUTH_TOKEN: "${TWILIO_AUTH_TOKEN}"
      TWILIO_PHONE_FROM: "${TWILIO_PHONE_FROM}"
      TWILIO_PHONE_TO: "${TWILIO_PHONE_TO}"
    functions:
      - name: birthdays
        runtime: python:default

Ce fichier configure le package de rappels et associe les variables d’environnement aux fonctions DigitalOcean. Chaque variable correspond aux identifiants nécessaires pour votre base de données et l’intégration Twilio.

2. Mettez à jour votre fichier .env

Reportez-vous à Jour 1 : Configuration d’une base de données PostgreSQL pour les rappels d’anniversaire pour les identifiants de la base de données et Jour 3 : Vérification des anniversaires et envoi de notifications SMS pour les identifiants Twilio afin de remplir les valeurs suivantes :

# Identifiants de la base de données (du Jour 1)
DB_HOST=<your-database-hostname>
DB_NAME=<your-database-name>
DB_USER=<your-database-username>
DB_PASSWORD=<your-database-password>
DB_PORT=5432  # Port PostgreSQL par défaut

# Identifiants Twilio (du Jour 3)
TWILIO_ACCOUNT_SID=<your-twilio-account-sid>
TWILIO_AUTH_TOKEN=<your-twilio-auth-token>
TWILIO_PHONE_FROM=<your-twilio-phone-number>
TWILIO_PHONE_TO=<your-personal-phone-number>

Remarque : Le fichier .env est utilisé pour stocker en toute sécurité des identifiants sensibles. Ces valeurs seront lues par votre fichier project.yml et mappées à l’environnement serverless lors du déploiement, les rendant accessibles à votre fonction dans le cloud.

3. Ajouter des dépendances

Mettez à jour le fichier requirements.txt avec les dépendances suivantes :

pg8000  
python-dotenv  
twilio  

pg8000 : Une bibliothèque cliente PostgreSQL purement Python.

python-dotenv : Utilisé pour charger des variables d’environnement à partir du fichier .env.

twilio : La bibliothèque Python Twilio pour envoyer des SMS.

4. Mettre à jour build.sh

Ajoutez le script suivant au fichier build.sh :

#!/bin/bash
set -e

# Afficher le répertoire de travail actuel pour le débogage
echo "Current working directory: $(pwd)"

# Vérifier si requirements.txt existe
if [[ -f "requirements.txt" ]]; then
  echo "Found requirements.txt in $(pwd)"
else
  echo "Error: requirements.txt not found in $(pwd)"
  exit 1
fi

# Créer un environnement virtuel
virtualenv --without-pip virtualenv

# Installer les dépendances à partir de requirements.txt
pip install -r requirements.txt --target virtualenv/lib/python3.9/site-packages

Ce script garantit que toutes les dépendances sont correctement emballées avec votre fonction. La commande chmod +x de l’étape 4 garantit qu’elle est exécutable.

5. Mettre à jour __main__.py

Ceci est le script principal pour votre service de rappel d’anniversaire. Nous utilisons essentiellement le script que nous avons construit au jour 3 pour envoyer des notifications d’anniversaire. Cependant, pour le rendre compatible avec les fonctions DigitalOcean, nous devons apporter quelques petits ajustements.

Mettre à jour le fichier __main__.py avec le contenu suivant :

# birthday_reminder_service/__main__.py

from datetime import datetime
import pg8000
from dotenv import load_dotenv
from twilio.rest import Client
import os

# Charger les variables d'environnement
load_dotenv()

def main(params):
    """DigitalOcean Functions entry point."""
    try:
        # Se connecter à la base de données
        connection = pg8000.connect(
            host=os.getenv("DO_DB_HOST"),
            database=os.getenv("DO_DB_NAME"),
            user=os.getenv("DO_DB_USER"),
            password=os.getenv("DO_DB_PASSWORD"),
            port=int(os.getenv("DO_DB_PORT"))
        )
        cursor = connection.cursor()

        # Obtenir le mois et le jour d'aujourd'hui
        today = datetime.now()
        today_month = today.month
        today_day = today.day

        # Requête pour récupérer les contacts dont l'anniversaire correspond à la date d'aujourd'hui
        cursor.execute(
            """
            SELECT first_name, last_name, birthday
            FROM contacts
            WHERE EXTRACT(MONTH FROM birthday) = %s
              AND EXTRACT(DAY FROM birthday) = %s;
            """,
            (today_month, today_day)
        )
        rows = cursor.fetchall()

        # Notifier pour chaque contact correspondant
        if rows:
            account_sid = os.getenv("TWILIO_ACCOUNT_SID")
            auth_token = os.getenv("TWILIO_AUTH_TOKEN")
            client = Client(account_sid, auth_token)

            for row in rows:
                first_name, last_name, _ = row
                message = client.messages.create(
                    body=f"🎉 It's {first_name} {last_name or ''}'s birthday today! 🎂",
                    from_=os.getenv("TWILIO_PHONE_FROM"),
                    to=os.getenv("TWILIO_PHONE_TO")
                )
                print(f"Message sent for {first_name} {last_name}. Message SID: {message.sid}")
        else:
            print("No birthdays today.")

        # Fermer le curseur et la connexion
        cursor.close()
        connection.close()

    except Exception as e:
        print(f"An error occurred: {e}")

Voici ce que nous avons changé:

  1. Ajout d’une fonction main(params): Les Fonctions DigitalOcean attendent une fonction de point d’entrée nommée main, prenant un argument params. C’est ici que la fonction démarre son exécution.

  2. Déplacé la logique du script à l’intérieur de la fonction main:
    Le code du Jour 3 a été intégré à l’intérieur de la fonction main pour répondre à cette exigence.

  3. Tout le reste reste le même :
    La logique de connexion à la base de données, les vérifications d’anniversaire et la logique de notification SMS n’ont pas changé.

Étape 5 : Emballez et déployez

Avec tout en place, déployez votre projet sur DigitalOcean Functions :

  1. Déployez le projet :
doctl serverless deploy my-birthday-reminder-service

Pour vérifier que votre fonction a été déployée avec succès dans l’espace de noms :

  1. Visitez le panneau de contrôle DigitalOcean et naviguez vers Functions dans la barre latérale gauche.
  2. Trouvez votre espace de noms (par exemple, my-birthday-reminder-namespace).
  3. Vérifiez que votre fonction apparaît sous l’espace de noms, généralement listée comme reminders/birthdays.
  4. Cliquez sur le nom de la fonction pour voir les détails, y compris les journaux, la configuration et l’historique des invocations.

Étape 6 : Testez votre fonction déployée

Une fois votre fonction déployée, il est temps de la tester. Vous pouvez invoquer la fonction manuellement pour vous assurer qu’elle fonctionne comme prévu. Il y a deux façons de le faire :

Option 1 : Utilisation de la CLI de DigitalOcean

doctl serverless functions invoke reminders/birthdays

Si tout est correctement configuré, votre fonction s’exécutera dans le cloud, vérifiant les anniversaires du jour et envoyant des notifications par SMS.

![https://doimages.nyc3.cdn.digitaloceanspaces.com/006Community/12-Days-of-DO/Postgressql-birthday/birthday_reminder_service_text_message.jpeg]

Option 2 : Utilisation du tableau de bord DigitalOcean

  1. Accédez au panneau de contrôle de DigitalOcean.
  2. Naviguez vers Fonctions et localisez votre fonction de rappels/anniversaires.
  3. Cliquez sur Exécuter pour l’exécuter manuellement.
  4. Visualisez la sortie et les journaux directement dans la console.

Cette méthode est particulièrement utile si vous préférez une interface visuelle ou si vous souhaitez vérifier les journaux dans un format propre et facile à lire.

Conseils de test

Lorsque vous invoquez la fonction, elle vérifiera les anniversaires correspondant à la date d’aujourd’hui. S’il y a une correspondance, vous recevrez un message texte avec les détails. Pour tester la fonction efficacement :

  • Ajoutez un ou plusieurs anniversaires dans votre base de données qui correspondent à la date actuelle.
  • Vérifiez la console ou les journaux CLI pour confirmer que la fonction a été exécutée avec succès.

🎁 Conclusion

Voici ce que nous avons accompli aujourd’hui :

✅ Configuration de doctl et création d’un espace de noms pour notre projet.
✅ Refactorisation du script Python pour le déploiement.
✅ Emballage et déploiement du service de rappel d’anniversaire sur DigitalOcean Functions.
✅ Test de la fonction dans le cloud en utilisant à la fois le CLI et le tableau de bord DigitalOcean.

À venir : Bien que cela soit un grand pas en avant, nous exécutons toujours la fonction manuellement. Dans le prochain article, nous automatiserons ce processus afin que le service de rappel d’anniversaire fonctionne automatiquement chaque jour à une heure précise. Imaginez-vous vous réveiller avec un rappel par texto sans lever le petit doigt—faisons que cela se produise demain ! 🚀

Source:
https://www.digitalocean.com/community/tutorials/deploying-birthday-notifications-with-digitalocean-functions