BDD für Alexa Skills – Teil 2: Lokale Lambda-Entwicklung

Keine Kommentare

Im ersten Teil dieser Blogreihe haben wir einen Alexa Skill und die dazugehörige Lambda-Funktion angelegt, die die Befehle des Skills verarbeitet.
Der nächste Schritt ist nun den Code für die Lambda in einer lokalen IDE zu bearbeiten und Änderungen dann in die Cloud zu deployen.

Lokales Git Repository anlegen

Zuerst einmal machen wir uns eine lokale Kopie der Lambda. Neben dem node_modules Verzeichnis (das erzeugen wir lokal) besteht diese momentan nur aus zwei Dateien: einer index.js mit dem JavaScript-Quellcode und einer package.json.
Wir legen uns lokal ein neues Verzeichnis für den Skill. In diesem Verzeichnis legen wir nun eine index.js Datei an (in die wir den Inhalt der index.js aus der Lambda kopieren) und eine package.json Datei (die mit dem Inhalt der package.json aus der Lambda befüllt wird.

Alternativ kann man auch eine Zip-Datei der Lambda (inkl. des node_module Verzeichnisses) herunterladen. Dafür im Header unter Aktionen den Eintrag “Exportfunktion” auswählen:
Screenshot: Export der Lambda Funktion als ZIP

Im folgenden Dialog wählen wir “Bereitstellungspaket herunterladen”:
Screenshot: Lambda Export als Bereitstellungspaket

Nun können wir die in der package.json definierten Pakete lokal installieren. Als Paketmanager nutzen wir yarn. Also können wir mit einem einfachen “yarn” die Abhängigkeiten installieren.
Jetzt ist auch Zeit dafür unser lokales git Repository anzulegen (und ggf. eine lokale .gitignore damit die node-module nicht im Repo landen).

Upload der Dateien mit der aws-cli

Den Upload von lokalen Änderungen zur AWS Cloud führen wir mit der AWS CLI durch. Die AWS CLI ist eine Commandline-Schnittstelle, die es unter anderem erlaubt den Code einer Lambda-Funktion zu aktualisieren. Hier habe ich viel Zeit verloren: Ich bin einem veralteten Tutorial aufgesessen und habe versucht die CLI über npm zu installieren. Die aktuelle Installation erfolgt aber über den Python-Paketmanager PIP. Schaut also einfach auf die AWS-CLI-Seite und befolgt die dortigen Installationsanweisungen.

Einen Benutzer für die CLI anlegen

Damit die CLI erfolgreich die Lambda aktualisieren kann, muss man ihr erst die notwendige Berechtigung erteilen. Dazu legt ihr zunächst im AWS Identity and Access Management (IAM) einen Benutzer an, der für den Upload verwendet wird.
Meldet euch beim IAM an und wählt in der linken Navigation den Eintrag “Benutzer”. Im folgenden Bildschirm den Eintrag “Benutzer hinzufügen” auswählen.

Gebt dem Benutzer einen sprechenden Namen und wählt als Zugrifftyp “Programmgesteuerter Zugriff.
Screenshot: Anlegen eines Benutzers für die AWS CLI in der IAM Console

Im nächsten Schritt müsst ihr die Berechtigungen auswählen. Ich habe hier die vorhandene Richtlinie “AWSLambdaFullAccess” verwendet:

Screenshot: Festlegen der Berechtigung des neuen Benutzers

Überspringt die Tags und erstellt im letzten Bildschirm des Wizards den Benutzer. Wenn der Benutzer angelegt wurde, erhaltet ihr im folgenden Bildschirm die Zugangsdaten des Benutzers die wir für die CLI benötigen. Am besten ladet ihr euch diese als CSV-Datei herunter und speichert sie lokal an einem sicheren Ort ab.

Screenshot: Herunterladen der Zugangsdaten des neuen Benutzers als CSV Datei

Die CLI konfigurieren

Jetzt könnt ihr die CLI konfigurieren. Geht dazu in eure Shell und führt den Befehl:
aws configure
aus. Nun werdet ihr nach der Access Key ID und dem Secret Access Key gefragt. Hier verwendet ihr die Zugangsdaten des soeben angelegten Benutzers. Als Default-Region müsst ihr Lambdas in Irland die Region “eu-west-1” angeben.

Der erste Upload

Jetzt sind wir schon fast soweit, die Lambda zum ersten Mal von der Commandline zu aktualisieren. Der Upload selbst erfolgt in Form eines ZIP-Archivs. Momentan hat unser Projekt folgende Struktur:

  • index.js
  • package.json
  • node_modules/

Diese Struktur wird nun gezippt, z.B. aus der Shell mit

zip -r fuenferpasch.zip index.js package.json node_modules/

Anschließend können wir dieses ZIP mit der CLI in die AWS Cloud hochladen. Dafür benötigen wir aber noch einmal die ID unserer Lambda-Funktion. Diese haben wir bereits im ersten Teil dieser Artikelserie verwendet um den Alexa Skill mit der Lambda zu verknüpfen.

aws lambda update-function-code --function-name  --zip-file fileb://./fuenferpasch.zip"

Im Erfolgsfall wird euch dies durch eine JSON-Ausgabe auf der Commandline quittiert.

Es bietet sich an, diese beiden Befehle (die Erstellung des ZIP-Archivs und das Upload desselbigen) in einem Script zusammenzufassen und in der package.json zu hinterlegen. So reicht später ein einfacher Aufruf von

yarn upload

um die Lambda in der Cloud zu aktualisieren.
Die aktualisierte package.json sieht somit so aus:

{
    "name": "Fuenferpasch",
    "version": "0.0.1",
    "description": "Blogartikel Demo Skill",
    "main": "index.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "upload": "zip -r fuenferpasch.zip index.js package.json node_modules/ && aws lambda update-function-code --function-name  --zip-file fileb://./fuenferpasch.zip"
    },
    "keywords": [
        "alexa",
        "skill",
        "demo"
    ],
    "author": "codecentric.de",
    "dependencies": {
        "ask-sdk": "^2.0.0"
    }
}

Ausblick

Mit diesem Stand können wir nun unsere Lambda lokal entwickeln und in der Cloud aktualisieren. Das ist nett, man merkt aber auch relativ schnell, dass die Turn-Around-Zeiten in der Entwicklung viel zu hoch sind. Gerade am Anfang passieren einem noch häufiger Fehler, wenn man sich mit der neuen API vertraut machen muss. Ein neuer Intent wird im Voice-Model angelegt, ein passender Handler geschrieben, der Code gezippt und hochgeladen, der Alexa Simulator geöffnet, der Skill gestartet, der Satz zum Auslösen des Intents eingegeben und … es kommt die Antwort “Bei der Ausführung des angeforderten Skills ist ein Problem aufgetreten”. Zum Glück gibt es in solchen Fällen die Log-Ausgaben in der Cloud Watch Management Console. Also sucht man in den Logs, ergänzt Logausgaben um schließlich festzustellen, dass man vergessen hat den neuen Intent im Skill zu registrieren. Oder man hatte einen einfachen Tippfehler. Das ist alles schnell passiert, kann auch einfach behoben werden, aber die Zeitspanne zum Auffinden dieser Fehler ist viel zu hoch.
Spätestens an diesem Punkt hatte ich mich davon verabschiedet, auf Tests verzichten zu wollen. Im nächsten Beitrag dieser Artikelserie schauen wir uns dann an, wie wir das bisherige Projekt um Unit-Tests, Linting und Transpiling ergänzen (um auch neue JavaScript Features wie async / await nutzen zu können).

Stefan Spittank

Stefan ist seit 2016 für die codecentric AG am Standort Solingen tätig.
Anwendungen nutzbar zu machen und eine gute „User Experience“ zu erreichen ist sein täglich Brot. Dabei helfen ihm auch seine langjährigen Erfahrungen als Verantwortlicher für User Interfaces in der IT-Branche.

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.