Google Cloud Platform Kullanarak Sunucusuz Ön Uç Uygulamaları Oluşturma

Yayınlanan: 2022-03-10
Kısa özet ↬ Geliştiriciler tarafından uygulamalarının iş mantığını ele almak için sunucusuz uygulamaların kullanımı yüksek oranda artış gösteriyor, ancak genel bulut içinde önemli bir hizmet sağlayıcısı olan Google Cloud, geliştiricilerin sunucusuz uygulamaları yönetmesine nasıl izin veriyor? Bu makalede, sunucusuz uygulamaların ne olduğunu, Google Cloud'da nasıl kullanıldığını ve ayrıca bir front-end uygulamasında kullanılabilecek senaryoları öğreneceksiniz.

Son zamanlarda, uygulamaların geliştirme paradigması, bir uygulamada kullanılan kaynakları manuel olarak dağıtmak, ölçeklendirmek ve güncellemek zorunda olmaktan, bu kaynakların yönetiminin çoğunu yapmak için üçüncü taraf bulut hizmeti sağlayıcılarına güvenmeye doğru kaymaya başladı.

Mümkün olan en kısa sürede pazara uygun bir uygulama oluşturmak isteyen bir geliştirici veya kuruluş olarak, ana odak noktanız, yapılandırma, dağıtım ve stres testi için daha az zaman harcarken temel uygulama hizmetinizi kullanıcılarınıza sunmak olabilir. başvurunuz. Kullanım durumunuz buysa, uygulamanızın iş mantığını sunucusuz bir şekilde ele almak en iyi seçeneğiniz olabilir. Ama nasıl?

Bu makale, uygulamalarında belirli işlevler oluşturmak isteyen ön uç mühendisleri veya Google Cloud Platform'a dağıtılan sunucusuz bir uygulama kullanarak mevcut bir arka uç hizmetinden belirli bir işlevi çıkarmak ve işlemek isteyen arka uç mühendisleri için faydalıdır.

Not : Burada anlatılanlardan faydalanmak için React ile çalışma deneyimine sahip olmanız gerekmektedir. Sunucusuz uygulamalarda önceden deneyim gerekmez.

Başlamadan önce, sunucusuz uygulamaların gerçekte ne olduğunu ve bir ön uç mühendis bağlamında bir uygulama oluştururken sunucusuz mimarinin nasıl kullanılabileceğini anlayalım.

Sunucusuz Uygulamalar

Sunucusuz uygulamalar, uygulama yazarı adına genel bulut içinde üçüncü taraf bulut hizmeti sağlayıcıları tarafından barındırılan ve yönetilen, yeniden kullanılabilir küçük olay güdümlü işlevlere bölünmüş uygulamalardır. Bunlar belirli olaylar tarafından tetiklenir ve talep üzerine yürütülür. Serverless kelimesine eklenen “ less ” eki sunucunun olmadığını gösterse de bu %100 değildir. Bu uygulamalar sunucularda ve diğer donanım kaynaklarında çalışmaya devam eder, ancak bu durumda bu kaynaklar geliştirici tarafından değil, üçüncü taraf bulut hizmeti sağlayıcısı tarafından sağlanır. Bu nedenle, uygulama yazarı için sunucusuzdurlar, ancak yine de sunucularda çalışırlar ve genel internet üzerinden erişilebilirler.

Sunucusuz bir uygulamanın kullanım örneği, açılış sayfanızı ziyaret eden ve ürün lansmanı e-postaları almaya abone olan potansiyel kullanıcılara e-posta göndermek olabilir. Bu aşamada, muhtemelen çalışan bir arka uç hizmetiniz yoktur ve bir tane oluşturmak, dağıtmak ve yönetmek için gereken zaman ve kaynakları feda etmek istemezsiniz, çünkü hepsi e-posta göndermeniz gerekir. Burada, bir e-posta istemcisi kullanan tek bir dosya yazabilir ve sunucusuz uygulamayı destekleyen herhangi bir bulut sağlayıcısına konuşlandırabilir ve bu sunucusuz uygulamayı açılış sayfanıza bağlarken sizin adınıza bu uygulamayı yönetmelerine izin verebilirsiniz.

Ön uç uygulamanız için sunucusuz uygulamalardan veya Hizmet Olarak İşlevler'den (FAAS) yararlanmayı düşünmeniz için pek çok neden olsa da, göz önünde bulundurmanız gereken bazı çok önemli nedenler şunlardır:

  • Uygulama otomatik ölçeklendirme
    Sunucusuz uygulamalar yatay olarak ölçeklenir ve bu “ ölçeklendirme ”, çağrıların miktarına bağlı olarak Bulut sağlayıcısı tarafından otomatik olarak yapılır, bu nedenle uygulama ağır yük altındayken geliştiricinin kaynakları manuel olarak eklemesi veya kaldırması gerekmez.
  • Maliyet etkinliği
    Olaya dayalı, sunucusuz uygulamalar yalnızca gerektiğinde çalışır ve bu, çağrılan süreye göre faturalandırıldıkları için ücretlere de yansır.
  • Esneklik
    Sunucusuz uygulamalar, yüksek oranda yeniden kullanılabilir olacak şekilde oluşturulmuştur ve bu, tek bir projeye veya uygulamaya bağlı olmadıkları anlamına gelir. Belirli bir işlevsellik, sunucusuz bir uygulamaya çıkarılabilir, birden çok proje veya uygulamada dağıtılabilir ve kullanılabilir. Sunucusuz uygulamalar, uygulama yazarının tercih ettiği dilde de yazılabilir, ancak bazı bulut sağlayıcıları yalnızca daha az sayıda dili destekler.

Atlamadan sonra daha fazlası! Aşağıdan okumaya devam edin ↓

Sunucusuz uygulamalardan yararlanırken, her geliştiricinin genel bulut içinde yararlanabileceği çok çeşitli bulut sağlayıcıları vardır. Bu makale bağlamında, Google Cloud Platform'daki sunucusuz uygulamalara — nasıl oluşturulduklarına, yönetildiklerine, dağıtıldıklarına ve ayrıca Google Cloud'daki diğer ürünlerle nasıl entegre olduklarına odaklanacağız. Bunu yapmak için, süreç boyunca çalışırken bu mevcut React uygulamasına yeni işlevler ekleyeceğiz:

  • Kullanıcı verilerini bulutta depolamak ve almak;
  • Google Cloud'da cron işleri oluşturma ve yönetme;
  • Cloud Functions'ı Google Cloud'a Dağıtma.

Not : Sunucusuz uygulamalar yalnızca React'e bağlı değildir, tercih ettiğiniz ön uç çerçeve veya kitaplık bir HTTP isteği yapabildiği sürece sunucusuz bir uygulama kullanabilir.

Google Bulut İşlevleri

Google Cloud, geliştiricilerin Bulut İşlevlerini kullanarak sunucusuz uygulamalar oluşturmasına olanak tanır ve bunları İşlevler Çerçevesini kullanarak çalıştırır. Bulut işlevleri, mevcut altı olay tetikleyicisinden belirli tetikleyiciyi dinlemek ve ardından yürütmek için yazıldığı işlemi gerçekleştirmek için Google Cloud'a dağıtılan yeniden kullanılabilir olay güdümlü işlevlerdir.

Kısa ömürlü ( varsayılan yürütme zaman aşımı 60 saniye ve maksimum 9 dakika olan) bulut işlevleri JavaScript, Python, Golang ve Java kullanılarak yazılabilir ve çalışma zamanları kullanılarak yürütülebilir. JavaScript'te, yalnızca Node çalışma zamanının bazı kullanılabilir sürümleri kullanılarak yürütülebilirler ve Google Cloud'da çalıştırılacak birincil işlev olarak dışa aktarıldıkları için düz JavaScript kullanılarak CommonJS modülleri biçiminde yazılırlar.

Bulut işlevine bir örnek, işlevin bir kullanıcının verilerini işlemesi için boş bir standart olan aşağıdaki gibidir.

 // index.js exports.firestoreFunction = function (req, res) { return res.status(200).send({ data: `Hello ${req.query.name}` }); }

Yukarıda bir fonksiyonu dışa aktaran bir modülümüz var. Yürütüldüğünde, HTTP yoluna benzer istek ve yanıt argümanlarını alır.

Not : Bir istek yapıldığında, bir bulut işlevi her HTTP protokolüyle eşleşir. Bir bulut işlevini yürütmek için istekte bulunurken eklenen veriler, GET istekleri için sorgu gövdesindeyken POST istekleri için istek gövdesinde bulunacağından, istek bağımsız değişkeninde veri beklerken bu dikkate değerdir.

Bulut işlevleri, geliştirme sırasında @google-cloud/functions-framework paketini yazılı işlevin yerleştirildiği klasöre kurarak veya npm i -g @google-cloud/functions-framework çalıştırarak birden çok işlev için kullanmak üzere global bir yükleme yaparak yerel olarak yürütülebilir. komut satırınızdan npm i -g @google-cloud/functions-framework . Kurulduktan sonra, aşağıdakine benzer dışa aktarılan modülün adıyla package.json betiğine eklenmelidir:

 "scripts": { "start": "functions-framework --target=firestoreFunction --port=8000", }

Yukarıda, package.json dosyasında, function-framework'ü çalıştıran ve ayrıca 8000 numaralı bağlantı noktasında yerel olarak çalıştırılacak hedef işlev olarak firestoreFunction belirten betiklerimizde tek bir komut var.

Bu işlevin uç noktasını, curl kullanarak localhost'ta 8000 numaralı bağlantı noktasına GET isteğinde bulunarak test edebiliriz. Aşağıdaki komutu bir terminale yapıştırmak bunu yapacak ve bir yanıt döndürecektir.

 curl https://localhost:8000?name="Smashing Magazine Author"

Yukarıdaki komut, GET HTTP yöntemiyle bir istek yapar ve 200 durum kodu ve sorguya eklenen adı içeren bir nesne verisi ile yanıt verir.

Bir Bulut İşlevi Dağıtma

Mevcut dağıtım yöntemleri arasında, yerel bir makineden bir bulut işlevini dağıtmanın hızlı bir yolu, kurduktan sonra bulut Sdk'sini kullanmaktır. Google Cloud'daki projenizle gcloud sdk'nin kimliğini doğruladıktan sonra aşağıdaki komutu terminalden çalıştırmak, yerel olarak oluşturulan bir işlevi Cloud Function hizmetine dağıtır.

 gcloud functions deploy "demo-function" --runtime nodejs10 --trigger-http --entry-point=demo --timeout=60 --set-env-vars=[name="Developer"] --allow-unauthenticated

Aşağıda açıklanan işaretleri kullanarak, yukarıdaki komut, " demo-function " adıyla google bulutuna HTTP ile tetiklenen bir işlevi dağıtır.

  • İSİM
    Bu, bir bulut işlevine dağıtılırken verilen addır ve gereklidir.
  • region
    Bu, bulut işlevinin dağıtılacağı bölgedir. Varsayılan olarak us-central1 .
  • trigger-http
    Bu, işlevin tetikleyici türü olarak HTTP'yi seçer.
  • allow-unauthenticated
    Bu, işlevin, arayanın kimliğinin doğrulanıp doğrulanmadığını kontrol etmeden oluşturulan uç noktası kullanılarak İnternet üzerinden Google Cloud dışında çağrılmasına olanak tanır.
  • source
    Dağıtılacak işlevi içeren dosyaya uçbirimden yerel yol.
  • entry-point
    Bu, işlevlerin yazıldığı dosyadan dağıtılacak belirli dışa aktarılan modül.
  • runtime
    Bu, kabul edilen çalışma zamanı listesindeki işlev için kullanılacak dil çalışma zamanıdır.
  • timeout
    Bu, bir işlevin zaman aşımına uğramadan önce çalışabileceği maksimum süredir. Varsayılan olarak 60 saniyedir ve maksimum 9 dakikaya ayarlanabilir.

Not : Bir işlevin kimliği doğrulanmamış isteklere izin vermesini sağlamak, işlevinizin uç noktasına sahip olan herkesin, siz izin vermeden de istekte bulunabileceği anlamına gelir. Bunu azaltmak için, ortam değişkenleri aracılığıyla veya her istekte yetkilendirme başlıkları isteyerek uç noktanın özel kalmasını sağlayabiliriz.

Artık demo işlevimiz dağıtıldığına ve uç noktaya sahip olduğumuza göre, bu işlevi küresel bir otomatik top yüklemesi kullanan gerçek dünyadaki bir uygulamada kullanılıyormuş gibi test edebiliriz. Açılan terminalden autocannon -d=5 -c=300 CLOUD_FUNCTION_URL çalıştırıldığında, bulut işlevine 5 saniyelik bir süre içinde 300 eşzamanlı istek oluşturulur. Bu, bulut işlevini başlatmak ve ayrıca işlevin kontrol panelinde keşfedebileceğimiz bazı ölçümler oluşturmak için fazlasıyla yeterlidir.

Not : Bir işlevin uç noktası, dağıtımdan sonra terminalde yazdırılacaktır. Aksi takdirde, uç nokta da dahil olmak üzere dağıtılan işlevle ilgili ayrıntıları almak için uçbirimden gcloud function describe FUNCTION_NAME çalıştırın.

Gösterge tablosundaki metrikler sekmesini kullanarak, kaç çağrı yapıldığını, ne kadar sürdüğünü, işlevin bellek ayak izini ve yapılan istekleri işlemek için kaç örneğin döndürüldüğünü içeren son istekten görsel bir temsil görebiliriz.

Yapılan tüm son isteklerden toplanan ölçümlerin bir grafiğini gösteren bir işlevin kontrol paneli.
Yapılan tüm istekleri gösteren bulut işlevi panosu. (Büyük önizleme)

Yukarıdaki resimdeki Etkin Örnekler grafiğine daha yakından bakıldığında, otomatik top kullanılarak yapılan istekleri işlemek için 209 örneğin birkaç saniye içinde döndürüldüğünü görebildiğimiz için Bulut İşlevlerinin yatay ölçeklendirme kapasitesi görülmektedir.

Bulut İşlev Günlükleri

Google bulutuna dağıtılan her işlevin bir günlüğü vardır ve bu işlev her yürütüldüğünde, o günlüğe yeni bir giriş yapılır. İşlev panosundaki Günlük sekmesinden, bir bulut işlevindeki tüm günlük girişlerinin bir listesini görebiliriz.

Aşağıda, autocannon kullanarak yaptığımız istekler sonucunda oluşturulan, konuşlandırılmış demo-function günlük girişleri bulunmaktadır.

İşlevin yürütme sürelerindeki günlükleri gösteren bulut işlevi günlüğü.
Tüm yürütme günlüklerini gösteren bulut işlevi günlüğü sekmesi. (Büyük önizleme)

Yukarıdaki günlük girişlerinin her biri, bir işlevin tam olarak ne zaman yürütüldüğünü, yürütmenin ne kadar sürdüğünü ve hangi durum koduyla sona erdiğini gösterir. Bir fonksiyondan kaynaklanan herhangi bir hata varsa, oluştuğu satır da dahil olmak üzere hatanın detayları buradaki günlüklerde gösterilecektir.

Google Cloud'daki Günlük Gezgini, bir bulut işlevindeki günlükler hakkında daha kapsamlı ayrıntıları görmek için kullanılabilir.

Ön Uç Uygulamaları ile Bulut İşlevleri

Bulut işlevleri, ön uç mühendisler için çok kullanışlı ve güçlüdür. Arka uç uygulamalarını yönetme bilgisi olmayan bir ön uç mühendisi, bir işlevi bir bulut işlevine çıkarabilir, Google Cloud'a dağıtabilir ve uç noktası aracılığıyla bulut işlevine HTTP istekleri göndererek bir ön uç uygulamada kullanabilir.

Bir ön uç uygulamada bulut işlevlerinin nasıl kullanılabileceğini göstermek için bu React uygulamasına daha fazla özellik ekleyeceğiz. Uygulama, kimlik doğrulama ve ana sayfa kurulumu arasında zaten temel bir yönlendirmeye sahiptir. Oluşturulan bulut işlevlerinin kullanımı uygulama azaltıcılar içinde yapılacağından, uygulama durumumuzu yönetmek için React Context API'yi kullanacak şekilde genişleteceğiz.

Başlamak için, createContext API'sini kullanarak uygulamamızın bağlamını oluşturuyoruz ve ayrıca uygulamamızdaki eylemleri işlemek için bir indirgeyici oluşturuyoruz.

 // state/index.js import { createContext } from “react”;

dışa aktarma const UserReducer = (eylem, durum) => { geçiş (action.type) { case “CREATE-USER”: break; durum “KULLANICI-RESMİ YÜKLE”: break; durum “FETCH-DATA” : ara durum “LOGOUT” : ara; varsayılan: console.log( ${action.type} is not recognized ) } };

dışa aktarma const userState = { user: null, isLoggedIn : false };

dışa aktarma const UserContext = createContext(userState);

Yukarıda, kendisine gönderilen eylemin türüne göre bir işlem gerçekleştirmesine izin veren bir switch ifadesi içeren bir UserReducer işlevi oluşturmaya başladık. Switch ifadesinin dört durumu vardır ve bunlar ele alacağımız eylemlerdir. Şimdilik henüz bir şey yapmıyorlar ama bulut fonksiyonlarımızla entegrasyona başladığımızda, onlarda yapılacak işlemleri adım adım uygulayacağız.

Ayrıca, React createContext API'sini kullanarak uygulamamızın bağlamını oluşturduk ve dışa aktardık ve ona, kimlik doğrulamadan sonra şu anda null değerinden kullanıcının verilerine güncellenecek olan bir kullanıcı değeri ve ayrıca olup olmadığını bilmek için bir isLoggedIn boole değeri içeren userState nesnesinin varsayılan değerini verdik. kullanıcı oturum açtı veya oturum açmadı.

Şimdi bağlamımızı tüketmeye devam edebiliriz, ancak bunu yapmadan önce, alt bileşenlerin bağlamımızın değer değişikliğine abone olabilmesi için tüm uygulama ağacımızı UserContext eklenen Provider ile sarmamız gerekir.

 // index.js import React from "react"; import ReactDOM from "react-dom"; import "./index.css"; import App from "./app"; import { UserContext, userState } from "./state/"; ReactDOM.render( <React.StrictMode> <UserContext.Provider value={userState}> <App /> </UserContext.Provider> </React.StrictMode>, document.getElementById("root") ); serviceWorker.unregister();

Enter uygulamamızı, root bileşenindeki UserContext sağlayıcısı ile sardık ve prop değerinde önceden oluşturulmuş userState varsayılan değerimizi ilettik.

Artık uygulama durumumuz tamamen kurulduğuna göre, bir bulut işlevi aracılığıyla Google Cloud Firestore'u kullanarak kullanıcının veri modelini oluşturmaya geçebiliriz.

Uygulama Verilerini İşleme

Bu uygulamadaki bir kullanıcının verileri benzersiz bir kimlik, bir e-posta, bir şifre ve bir görüntünün URL'sinden oluşur. Bir bulut işlevi kullanılarak bu veriler, Google Cloud Platform'da sunulan Cloud Firestore Hizmeti kullanılarak bulutta depolanacaktır.

Esnek bir NoSQL veritabanı olan Google Cloud Firestore , çevrimdışı veri desteğinin yanı sıra daha zengin ve daha hızlı sorgulara izin veren yeni geliştirilmiş özelliklerle Firebase Gerçek Zamanlı Veritabanından oluşturulmuştur. Firestore hizmeti içindeki veriler, MongoDB gibi diğer NoSQL veritabanlarına benzer şekilde koleksiyonlar ve belgeler halinde düzenlenir.

Firestore'a Google Cloud Console aracılığıyla görsel olarak erişilebilir. Başlatmak için sol gezinme bölmesini açın ve Veritabanı bölümüne gidin ve Firestore'a tıklayın. Bu, mevcut verilere sahip kullanıcılar için koleksiyonların listesini gösterir veya mevcut bir koleksiyon olmadığında kullanıcıdan yeni bir koleksiyon oluşturmasını ister. Uygulamamız tarafından kullanılacak bir kullanıcı koleksiyonu oluşturacağız.

Google Cloud Platform'daki diğer hizmetlere benzer şekilde Cloud Firestore, bir düğüm ortamında kullanılmak üzere oluşturulmuş bir JavaScript istemci kitaplığına sahiptir ( tarayıcıda kullanılırsa bir hata verilir). Doğaçlama yapmak için, @google-cloud/firestore paketini kullanarak Cloud Firestore'u bir bulut işlevinde kullanıyoruz.

Cloud Firestore'u Bulut İşleviyle Kullanma

Başlamak için, demo-function işlevinden oluşturduğumuz ilk işlevi firestoreFunction olarak yeniden adlandıracağız ve ardından Firestore ile bağlantı kuracak ve verileri kullanıcılarımızın koleksiyonuna kaydedecek şekilde genişleteceğiz.

 require("dotenv").config(); const { Firestore } = require("@google-cloud/firestore"); const { SecretManagerServiceClient } = require("@google-cloud/secret-manager"); const client = new SecretManagerServiceClient(); exports.firestoreFunction = function (req, res) { return { const { email, password, type } = req.body; const firestore = new Firestore(); const document = firestore.collection("users"); console.log(document) // prints details of the collection to the function logs if (!type) { res.status(422).send("An action type was not specified"); } switch (type) { case "CREATE-USER": break case "LOGIN-USER": break; default: res.status(422).send(`${type} is not a valid function action`) } };

Yangın deposunu içeren daha fazla işlemi ele almak için, uygulamamızın kimlik doğrulama ihtiyaçlarını ele almak için iki durumlu bir switch ifadesi ekledik. Switch deyimimiz, uygulamamızdan bu fonksiyona istek yaparken istek gövdesine eklediğimiz bir type ifadesini değerlendirir ve bu type veriler istek gövdemizde bulunmadığında, istek Kötü İstek ve 400 durum kodu olarak tanımlanır. eksik type belirtmek için bir iletinin yanında yanıt olarak gönderilir.

Cloud Firestore istemci kitaplığı içindeki Application Default Credentials(ADC) kitaplığını kullanarak Firestore ile bağlantı kurarız. Sonraki satırda başka bir değişkende toplama yöntemini çağırıyoruz ve koleksiyonumuzun adını geçiyoruz. Bunu, içerilen belgelerin toplanmasıyla ilgili diğer işlemleri daha ileri düzeyde gerçekleştirmek için kullanacağız.

Not : Google Cloud'daki hizmetler için istemci kitaplıkları, oluşturucu başlatılırken iletilen oluşturulmuş bir hizmet hesabı anahtarını kullanarak ilgili hizmetlerine bağlanır. Hizmet hesabı anahtarı bulunmadığında, varsayılan olarak Uygulama Varsayılan Kimlik Bilgilerini kullanır ve bu da bulut işlevine atanan IAM rollerini kullanarak bağlanır.

Gcloud SDK kullanılarak yerel olarak dağıtılan bir işlevin kaynak kodunu düzenledikten sonra, bulut işlevini güncellemek ve yeniden dağıtmak için önceki komutu bir terminalden yeniden çalıştırabiliriz.

Artık bir bağlantı kurulduğuna göre, istek gövdesindeki verileri kullanarak yeni bir kullanıcı oluşturmak için CREATE-USER vakasını uygulayabiliriz.

 require("dotenv").config(); const { Firestore } = require("@google-cloud/firestore"); const path = require("path"); const { v4 : uuid } = require("uuid") const cors = require("cors")({ origin: true }); const client = new SecretManagerServiceClient(); exports.firestoreFunction = function (req, res) { return cors(req, res, () => { const { email, password, type } = req.body; const firestore = new Firestore(); const document = firestore.collection("users"); if (!type) { res.status(422).send("An action type was not specified"); } switch (type) { case "CREATE-USER": if (!email || !password) { res.status(422).send("email and password fields missing"); } const id = uuid() return bcrypt.genSalt(10, (err, salt) => { bcrypt.hash(password, salt, (err, hash) => { document.doc(id) .set({ id : id email: email, password: hash, img_uri : null }) .then((response) => res.status(200).send(response)) .catch((e) => res.status(501).send({ error : e }) ); }); }); case "LOGIN": break; default: res.status(400).send(`${type} is not a valid function action`) } }); };

Kaydedilmek üzere olan belgenin ID'si olarak kullanılacak uuid paketini kullanarak belge üzerindeki set metoduna ve ayrıca kullanıcının ID'sine geçirerek bir UUID oluşturduk. Varsayılan olarak, eklenen her belgede rastgele bir kimlik oluşturulur, ancak bu durumda, resim yüklemesini işlerken belgeyi güncelleyeceğiz ve belirli bir belgenin güncellenmesini sağlamak için UUID kullanılacaktır. Kullanıcının parolasını düz metin olarak saklamak yerine, önce bcryptjs kullanarak onu tuzlarız, ardından sonuç karmasını kullanıcının parolası olarak saklarız.

firestoreFunction bulut işlevini uygulamaya entegre ederek, bunu kullanıcı azaltıcı içindeki CREATE_USER durumundan kullanıyoruz.

Hesap Oluştur düğmesine tıkladıktan sonra, firestoreFunction işlevinin uç noktasına yazılan e-posta ve parolayı içeren bir POST isteği yapmak için CREATE_USER türünde redüktörlere bir eylem gönderilir.

 import { createContext } from "react"; import { navigate } from "@reach/router"; import Axios from "axios"; export const userState = { user : null, isLoggedIn: false, }; export const UserReducer = (state, action) => { switch (action.type) { case "CREATE_USER": const FIRESTORE_FUNCTION = process.env.REACT_APP_FIRESTORE_FUNCTION; const { userEmail, userPassword } = action; const data = { type: "CREATE-USER", email: userEmail, password: userPassword, }; Axios.post(`${FIRESTORE_FUNCTION}`, data) .then((res) => { navigate("/home"); return { ...state, isLoggedIn: true }; }) .catch((e) => console.log(`couldnt create user. error : ${e}`)); break; case "LOGIN-USER": break; case "UPLOAD-USER-IMAGE": break; case "FETCH-DATA" : break case "LOGOUT": navigate("/login"); return { ...state, isLoggedIn: false }; default: break; } }; export const UserContext = createContext(userState);

Yukarıda, firestoreFunction istekte bulunmak için Axios'u kullandık ve bu istek çözüldükten sonra, istekten döndürülen verilere kullanıcının başlangıç ​​durumunu null olarak ayarladık ve son olarak kullanıcıyı kimliği doğrulanmış bir kullanıcı olarak ana sayfaya yönlendirdik. .

Bu noktada, yeni bir kullanıcı başarıyla bir hesap oluşturabilir ve ana sayfaya yönlendirilebilir. Bu süreç, bir bulut işlevinden temel veri oluşturma işlemini gerçekleştirmek için Firestore'u nasıl kullandığımızı gösterir.

Dosya Depolamayı Kullanma

Bir uygulamada bir kullanıcının dosyalarının saklanması ve alınması, çoğu zaman bir uygulamada çok ihtiyaç duyulan bir özelliktir. Bir node.js arka ucuna bağlı bir uygulamada Multer, yüklenen bir dosyanın geldiği çok parçalı/form verilerini işlemek için genellikle bir ara yazılım olarak kullanılır. Ancak node.js arka ucunun yokluğunda, çevrimiçi bir dosya kullanabiliriz. Statik uygulama varlıklarını depolamak için Google Cloud Storage gibi depolama hizmeti.

Google Cloud Storage, uygulamalar için nesneler olarak herhangi bir miktarda veriyi paketlerde depolamak için kullanılan, küresel olarak kullanılabilen bir dosya depolama hizmetidir. Hem küçük hem de büyük boyutlu uygulamalar için statik varlıkların depolanmasını idare edecek kadar esnektir.

Bulut Depolama hizmetini bir uygulama içinde kullanmak için mevcut Depolama API uç noktalarından veya resmi düğüm Depolama istemci kitaplığını kullanarak kullanabiliriz. Ancak, Node Storage istemci kitaplığı bir Tarayıcı penceresinde çalışmaz, bu nedenle kitaplığı kullanacağımız Bulut İşlevinden yararlanabiliriz.

Bunun bir örneği, oluşturulan bir Bulut Kovasına bir dosya bağlayan ve yükleyen aşağıdaki Bulut İşlevidir.

 const cors = require("cors")({ origin: true }); const { Storage } = require("@google-cloud/storage"); const StorageClient = new Storage(); exports.Uploader = (req, res) => { const { file } = req.body; StorageClient.bucket("TEST_BUCKET") .file(file.name) .then((response) => { console.log(response); res.status(200).send(response) }) .catch((e) => res.status(422).send({error : e})); }); };

Yukarıdaki bulut işlevinden aşağıdaki iki ana işlemi gerçekleştiriyoruz:

  • İlk olarak, Storage constructor içinde Cloud Storage ile bir bağlantı oluşturuyoruz ve bu, Cloud Storage ile kimlik doğrulaması yapmak için Google Cloud'daki Application Default Credentials (ADC) özelliğini kullanıyor.

  • İkinci olarak, istek gövdesinde bulunan dosyayı TEST_BUCKET yöntemini çağırarak ve dosyanın adını .file . Bu eşzamansız bir işlem olduğundan, bu eylemin ne zaman çözüldüğünü bilmek için bir söz kullanırız ve 200 yanıtı geri göndeririz, böylece çağrının yaşam döngüsünü sona erdiririz.

Şimdi, bir kullanıcının profil görüntüsünün yüklenmesini işlemek için yukarıdaki Uploader Bulut İşlevini genişletebiliriz. Bulut işlevi, bir kullanıcının profil resmini alır, bunu uygulamamızın bulut paketinde saklar ve ardından kullanıcının img_uri verilerini Firestore hizmetinde kullanıcılarımızın koleksiyonunda günceller.

 require("dotenv").config(); const { Firestore } = require("@google-cloud/firestore"); const cors = require("cors")({ origin: true }); const { Storage } = require("@google-cloud/storage"); const StorageClient = new Storage(); const BucketName = process.env.STORAGE_BUCKET exports.Uploader = (req, res) => { return Cors(req, res, () => { const { file , userId } = req.body; const firestore = new Firestore(); const document = firestore.collection("users"); StorageClient.bucket(BucketName) .file(file.name) .on("finish", () => { StorageClient.bucket(BucketName) .file(file.name) .makePublic() .then(() => { const img_uri = `https://storage.googleapis.com/${Bucket}/${file.path}`; document .doc(userId) .update({ img_uri, }) .then((updateResult) => res.status(200).send(updateResult)) .catch((e) => res.status(500).send(e)); }) .catch((e) => console.log(e)); }); }); };

Şimdi, aşağıdaki ekstra işlemleri gerçekleştirmek için yukarıdaki Yükleme işlevini genişlettik:

  • İlk olarak, Firestore yapıcısını başlatarak users koleksiyonunu almak için Firestore hizmetiyle yeni bir bağlantı kurar ve Cloud Storage ile kimlik doğrulaması yapmak için Uygulama Varsayılan Kimlik Bilgilerini (ADC) kullanır.
  • İstek gövdesine eklenen dosyayı yükledikten sonra, yüklenen dosya üzerinde makePublic yöntemini çağırarak genel bir URL üzerinden erişilebilir olması için herkese açık hale getiriyoruz. Cloud Storage'ın varsayılan Erişim Kontrolüne göre, bir dosyayı herkese açık hale getirmeden internet üzerinden bir dosyaya erişilemez ve uygulama yüklendiğinde bunu yapabilmek için.

Not : Bir dosyayı herkese açık hale getirmek, uygulamanızı kullanan herkesin dosya bağlantısını kopyalayabileceği ve dosyaya sınırsız erişime sahip olabileceği anlamına gelir. Bunu önlemenin bir yolu, paketinizdeki bir dosyaya tamamen herkese açık hale getirmek yerine geçici erişim vermek için İmzalı bir URL kullanmaktır.

  • Ardından, kullanıcının mevcut verilerini, yüklenen dosyanın URL'sini içerecek şekilde güncelleriz. Firestore'un WHERE sorgusunu kullanarak belirli kullanıcının verilerini buluruz ve istek gövdesinde bulunan userId kullanırız, ardından img_uri alanını yeni güncellenen görüntünün URL'sini içerecek şekilde ayarlarız.

Yukarıdaki bulut Upload işlevi, Firestore hizmetinde kayıtlı kullanıcıları olan herhangi bir uygulamada kullanılabilir. Kullanıcının IS'sini ve bir görüntüyü istek gövdesine koyarak, uç noktaya bir POST isteği yapmak için gereken her şey.

Uygulama içinde buna bir örnek, işleve POST isteği yapan ve istekten döndürülen görüntü bağlantısını uygulama durumuna getiren UPLOAD-FILE durumudur.

 # index.js import Axios from 'axios' const UPLOAD_FUNCTION = process.env.REACT_APP_UPLOAD_FUNCTION export const UserReducer = (state, action) => { switch (action.type) { case "CREATE-USER" : # .....CREATE-USER-LOGIC .... case "UPLOAD-FILE": const { file, id } = action return Axios.post(UPLOAD_FUNCTION, { file, id }, { headers: { "Content-Type": "image/png", }, }) .then((response) => {}) .catch((e) => console.log(e)); default : return console.log(`${action.type} case not recognized`) } }

Yukarıdaki geçiş durumundan, eklenen dosyanın istek gövdesine dahil edilmesi için UPLOAD_FUNCTION Axios kullanarak bir POST isteği yapıyoruz ve ayrıca istek başlığına bir görüntü Content-Type ekledik.

Başarılı bir yüklemeden sonra, bulut işlevinden döndürülen yanıt, google bulut deposuna yüklenen görüntünün geçerli bir URL'sini içerecek şekilde güncellenen kullanıcının veri belgesini içerir. Daha sonra kullanıcının durumunu yeni verileri içerecek şekilde güncelleyebiliriz ve bu aynı zamanda profil bileşenindeki kullanıcının profil resmi src öğesini de günceller.

Güncelleme profil resmine sahip bir kullanıcının profil sayfası
Yeni güncellenen profil resmini gösterecek şekilde yeni güncellenen bir kullanıcının profil sayfası. (Büyük önizleme)

Cron İşlerini İşleme

Kullanıcılara e-posta göndermek veya belirli bir zamanda dahili bir eylem gerçekleştirmek gibi tekrarlayan otomatik görevler, çoğu zaman uygulamalara dahil edilen bir özelliktir. Normal bir node.js uygulamasında, bu tür görevler, node-cron veya node-schedule kullanılarak cron işleri olarak ele alınabilir. Google Cloud Platform'u kullanarak sunucusuz uygulamalar oluştururken, Bulut Zamanlayıcı ayrıca bir cron işlemi gerçekleştirmek üzere tasarlanmıştır.

Not : Bulut Zamanlayıcı gelecekte yürütülecek işler oluşturmada Unix cron yardımcı programına benzer şekilde çalışsa da, Bulut Zamanlayıcı'nın cron yardımcı programı gibi bir komut çalıştırmadığını belirtmek önemlidir. Bunun yerine, belirtilen bir hedefi kullanarak bir işlem gerçekleştirir.

Adından da anlaşılacağı gibi, Bulut Zamanlayıcı, kullanıcıların gelecekte gerçekleştirilecek bir işlemi planlamalarına olanak tanır. Her işleme bir adı verilir ve işler görsel olarak oluşturulabilir, güncellenebilir ve hatta Bulut Konsolu'nun Zamanlayıcı bölümünden yok edilebilir. Ad ve açıklama alanının yanı sıra, Bulut Zamanlayıcı'daki işler aşağıdakilerden oluşur:

  • Sıklık
    Bu, Cron işinin yürütülmesini programlamak için kullanılır. Programlar, bir Linux ortamında cron tablosunda arka plan işleri oluşturulurken orijinal olarak kullanılan unix-cron formatı kullanılarak belirlenir. Unix-cron formatı, her biri bir zaman noktasını temsil eden beş değer içeren bir dizeden oluşur. Aşağıda beş dizenin her birini ve temsil ettikleri değerleri görebiliriz.
 - - - - - - - - - - - - - - - - minute ( - 59 ) | - - - - - - - - - - - - - hour ( 0 - 23 ) | | - - - - - - - - - - - - day of month ( 1 - 31 ) | | | - - - - - - - - - month ( 1 - 12 ) | | | | - - - - - -- day of week ( 0 - 6 ) | | | | | | | | | | | | | | | | | | | | | | | | | * * * * *

Bir iş için bir frekans-zaman değeri oluşturmaya çalışırken Crontab oluşturucu aracı kullanışlı olur. Zaman değerlerini bir araya getirmeyi zor buluyorsanız, Crontab oluşturucu bir çizelge oluşturan değerleri seçebileceğiniz ve oluşturulan değeri kopyalayıp frekans olarak kullanabileceğiniz görsel bir açılır menüye sahiptir.

  • Saat dilimi
    cron işinin yürütüldüğü saat dilimi. Zaman dilimleri arasındaki zaman farkı nedeniyle, belirtilen farklı zaman dilimleriyle yürütülen cron işlerinin yürütme süreleri farklı olacaktır.
  • Hedef
    Belirtilen İşin yürütülmesinde kullanılan budur. Hedef, işin belirtilen zamanda URL'ye istekte bulunduğu bir HTTP türü veya işin mesaj yayınlayabileceği veya buradan mesaj çekebileceği bir Pub/Sub konusu ve son olarak bir App Engine Uygulaması olabilir.

Bulut Zamanlayıcı, HTTP ile tetiklenen Bulut İşlevleri ile mükemmel bir şekilde birleşir. Bulut Zamanlayıcı içinde hedefi HTTP olarak ayarlanmış bir iş oluşturulduğunda, bu iş bir bulut işlevini yürütmek için kullanılabilir. Yapılması gereken tek şey, bulut işlevinin uç noktasını belirlemek, isteğin HTTP fiilini belirlemek ve ardından görüntülenen gövde alanına işlev için iletilmesi gereken verileri eklemek. Aşağıdaki örnekte gösterildiği gibi:

Bulut konsolunu kullanarak bir cron işi oluşturmak için gerekli alanlar
Bulut konsolunu kullanarak bir cron işi oluşturmak için gerekli alanlar. (Büyük önizleme)

Yukarıdaki resimdeki cron işi, bir bulut işlevinin örnek uç noktasına bir POST isteğinde bulunarak her gün sabah 9'da çalışır.

Bir cron işinin daha gerçekçi bir kullanım durumu, Mailgun gibi harici bir posta hizmeti kullanarak kullanıcılara belirli aralıklarla planlanmış e-postalar göndermektir. Bunu çalışırken görmek için, Mailgun'a bağlanmak için nodemailer JavaScript paketini kullanarak belirli bir e-posta adresine bir HTML e-postası gönderen yeni bir bulut işlevi oluşturacağız:

 # index.js require("dotenv").config(); const nodemailer = require("nodemailer"); exports.Emailer = (req, res) => { let sender = process.env.SENDER; const { reciever, type } = req.body var transport = nodemailer.createTransport({ host: process.env.HOST, port: process.env.PORT, secure: false, auth: { user: process.env.SMTP_USERNAME, pass: process.env.SMTP_PASSWORD, }, }); if (!reciever) { res.status(400).send({ error: `Empty email address` }); } transport.verify(function (error, success) { if (error) { res .status(401) .send({ error: `failed to connect with stmp. check credentials` }); } }); switch (type) { case "statistics": return transport.sendMail( { from: sender, to: reciever, subject: "Your usage satistics of demo app", html: { path: "./welcome.html" }, }, (error, info) => { if (error) { res.status(401).send({ error : error }); } transport.close(); res.status(200).send({data : info}); } ); default: res.status(500).send({ error: "An available email template type has not been matched.", }); } };

Using the cloud function above we can send an email to any user's email address specified as the receiver value in the request body. It performs the sending of emails through the following steps:

  • It creates an SMTP transport for sending messages by passing the host , user and pass which stands for password, all displayed on the user's Mailgun dashboard when a new account is created.
  • Next, it verifies if the SMTP transport has the credentials needed in order to establish a connection. If there's an error in establishing the connection, it ends the function's invocation and sends back a 401 unauthenticated status code.
  • Next, it calls the sendMail method to send the email containing the HTML file as the email's body to the receiver's email address specified in the to field.

Note : We use a switch statement in the cloud function above to make it more reusable for sending several emails for different recipients. This way we can send different emails based on the type field included in the request body when calling this cloud function.

Now that there is a function that can send an email to a user; we are left with creating the cron job to invoke this cloud function. This time, the cron jobs are created dynamically each time a new user is created using the official Google cloud client library for the Cloud Scheduler from the initial firestoreFunction .

We expand the CREATE-USER case to create the job which sends the email to the created user at a one-day interval.

 require("dotenv").config();cloc const { Firestore } = require("@google-cloud/firestore"); const scheduler = require("@google-cloud/scheduler") const cors = require("cors")({ origin: true }); const EMAILER = proccess.env.EMAILER_ENDPOINT const parent = ScheduleClient.locationPath( process.env.PROJECT_ID, process.env.LOCATION_ID ); exports.firestoreFunction = function (req, res) { return cors(req, res, () => { const { email, password, type } = req.body; const firestore = new Firestore(); const document = firestore.collection("users"); const client = new Scheduler.CloudSchedulerClient() if (!type) { res.status(422).send({ error : "An action type was not specified"}); } switch (type) { case "CREATE-USER":

      const job = { httpTarget: { uri: process.env.EMAIL_FUNCTION_ENDPOINT, httpMethod: "POST", body: { email: email, }, }, schedule: "*/30 */6 */5 10 4", timezone: "Africa/Lagos", }
 if (!email || !password) { res.status(422).send("email and password fields missing"); } return bcrypt.genSalt(10, (err, salt) => { bcrypt.hash(password, salt, (err, hash) => { document .add({ email: email, password: hash, }) .then((response) => {
                  client.createJob({ parent : parent, job : job }).then(() => res.status(200).send(response)) .catch(e => console.log(`unable to create job : ${e}`) )
 }) .catch((e) => res.status(501).send(`error inserting data : ${e}`) ); }); }); default: res.status(422).send(`${type} is not a valid function action`) } }); };

From the snippet above, we can see the following:

  • A connection to the Cloud Scheduler from the Scheduler constructor using the Application Default Credentials (ADC) is made.
  • We create an object consisting of the following details which make up the cron job to be created:
    • uri
      The endpoint of our email cloud function in which a request would be made to.
    • body
      This is the data containing the email address of the user to be included when the request is made.
    • schedule
      The unix cron format representing the time when this cron job is to be performed.
  • After the promise from inserting the user's data document is resolved, we create the cron job by calling the createJob method and passing in the job object and the parent.
  • The function's execution is ended with a 200 status code after the promise from the createJob operation has been resolved.

After the job is created, we'll see it listed on the scheduler page.

List of all scheduled cron jobs including the last created job.
List of all scheduled cron jobs including the last created job. (Büyük önizleme)

From the image above we can see the time scheduled for this job to be executed. We can decide to manually run this job or wait for it to be executed at the scheduled time.

Çözüm

Within this article, we have had a good look into serverless applications and the benefits of using them. We also had an extensive look at how developers can manage their serverless applications on the Google Cloud using Cloud Functions so you now know how the Google Cloud is supporting the use of serverless applications.

Within the next years to come, we will certainly see a large number of developers adapt to the use of serverless applications when building applications. If you are using cloud functions in a production environment, it is recommended that you read this article from a Google Cloud advocate on “6 Strategies For Scaling Your Serverless Applications”.

The source code of the created cloud functions are available within this Github repository and also the used front-end application within this Github repository. The front-end application has been deployed using Netlify and can be tested live here.

Referanslar

  • Google Bulut
  • Cloud Functions
  • Cloud Source Repositories
  • Cloud Scheduler overview
  • Bulut Firestore
  • “6 Strategies For Scaling Your Serverless Applications,” Preston Holmes