W zeszłym tygodniu zacząłem opisywać serverless w google a dokładnie cloud functions i co trzeba zrobić by wystartować z projektem/funkcją. Dziś zaś skoncentruje się nad tym jak taką funkcję możemy testować i debugować lokalnie.
Prawie jak Azure (prawie robi różnicę), google udostępnia emulator lokalny funkcji. Pisząc google udostępnia już pewnie naginam prawdę, bo google twierdzi, że to nie jest oficjalny produkt googla, ale jest copyright by Google Inc……. Nigdy takich spraw nie pojmę. Do tego, Azure może działać on premise, zaś google nie. Więc stąd to jest emulator, gdzie w Azure może to być po prostu implementacja serwera funkcji.
Instalacja emulatora
Ale dobra. Co potrzebujemy do tego by się tym wszystkim pobawić? Jedynie NPM albo Yarn (przydałoby się by to w końcu opisać). Dodatkowo albo VS Code albo Google Chrome.
Jeżeli mamy npm to możemy odpalić komendę:
npm install -g @google-cloud/functions-emulator
Jeżeli zaś yarn to:
yarn global add @google-cloud/functions-emulator
Choć u mnie yarn nie zadziałał, dostałem wyjątkiem prosto w oczy:
> yarn global add @google-cloud/functions-emulator yarn global v0.19.1 [1/4] Resolving packages... warning @google-cloud/functions-emulator > @google-cloud/storage > gcs-resumable-upload > google-auto-auth > gcp-metadata > retry-request > request > [email protected]: Use uuid module instead [2/4] Fetching packages... [3/4] Linking dependencies... [4/4] Building fresh packages... ⠁ ⠁ ⠁ ⠁ error C:\Users\Gutek\AppData\Local\Yarn\config\global\node_modules\grpc: Command failed. Exit code: 1 Command: C:\WINDOWS\system32\cmd.exe Arguments: /d /s /c ./node_modules/.bin/node-pre-gyp install --fallback-to-build --library=static_library Directory: C:\Users\Gutek\AppData\Local\Yarn\config\global\node_modules\grpc Output: '.' is not recognized as an internal or external command, operable program or batch file. info Visit https://yarnpkg.com/en/docs/cli/global for documentation about this command.
Może to wina windows, nie wiem.
Operacje/konfiguracja
Po instalacji powinniśmy mieć dostępne polecenie functions – polecenie to będzie nam pomagało w deployowaniu jak i debugowaniu naszej testowej funkcji. Możemy się dużo o nim dowiedzieć pisząc:
functions --help
Ogólnie, zasada:
functions COMMAND --help
tutaj działa i to bardzo dobrze.
Ale z jednych takich prostych rzeczy to możemy dowiedzieć się jaka jest konfiguracja naszego systemu za pomocą polecenia:
functions config list
Możemy to porównać z domyślnymi ustawieniami:
functions config default
Jak i możemy za pomocą polecenia functions config
edytować parametry. Tutaj functions config --help
pomoże.
Start/Stop/Deploy/Execute
By skorzystać z emulatora musimy na początku wystartować nasz system. Możemy to zrobić za pomocą komendy:
$ functions start Starting Google Cloud Functions Emulator... Google Cloud Functions Emulator STARTED ┌────────┬────────────┬─────────┬───────────────────────────────────────────────────┐ │ Status │ Name │ Trigger │ Resource │ ├────────┼────────────┼─────────┼───────────────────────────────────────────────────┤ │ READY │ helloWorld │ HTTP │ http://localhost:8010/gfun/us-central1/helloWorld │ └────────┴────────────┴─────────┴───────────────────────────────────────────────────┘
Wylistowanie dostępnych funkcji pojawia się wtedy, kiedy nasz emulator ma już jakąś funkcję wgraną.
Przeciwieństwem komendy jest:
$ functions stop Stopping Google Cloud Functions Emulator... Google Cloud Functions Emulator STOPPED
Piszę o tym, bo warto pamiętać, że jak coś wystartowaliśmy to warto to ubić. Ogólnie my nie wiemy, że coś działa – gdyż po wystartowaniu, dostajemy kontrolę nad terminalem/konsolą.
Deployowanie i uruchamianie
Dobra, by dalej coś zrobić potrzebujemy banalnego kodu. W jakimś testowym/tymczasowym folderze stwórzmy sobie plik index.js
(nie wiem, nie sprawdzałem innych nazw, możliwe, że to nie ma znaczenia) i dodajemy do niego:
exports.helloWorld = (reg, res) => { if (req.body.message === undefined) { res.status(400).send('No message defined!'); } else { res.status(200).send('Success: ' + req.body.message); } };
Zapiszmy plik i otwórzmy linię poleceń w danym katalogu, w którym jest nasza funkcja. Taką funkcję możemy zdeployować do naszego emulator, w tym celu wykonujemy polecenie deploy wraz z nazwą funkcji exportowaniej jak i typem triggera:
$ functions deploy helloWorld --trigger-http Copying file://C:\Users\Gutek\AppData\Local\Temp\us-central1-helloWorld-2560qRS5aZBOKymF.zip... Waiting for operation to finish...done. Deploying function.......done. Function helloWorld deployed. ┌────────────┬──────────────────────────────────────────────────────────────────────────────────────┐ │ Property │ Value │ ├────────────┼──────────────────────────────────────────────────────────────────────────────────────┤ │ Name │ helloWorld │ ├────────────┼──────────────────────────────────────────────────────────────────────────────────────┤ │ Trigger │ HTTP │ ├────────────┼──────────────────────────────────────────────────────────────────────────────────────┤ │ Resource │ http://localhost:8010/gfun/us-central1/helloWorld │ ├────────────┼──────────────────────────────────────────────────────────────────────────────────────┤ │ Timeout │ 60 seconds │ ├────────────┼──────────────────────────────────────────────────────────────────────────────────────┤ │ Local path │ D:\test\gfun │ ├────────────┼──────────────────────────────────────────────────────────────────────────────────────┤ │ Archive │ file://C:\Users\Gutek\AppData\Local\Temp\us-central1-helloWorld-2560qRS5aZBOKymF.zip │ └────────────┴──────────────────────────────────────────────────────────────────────────────────────┘
Jak widać nasza funkcja została z deployowana i teraz nawet mamy do niej URL dostępowe:
http://localhost:8010/gfun/us-central1/helloWorld
Jednak adresu nie trzeba znać jeżeli korzystamy z CLI:
functions call helloWorld
Możemy też przejrzeć logi wykonania funkcji za pomocą polecenia:
functions logs read
Ale do nich jeszcze dzisiaj wrócimy.
Debuggowanie z poziomu VS Code
Mając funkcję, która jest z deployowana, możemy otworzyć VS Code w katalogu gdzie nasz plik się z apką znajduje. Majac VS Code otwarte na katalogu możemy wystartować z deubogwaniem – F5
. To nam powinno stworzyć plik launch.json
zawierający taski do uruchomienia debuggera. Podmieńmy zawartość launch.json
na:
{ "version": "0.2.0", "configurations": [ { "name": "gcloud Gutek Test", "type": "node", "request": "attach", "port": 5858 } ] }
Możemy też na:
{ "version": "0.2.0", "configurations": [ { "name": "Inspect Function", "type": "node2", "request": "attach", "port": 9229 } ] }
Albo ogólnie możemy mieć dwa takie taski. Różnica polega na tym, że ten drugi korzysta z inspektora V8 który umożliwia podłączenie się chrome DevTools do instancji node.js. Także dwa taski różnią się tym co musimy odpalić z linii poleceń by się nimi pobawić. Opcję Inspect Function opisuje w Chrome DevTools (dosłownie to samo trzeba wpisać), tutaj zaś zajmijmy się gcloud Gutek Test.
Mając plik launch.json zaktualizowany, możemy zacząć debuggować naszą funkcję.
W tym celu należy odpalić dosłownie debugowanie za pomocą polecenia:
$ functions debug helloWorld Debugger for helloWorld listening on port 5858.
Mając informację o tym, że debuggor wystartował, możemy ponownie kliknąć F5
i zacząć debuggowanie. Oczywiście by nasza metoda się wykonała trzeba albo uderzyć do endpointu HTTP albo poprzez functions call
. Byśmy mogli coś podejrzeć potrzebujemy breakpoint (F9
) :)
Jedyny problem z debuggowaniem na jaki ja natrafiłem to problem z timeout. W ustawieniach mamy, że funkcja ma działać max przez 60 sekund. A więc za dużo czasu na debugging to nie mamy. Warto więc zmienić tę opcję za pomocą functions config.
Jak widać działa to dość sprawnie. Pozostawię was z VS Code byście się trochę pobawili. Ale jak skończycie chodźcie z powrotem, bo dalej piszemy o debuggowaniu.
Debuggowanie z poziomu Google Chrome
To wiemy jak debuggować z poziomy VS Code, a jak to zrobić z poziomu chrome? Najpierw zresetujmy naszą funkcję (na wszelki wypadek):
functions reset helloWorld
To zakończy sesję debguggowania i na nowo “wystartuje” funkcję. Jeżeli chcemy przy tym restarcie zachować debugging to możemy dodać parametr --keep
, jednak dla tego przypadku tego nie róbmy, przejdźmy przez pełny proces debuggowania w chrome.
Jeżeli chcemy skorzystać z najnowszej wersji node.js, to możemy podłączyć się pod inspektora (to samo polecenie trzeba użyć jak chcielibyśmy z drugiego tasku w VS Code skorzystać):
$ functions inspect helloWorld Debugger for helloWorld listening on port 9229.
Teraz możemy dobrać się do debuggowania naszego kodu tylko nie znamy url z którego mamy skorzystać. Ta część niestety nie jest fajnie rozwiązana. By dowiedzieć się jaki URL mamy użyć musimy odczytać logi:
$ functions logs read --limit=5 Warning: This is an experimental feature and could change at any time. To start debugging, open the following URL in Chrome: chrome-devtools://devtools/remote/serve_file/@60cd6e859b9f557d2312f5bf532f6aec5f284980/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9229/1a893692-053b-4210-93d3-4199fb497c56 2017-07-12T15:10:13.709Z - info: Debugger (via --inspect) for projects/gfun/locations/us-central1/functions/helloWorld listening on port 9229.
Zastosowałem –limit=X do ograniczenia liczby zwracanych ostatnich linijek. 5 wystarczy. Z logu wynika że nasz link to:
chrome-devtools://devtools/remote/serve_file/@60cd6e859b9f557d2312f5bf532f6aec5f284980/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9229/1a893692-053b-4210-93d3-4199fb497c56
Odpalamy Chrome, wklejamy url. Teraz trzeba cierpliwości by znaleźć nasz plik index (CTRL+P
albo CMD+P
). Jak go znajdziemy to ustawmy breakpoint i następnie wykonajmy zapytanie do naszej funkcji (url dostaliśmy przy deploy, jest taki sam jak przy VS Code). I boom:
Podsumowanie
To tyle na dzisiaj, tylko tyle albo aż tyle. Więcej za bardzo się nie da zrobić z emulatorem, ale i tak da się dość dużo. Zarówno łatwo jest go wystartować jak i potem wgrać funkcję i na końcu ją z debuggować. Narzędzie o dziwo bardzo przyjazne czego się po google jakoś nie spodziewałem – nie wiem czemu ;)
Tak czy siak, warto się nim pobawić, pełną dokumentację jak i tutoriale można znaleźć na github. Kończąc życzę miłej zabawy :) do jutra!