12 Giorni di DigitalOcean (Giorno 4) – Distribuire Notifiche di Compleanno con le Funzioni di DigitalOcean

Benvenuti a Giorno 4 di 12 Giorni di DigitalOcean! Ieri, abbiamo aggiunto le notifiche SMS di Twilio al nostro Servizio di Promemoria per Compleanni, rendendolo in grado di inviare messaggi di testo per i compleanni di oggi. 🎂

Oggi, porteremo le cose al livello successivo distribuendo il nostro script su DigitalOcean Functions. Questo consente al nostro servizio di funzionare nel cloud senza la necessità di un server dedicato, rendendo la nostra app leggera, scalabile e pronta per l’automazione.

Con questa configurazione, riceverai promemoria per i compleanni anche quando il tuo computer è spento o non è connesso a Internet: non sarà più necessario eseguire lo script manualmente sul tuo dispositivo. 🎉

Perché DigitalOcean Functions?

A volte, tutto ciò di cui hai bisogno è uno script semplice che gira occasionalmente. Gestire l’infrastruttura per qualcosa del genere può essere eccessivo. È qui che entrano in gioco Functions. È una piattaforma serverless, il che significa che puoi distribuire codice che viene eseguito solo quando necessario, e paghi solo per ciò che usi. Perfetto per il nostro caso d’uso: controllare i compleanni e inviare promemoria quotidianamente.

🚀 Cosa Imparerai

Entro la fine di oggi, saprai come:

  1. Impostare doctl di DigitalOcean strumento CLI.
  2. Creare e connettersi a un namespace serverless (il modo di DigitalOcean per tenere organizzate le funzioni).
  3. Imballare e distribuire il tuo Servizio di Promemoria per Compleanni su DigitalOcean Functions.
  4. Testare la tua funzione distribuita nel cloud.

🛠 Cosa Ti Serve

Prima di iniziare, assicurati di avere:

🧑‍🍳 Ricetta per il Giorno 4: Distribuzione su DigitalOcean Functions

Passo 1: Configura il doctl CLI

Se hai già configurato doctl sul tuo computer, puoi saltare questo passaggio. Per chi deve configurarlo, segui queste istruzioni:

Prima di iniziare, parliamo brevemente di doctl. È lo strumento ufficiale della linea di comando di DigitalOcean che ti consente di gestire le tue risorse cloud direttamente dal tuo terminale. Lo utilizzeremo per creare uno spazio dei nomi (una cartella per le nostre funzioni serverless), distribuire il nostro script Python e testare la funzione.

La configurazione è semplice:

  1. Installa doctl: Segui la guida all’installazione per il tuo sistema operativo.

  2. Autenticare doctl: Collegalo al tuo account DigitalOcean eseguendo:

    doctl auth init
    
  3. Verifica l’installazione: Assicurati che tutto funzioni eseguendo:

    doctl account get
    

Se ha successo, questo comando restituirà dettagli sul tuo account DigitalOcean, come la tua email e l’ID dell’account.

Passo 2: Installa il Software Serverless

DigitalOcean Functions richiede software di supporto serverless, che dovrai installare. Questa è una configurazione una tantum, quindi una volta installato, non sarà necessario farlo di nuovo per progetti futuri.

Esegui il seguente comando:

doctl serverless install

Puoi controllare lo stato dell’installazione con:

doctl serverless status

Se vedi un errore come:

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

Non preoccuparti: significa solo che non abbiamo ancora creato o collegato uno spazio dei nomi. Ci occuperemo di questo nel passo successivo.

Passo 3: Crea e Connettiti a uno Spazio dei Nomi

I namespace sono come cartelle per organizzare le funzioni serverless. Creiamo uno per il nostro Servizio di Promemoria per Compleanni:

  1. Crea un nuovo namespace:

    doctl serverless namespaces create --label "my-birthday-reminder-namespace" --region "nyc1"
    

  2. Collegati al namespace:

    doctl serverless connect my-birthday-reminder-namespace
    

  3. Verifica la connessione:

    doctl serverless status
    

Ora dovresti vedere una conferma che sei connesso al namespace.

Consiglio Pro: Per vedere un elenco di tutti gli spazi dei nomi disponibili, utilizza il seguente comando:

doctl serverless namespaces list

Questo può essere utile se stai gestendo più progetti o vuoi verificare lo spazio dei nomi che hai appena creato.

Passo 4: Inizializza e Imposta la Struttura del Progetto

Le Funzioni di DigitalOcean si aspettano una struttura di progetto specifica per le distribuzioni senza server. Puoi avviare questa struttura usando doctl serverless init, crearla manualmente o persino clonare un repository di avvio. Per semplificare le cose, la imposteremo usando doctl serverless init:

  1. Esegui il seguente comando per inizializzare il progetto:

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

    Questo crea una directory di progetto locale chiamata my-birthday-reminder-service con la seguente struttura predefinita:

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

  2. Naviga nella directory del progetto:

    cd my-birthday-reminder-service
    
  3. Rinomina le cartelle per adattarle al nostro caso d’uso:

    mv packages/sample packages/reminders
    mv packages/reminders/hello packages/reminders/birthdays
    mv packages/reminders/birthdays/hello.py packages/reminders/birthdays/__main__.py
    
  4. Crea i file necessari:

    • Crea un file .env vuoto nella radice del progetto:
    touch .env
    

    Questo conterrà le tue credenziali per il database e Twilio. Il file si troverà nella radice della cartella my-birthday-reminder-service.

    • Crea un file requirements.txt nella cartella birthdays:
    touch packages/reminders/birthdays/requirements.txt
    

    Questo file elencherà le dipendenze Python necessarie per la tua funzione. Si troverà sotto packages/reminders/birthdays.

    • Crea un file build.sh nella cartella birthdays:
    touch packages/reminders/birthdays/build.sh
    chmod +x packages/reminders/birthdays/build.sh
    

    Lo script build.sh è necessario per il deployment di funzioni con dipendenze esterne. Il comando chmod assicura che lo script sia eseguibile su sistemi Mac/Linux.

Struttura Aggiornata: Dopo aver completato questi passaggi, la struttura del tuo progetto dovrebbe apparire così:

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

Consiglio da Pro: Se rinomini accidentalmente una cartella, puoi eseguire di nuovo il comando o rinominarla manualmente nel tuo esploratore di file.

Passo 5: Aggiorna i File

Ora che la struttura è in atto, popoliamola con i file necessari. Apri la directory my-birthday-reminder-service nel tuo editor di codice preferito.

1. Aggiorna project.yml

Il file project.yml è un file di configurazione che definisce la struttura, le variabili d’ambiente e le funzioni del tuo progetto serverless. Sostituisci il suo contenuto con:

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

Questo file configura il pacchetto dei promemoria e mappa le variabili d’ambiente alle Funzioni di DigitalOcean. Ogni variabile corrisponde alle credenziali necessarie per il tuo database e l’integrazione con Twilio.

2. Aggiorna il tuo file .env

Fai riferimento a Giorno 1: Configurazione di un Database PostgreSQL per Promemoria di Compleanno per le credenziali del database e Giorno 3: Controllo dei Compleanni e Invio di Notifiche SMS per le credenziali di Twilio per popolare i seguenti valori:

# Credenziali del database (da Giorno 1)
DB_HOST=<your-database-hostname>
DB_NAME=<your-database-name>
DB_USER=<your-database-username>
DB_PASSWORD=<your-database-password>
DB_PORT=5432  # Porta predefinita di PostgreSQL

# Credenziali di Twilio (da Giorno 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>

Nota: Il file .env è utilizzato per memorizzare in modo sicuro le credenziali sensibili. Questi valori saranno letti dal tuo file project.yml e mappati all’ambiente serverless durante il deployment, rendendoli accessibili alla tua funzione nel cloud.

3. Aggiungi Dipendenze

Aggiorna il file requirements.txt con le seguenti dipendenze:

pg8000  
python-dotenv  
twilio  

pg8000: Una libreria client PostgreSQL in puro Python.

python-dotenv: Utilizzato per caricare le variabili d’ambiente dal file .env.

twilio: La libreria Python di Twilio per l’invio di messaggi SMS.

4. Aggiorna build.sh

Aggiungi il seguente script al file build.sh:

#!/bin/bash
set -e

# Stampa la directory di lavoro corrente per il debug
echo "Current working directory: $(pwd)"

# Controlla se requirements.txt esiste
if [[ -f "requirements.txt" ]]; then
  echo "Found requirements.txt in $(pwd)"
else
  echo "Error: requirements.txt not found in $(pwd)"
  exit 1
fi

# Crea un ambiente virtuale
virtualenv --without-pip virtualenv

# Installa le dipendenze da requirements.txt
pip install -r requirements.txt --target virtualenv/lib/python3.9/site-packages

Questo script garantisce che tutte le dipendenze siano imballate correttamente con la tua funzione. Il comando chmod +x dal Passo 4 garantisce che sia eseguibile.

5. Aggiorna __main__.py

Questo è lo script principale per il tuo Servizio di Promemoria per Compleanni. Fondamentalmente stiamo usando lo script che abbiamo costruito nel Giorno 3 per inviare le notifiche di compleanno. Tuttavia, per renderlo compatibile con le Funzioni di DigitalOcean, dobbiamo apportare alcune piccole modifiche.

Aggiorna il file __main__.py con il seguente contenuto:

# servizio_promemoria_compleanno/__main__.py

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

# Carica le variabili d'ambiente
load_dotenv()

def main(params):
    """DigitalOcean Functions entry point."""
    try:
        # Connetti al database
        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()

        # Ottieni il mese e il giorno di oggi
        today = datetime.now()
        today_month = today.month
        today_day = today.day

        # Query per recuperare i contatti il cui compleanno corrisponde alla data di oggi
        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()

        # Notifica per ogni contatto corrispondente
        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.")

        # Chiudi il cursore e la connessione
        cursor.close()
        connection.close()

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

Ecco cosa abbiamo cambiato:

  1. Aggiunta una funzione main(params): DigitalOcean Functions si aspetta una funzione di entry point chiamata main, che accetta un argomento params. Qui è dove inizia l’esecuzione della funzione.

  2. Spostata la logica dello script all’interno della funzione main:
    Il codice del Giorno 3 è stato racchiuso all’interno della funzione main per allinearsi a questo requisito.

  3. Tutto il resto rimane invariato:
    La logica di connessione al database, i controlli di compleanno e la logica di notifica SMS non sono cambiati.

Passo 5: Imballa e Distribuisci

Con tutto in ordine, distribuisci il tuo progetto su DigitalOcean Functions:

  1. Distribuisci il progetto:
doctl serverless deploy my-birthday-reminder-service

Per verificare che la tua funzione sia stata distribuita con successo nello spazio dei nomi:

  1. Visita il Pannello di Controllo di DigitalOcean e vai su Functions nella barra laterale sinistra.
  2. Trova il tuo spazio dei nomi (ad esempio, my-birthday-reminder-namespace).
  3. Controlla che la tua funzione appaia sotto lo spazio dei nomi, tipicamente elencata come reminders/birthdays.
  4. Clicca sul nome della funzione per visualizzare i dettagli, inclusi log, configurazione e cronologia delle invocazioni.

Passo 6: Testa la Tua Funzione Distribuita

Una volta che la tua funzione è stata distribuita, è tempo di testarla. Puoi invocare la funzione manualmente per assicurarti che funzioni come previsto. Ci sono due modi per farlo:

Opzione 1: Utilizzare il CLI di DigitalOcean

doctl serverless functions invoke reminders/birthdays

Se tutto è configurato correttamente, la tua funzione verrà eseguita nel cloud, controllando i compleanni di oggi e inviando notifiche SMS.

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

Opzione 2: Utilizzare il Dashboard di DigitalOcean

  1. Vai al Pannello di Controllo di DigitalOcean.
  2. Naviga a Funzioni e individua la tua funzione di promemoria/compleanni.
  3. Clicca su Esegui per avviarla manualmente.
  4. Visualizza l’output e i log direttamente nella console.

Questo metodo è particolarmente utile se preferisci un’interfaccia visiva o vuoi controllare i log in un formato pulito e facile da leggere.

Consigli per il Test

Quando invochi la funzione, controllerà i compleanni che corrispondono alla data di oggi. Se c’è una corrispondenza, riceverai un messaggio di testo con i dettagli. Per testare efficacemente la funzione:

  • Aggiungi uno o più compleanni nel tuo database che corrispondono alla data attuale.
  • Controlla la console o i log del CLI per confermare che la funzione sia stata eseguita con successo.

🎁 Conclusione

Ecco cosa abbiamo realizzato oggi:

✅ Configurato doctl e creato uno spazio dei nomi per il nostro progetto.
✅ Rifattorizzato lo script Python per il deployment.
✅ Impacchettato e distribuito il Servizio di Promemoria Compleanni su DigitalOcean Functions.
✅ Testato la funzione nel cloud utilizzando sia il CLI che il Dashboard di DigitalOcean.

Prossimo: Anche se questo è un grande passo avanti, stiamo ancora eseguendo la funzione manualmente. Nel prossimo post, automatizzeremo questo processo affinché il Servizio di Promemoria Compleanni venga eseguito automaticamente ogni giorno a un’ora specifica. Immagina di svegliarti con un promemoria via testo senza muovere un dito—facciamo in modo che accada domani! 🚀

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