12 Dagen van DigitalOcean (Dag 4) – Verjaardagsmeldingen implementeren met DigitalOcean Functies

Welkom bij Dag 4 van 12 Dagen van DigitalOcean! Gisteren hebben we Twilio SMS-notificaties toegevoegd aan onze Verjaardagsherinneringsdienst, waardoor het in staat is om sms-berichten te versturen voor de verjaardagen van vandaag. 🎂

Vandaag gaan we een stap verder door ons script te implementeren op DigitalOcean Functions. Dit stelt onze service in staat om in de cloud te draaien zonder de noodzaak van een toegewijde server, waardoor onze app lichtgewicht, schaalbaar en klaar voor automatisering is.

Met deze opzet ontvang je verjaardagsherinneringen, zelfs wanneer je computer uit staat of niet met internet is verbonden—geen noodzaak om het script handmatig op je machine uit te voeren. 🎉

Waarom DigitalOcean Functions?

Soms heb je gewoon een eenvoudig script nodig dat af en toe draait. Het beheren van infrastructuur voor iets dergelijks kan overdreven zijn. Daar komt Functions om de hoek kijken. Het is een serverless platform, wat betekent dat je code kunt implementeren die alleen draait wanneer dat nodig is, en je betaalt alleen voor wat je gebruikt. Perfect voor onze gebruikscase—het controleren van verjaardagen en dagelijks herinneringen versturen.

🚀 Wat Je Zult Leren

Aan het einde van vandaag weet je hoe je:

  1. De doctl CLI-tool van DigitalOcean instelt.
  2. Een serverless namespace (de manier waarop DigitalOcean functies georganiseerd houdt) aanmaakt en verbindt.
  3. Je Verjaardagsherinneringsdienst verpakt en implementeert naar DigitalOcean Functions.
  4. Je geïmplementeerde functie in de cloud test.

🛠 Wat Je Nodig Hebt

Voordat je begint, zorg ervoor dat je hebt:

🧑‍🍳 Recept voor Dag 4: Implementeren naar DigitalOcean Functions

Stap 1: Stel de doctl CLI in

Als je doctl al op je machine hebt ingesteld, kun je deze stap overslaan. Voor degenen die het moeten instellen, volg deze instructies:

Voordat we beginnen, laten we snel praten over doctl. Het is de officiële command-line interface tool van DigitalOcean waarmee je je cloudresources rechtstreeks vanuit je terminal kunt beheren. We zullen het gebruiken om een namespace (een map voor onze serverless functies) te maken, ons Python-script te implementeren en de functie te testen.

Het instellen is eenvoudig:

  1. Installeer doctl: Volg de installatiehandleiding voor jouw besturingssysteem.

  2. Authenticeer doctl: Verbind het met je DigitalOcean-account door het volgende uit te voeren:

    doctl auth init
    
  3. Controleer de installatie: Zorg ervoor dat alles werkt door het volgende uit te voeren:

    doctl account get
    

Als het succesvol is, zal deze opdracht details over uw DigitalOcean-account retourneren, zoals uw e-mailadres en account-ID.

Stap 2: Installeer de Serverless Software

DigitalOcean Functions vereist serverless ondersteuningssoftware, die u moet installeren. Dit is een eenmalige installatie, dus zodra het is geïnstalleerd, hoeft u het niet opnieuw te doen voor toekomstige projecten.

Voer de volgende opdracht uit:

doctl serverless install

U kunt de installatie-status controleren met:

doctl serverless status

Als u een fout ziet zoals:

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

Maak je geen zorgen—dat betekent gewoon dat we nog geen namespace hebben aangemaakt of verbonden. Dat zullen we in de volgende stap doen.

Stap 3: Maak een Namespace aan en Maak Verbinding

Namespaces zijn als mappen voor het organiseren van serverloze functies. Laten we er een maken voor onze Verjaardagsherinneringsdienst:

  1. Maak een nieuwe namespace:

    doctl serverless namespaces create --label "mijn-verjaardagsherinnering-namespace" --region "nyc1"
    

  2. Verbind met de namespace:

    doctl serverless connect mijn-verjaardags-herinnering-namespace
    

  3. Controleer de verbinding:

    doctl serverless status
    

Je zou nu een bevestiging moeten zien dat je verbonden bent met de namespace.

Pro Tip: Om een lijst van alle beschikbare namespaces te zien, gebruik je de volgende opdracht:

doctl serverless namespaces list

Dit kan handig zijn als je meerdere projecten beheert of als je de namespace wilt verifiëren die je zojuist hebt aangemaakt.

Stap 4: Initialiseer en Stel de Projectstructuur In

DigitalOcean Functions verwacht een specifieke projectstructuur voor serverless implementaties. Je kunt deze structuur opstarten met doctl serverless init, het handmatig aanmaken, of zelfs een starter repo klonen. Om het eenvoudig te houden, zullen we het opzetten met doctl serverless init:

  1. Voer de volgende opdracht uit om het project te initialiseren:

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

    Dit creëert een lokale projectdirectory genaamd my-birthday-reminder-service met de volgende standaardstructuur:

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

  2. Navigeer naar de projectdirectory:

    cd mijn-verjaardag-herinnerings-service
    
  3. Hernoem de mappen om aan onze gebruikscase te voldoen:

    mv pakketten/voorbeeld pakketten/herinneringen
    mv pakketten/herinneringen/hallo pakketten/herinneringen/verjaardagen
    mv pakketten/herinneringen/verjaardagen/hallo.py pakketten/herinneringen/verjaardagen/__main__.py
    
  4. Maak de benodigde bestanden aan:

    • Maak een leeg .env-bestand aan in de hoofdmap van het project:
    touch .env
    

    Dit bestand bevat je database- en Twilio-inloggegevens. Het bestand bevindt zich in de hoofdmap van de my-birthday-reminder-service map.

    • Maak een requirements.txt bestand aan in de birthdays map:
    touch packages/reminders/birthdays/requirements.txt
    

    Dit bestand bevat de Python-afhankelijkheden die nodig zijn voor je functie. Het bevindt zich onder packages/reminders/birthdays.

    • Maak een build.sh bestand aan in de birthdays map:
    touch packages/reminders/birthdays/build.sh
    chmod +x packages/reminders/birthdays/build.sh
    

    Het build.sh script is nodig voor het implementeren van functies met externe afhankelijkheden. De chmod opdracht zorgt ervoor dat het script uitvoerbaar is op Mac/Linux-systemen.

Bijgewerkte Structuur: Na het voltooien van deze stappen zou je projectstructuur er als volgt uit moeten zien:

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

Pro Tip: Als je per ongeluk een map verkeerd hebt genoemd, kun je de opdracht opnieuw uitvoeren of het handmatig hernoemen in je bestandsverkenner.

Stap 5: Bestanden Bijwerken

Nu de structuur klaar is, laten we deze vullen met de benodigde bestanden. Open de my-birthday-reminder-service directory in je favoriete code-editor

1. Werk project.yml bij

Het project.yml bestand is een configuratiebestand dat de structuur, omgevingsvariabelen en functies van je serverloze project definieert. Vervang de inhoud met:

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

Dit bestand stelt het reminders-pakket in en koppelt omgevingsvariabelen aan DigitalOcean Functions. Elke variabele komt overeen met de inloggegevens die nodig zijn voor je database en Twilio-integratie.

2. Werk je .env-bestand bij

Verwijs naar Dag 1: Een PostgreSQL-database instellen voor verjaardagsherinneringen voor de database-inloggegevens en Dag 3: Verjaardagen controleren en SMS-meldingen verzenden voor Twilio-inloggegevens om de volgende waarden in te vullen:

# Database-inloggegevens (van Dag 1)
DB_HOST=<your-database-hostname>
DB_NAME=<your-database-name>
DB_USER=<your-database-username>
DB_PASSWORD=<your-database-password>
DB_PORT=5432  # Standaard PostgreSQL-poort

# Twilio-inloggegevens (van Dag 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>

Opmerking: Het .env bestand wordt gebruikt om gevoelige inloggegevens veilig op te slaan. Deze waarden worden gelezen door je project.yml bestand en gekoppeld aan de serverless omgeving tijdens de implementatie, waardoor ze toegankelijk zijn voor je functie in de cloud.

3. Voeg afhankelijkheden toe

Werk het requirements.txt bestand bij met de volgende afhankelijkheden:

pg8000  
python-dotenv  
twilio  

pg8000: Een pure-Python PostgreSQL-clientbibliotheek.

python-dotenv: Gebruikt om omgevingsvariabelen te laden vanuit het .env bestand.

twilio: De Twilio Python-bibliotheek voor het verzenden van sms-berichten.

4. Werk build.sh

Voeg het volgende script toe aan het build.sh bestand:

#!/bin/bash
set -e

# Druk de huidige werkdirectory af voor debugging
echo "Current working directory: $(pwd)"

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

# Maak een virtuele omgeving aan
virtualenv --without-pip virtualenv

# Installeer afhankelijkheden vanuit requirements.txt
pip install -r requirements.txt --target virtualenv/lib/python3.9/site-packages

Dit script zorgt ervoor dat alle afhankelijkheden correct zijn verpakt met je functie. Het chmod +x commando uit Stap 4 zorgt ervoor dat het uitvoerbaar is.

5. Werk __main__.py bij

Dit is het hoofdschema voor je Verjaardagsherinneringsdienst. We gebruiken in wezen het script dat we op Dag 3 hebben gebouwd voor het verzenden van verjaardagsmeldingen. Om het echter compatibel te maken met DigitalOcean Functions, moeten we een paar kleine aanpassingen doen.

Werk het __main__.py bestand bij met de volgende inhoud:

# verjaardag_herinneringsdienst/__main__.py

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

# Laad omgevingsvariabelen
load_dotenv()

def main(params):
    """DigitalOcean Functions entry point."""
    try:
        # Maak verbinding met de 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()

        # Haal de maand en dag van vandaag op
        today = datetime.now()
        today_month = today.month
        today_day = today.day

        # Query om contacten te ophalen waarvan de verjaardag overeenkomt met de datum van vandaag
        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()

        # Meld voor elk overeenkomstig contact
        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.")

        # Sluit de cursor en verbinding
        cursor.close()
        connection.close()

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

Dit is wat we hebben veranderd:

  1. Een main(params) functie toegevoegd: DigitalOcean Functions verwacht een entry point functie genaamd main, die een params argument neemt. Dit is waar de functie begint met uitvoeren.

  2. De scriptlogica verplaatst naar de main functie:
    De code van Dag 3 is binnen de main functie gewikkeld om aan deze vereiste te voldoen.

  3. Alles blijft hetzelfde:
    De logica voor de databaseverbinding, verjaardagscontroles en de logica voor SMS-notificaties zijn onveranderd.

Stap 5: Pakket en Implementatie

Met alles op zijn plaats, implementeer je project naar DigitalOcean Functions:

  1. Implementeer het project:
doctl serverless deploy my-birthday-reminder-service

Om te verifiëren dat je functie succesvol is geïmplementeerd naar de namespace:

  1. Bezoek het DigitalOcean Control Panel en navigeer naar Functions in de linker zijbalk.
  2. Zoek je namespace (bijv. my-birthday-reminder-namespace).
  3. Controleer of je functie onder de namespace verschijnt, meestal vermeld als reminders/birthdays.
  4. Klik op de functienaam om details te bekijken, inclusief logs, configuratie en aanroepgeschiedenis.

Stap 6: Test je Geïmplementeerde Functie

Zodra je functie is geïmplementeerd, is het tijd om deze te testen. Je kunt de functie handmatig aanroepen om ervoor te zorgen dat deze werkt zoals verwacht. Er zijn twee manieren om dit te doen:

Optie 1: Gebruik de DigitalOcean CLI

doctl serverless functions invoke reminders/birthdays

Als alles correct is ingesteld, wordt je functie in de cloud uitgevoerd, waarbij deze de verjaardagen van vandaag controleert en SMS-meldingen verzendt.

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

Optie 2: Gebruik het DigitalOcean Dashboard

  1. Ga naar het DigitalOcean Control Panel.
  2. Navigeren naar Functies en zoek je herinneringen/verjaardagen functie.
  3. Klik op Uitvoeren om het handmatig uit te voeren.
  4. Bekijk de output en logs direct in de console.

Deze methode is vooral handig als je de voorkeur geeft aan een visuele interface of als je de logs in een schoon, gemakkelijk leesbaar formaat wilt controleren.

Testtips

Wanneer je de functie aanroept, controleert deze op verjaardagen die overeenkomen met de datum van vandaag. Als er een overeenkomst is, ontvang je een sms met de details. Om de functie effectief te testen:

  • Voeg een of meer verjaardagen toe in je database die overeenkomen met de huidige datum.
  • Controleer de console of CLI-logs om te bevestigen dat de functie succesvol is uitgevoerd.

🎁 Conclusie

Dit hebben we vandaag bereikt:

doctl ingesteld en een namespace voor ons project aangemaakt.
✅ Het Python-script herzien voor implementatie.
✅ De Verjaardagsherinneringsdienst verpakt en geïmplementeerd naar DigitalOcean Functions.
✅ De functie in de cloud getest met zowel de CLI als het DigitalOcean Dashboard.

Wat komt daarna: Hoewel dit een grote stap vooruit is, voeren we de functie nog steeds handmatig uit. In de volgende post zullen we dit proces automatiseren, zodat de Verjaardagsherinneringsdienst elke dag op een specifiek tijdstip automatisch draait. Stel je voor dat je wakker wordt met een sms-herinnering zonder een vinger te hoeven uitsteken—laten we dat morgen laten gebeuren! 🚀

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