Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Ruby

Google Cloud Functions पर Ruby में महारत हासिल करें: निर्बाध रूप से निर्माण, परीक्षण और तैनात करें

सर्वरलेस फंक्शन्स क्लाउड सेवाओं के विकास और तैनाती का एक नया प्रोग्रामिंग प्रतिमान है। एक सर्वरलेस दुनिया में, हम अपने बैकएंड सेवाओं के प्रोविजनिंग, मेंटेनेंस और स्केलिंग को क्लाउड प्रोवाइडर पर अमूर्त करते हैं। यह डेवलपर्स को एक विशिष्ट समस्या को हल करने पर ध्यान केंद्रित करने की अनुमति देकर डेवलपर उत्पादकता में काफी सुधार करता है। सर्वरलेस फंक्शन्स बनाने के कई फायदे और नुकसान हैं, लेकिन उन्हें बनाने में एक चीज पर विचार करना भाषा समर्थन है। हाल ही में, Google ने Google Cloud Functions के लिए Ruby 2.7 के समर्थन की घोषणा की, और इस लेख में, मैं Google Cloud Functions पर Ruby में एक सर्वरलेस फंक्शन के निर्माण, परीक्षण और तैनाती पर ध्यान केंद्रित करूंगा और सर्वरलेस फंक्शन्स के फायदे और नुकसान।

एक सर्वरलेस OTP सिस्टम का निर्माण

वन-टाइम पासवर्ड (OTP) छोटे संख्यात्मक कोड होते हैं जिनका उपयोग प्रमाणीकरण उद्देश्यों के लिए किया जाता है, जैसे जब आपका बैंक आपकी पहचान सत्यापित करने के लिए टेक्स्ट के माध्यम से एक OTP भेजता है।

इस लेख में, हम एक OTP फंक्शन का निर्माण करेंगे जो तीन मुख्य जिम्मेदारियों को संभालता है:

POST /otp: प्रदान किए गए phone_number पर एक OTP संदेश उत्पन्न करता है और भेजता है।

# Request
{ "phone_number": "+2347012345678" }

# Response
{ "status": true, "message": "OTP sent successfully", "data": { "phone_number": "+2347012345678", "otp": 6872, "expires_at": "2021-02-09 07:15:25 +0100" } }

PUT /otp/verify: उपयोगकर्ता द्वारा प्रदान किए गए OTP के विरुद्ध एक OTP को सत्यापित करता है।

# Request
{ "phone_number": "+2347012345678", "otp": 7116 }

# Response
{ "status": true, "message": "OTP verified", "data": {} }

PUT /otp/resend: प्रदान किए गए phone_number पर एक OTP उत्पन्न करने और पुनः भेजने का प्रयास करता है।

# Request
{ "phone_number": "+2347012345678" }

# Response
{ "status": true, "message": "OTP sent successfully", "data": { "phone_number": "+2347012345678", "otp": 8533, "expires_at": "2021-02-09 08:59:16 +0100" } }

सरलता के लिए, हमारा क्लाउड फंक्शन एक पूर्ण SQL या NoSQL डेटाबेस के बजाय Cloud MemoryStore (GCP पर Redis या Memcache) द्वारा समर्थित होगा। यह हमें स्टेटलेस वातावरण में साझा राज्यों के बारे में जानने में भी सक्षम करेगा।

Ruby के साथ Google Cloud Function लिखना

GCF में फंक्शन्स लिखने के लिए, हम Google Cloud टीम द्वारा GCF फंक्शन्स बनाने के लिए प्रदान किए गए Functions Framework पर भरोसा करेंगे (इस पर बाद में और अधिक)।

सबसे पहले, ऐप डायरेक्टरी बनाएं और डायरेक्टरी में प्रवेश करें।

mkdir otp-cloud-function && cd otp-cloud-function

अगला, अपना Gemfile बनाएं और इंस्टॉल करें।

अधिकांश मानक Ruby एप्लिकेशन की तरह, हम अपने फंक्शन की निर्भरताओं को प्रबंधित करने के लिए bundler का उपयोग करेंगे

source "https://rubygems.org"
# Core
gem "functions_framework", "~> 0.7"
# Twilio for Sms
gem 'twilio-ruby', '~> 5.43.0'
# Database
gem 'redis'
# Connection Pooling
gem 'connection_pool'
# Time management
gem 'activesupport'
# API Serialization
gem 'active_model_serializers', '~> 0.10.0'

group :development, :test do
  gem 'pry'
  gem 'rspec'
  gem 'rspec_junit_formatter'
  gem 'faker', '~> 2.11.0'
end
bundle install

फंक्शन बनाना

आम तौर पर, विभिन्न होस्टिंग वातावरण आपको एक अलग फाइल निर्दिष्ट करने की अनुमति देते हैं जहां आपके फंक्शन्स लिखे जाते हैं। हालांकि, Google Cloud Functions को इसकी आवश्यकता होती है कि यह आपके प्रोजेक्ट डायरेक्टरी के रूट में app.rb हो। अब, हम अपना फंक्शन लिखने के लिए तैयार हैं।

app.rb खोलें और फंक्शन बनाएं:

# Cloud Functions Entrypoint
require 'functions_framework'
require 'connection_pool'
require 'active_model_serializers'
require './lib/store'
require './lib/send_sms_notification'
require './lib/response'
require './lib/serializers/models/base_model'
require './lib/serializers/models/otp_response'
require './lib/serializers/application_serializer'
require './lib/serializers/base_model_serializer'
require './lib/serializers/otp_response_serializer'

FunctionsFramework.on_startup do |function|
  # Setup Shared Redis Client
  require 'redis'
  set_global :redis_client, ConnectionPool.new(size: 5, timeout: 5) { Redis.new }
end

# Define HTTP Function
FunctionsFramework.http "otp" do |request|
  store = Store.new(global(:redis_client))
  data = JSON.parse(request.body.read)
  
  if request.post? && request.path == '/otp'
    phone_number = data['phone_number']
    record = store.get(phone_number)
    unless record.nil? || record.expired?
      data = Models::OtpResponse.new(phone_number: phone_number, otp: record['otp'], expires_at: record['expires_at'])
      json = Response.generate_json(status: true, message: 'OTP previously sent', data: data)
      return json
    end
    
    otp = rand(1111..9999)
    record = store.set(phone_number, otp)
    SendSmsNotification.new(phone_number, otp).call
    data = Models::OtpResponse.new(phone_number: phone_number, otp: record['otp'], expires_at: record['expires_at'])
    Response.generate_json(status: true, message: 'OTP sent successfully', data: data)
    
  elsif request.put? && request.path == '/otp/verify'
    phone_number = data['phone_number']
    record = store.get(phone_number)
    if record.nil?
      return Response.generate_json(status: false, message: "OTP not sent to number")
    elsif record.expired?
      return Response.generate_json(status: false, message: 'OTP code expired')
    end
    
    is_verified = data['otp'] == record['otp']
    if is_verified
      return Response.generate_json(status: true, message: 'OTP verified')
    else
      return Response.generate_json(status: false, message: 'OTP does not match')
    end
    
  elsif request.put? && request.path == '/otp/resend'
    phone_number = data['phone_number']
    store.del(phone_number)
    otp = rand(1111..9999)
    record = store.set(phone_number, otp)
    SendSmsNotification.new(phone_number, otp).call
    data = Models::OtpResponse.new(phone_number: phone_number, otp: record['otp'], expires_at: record['expires_at'])
    json = Response.generate_json(status: true, message: 'OTP sent successfully', data: data)
  else
    Response.generate_json(status: false, message: 'Request method and path did not match')
  end
end

यह बहुत सारा कोड है, इसलिए हम इसे तोड़ देंगे:

  • Functions_Framework.on_startup कोड का एक ब्लॉक है जो फंक्शन्स द्वारा अनुरोधों को प्रोसेस करना शुरू करने से पहले प्रति Ruby इंस्टेंस चलता है। हमारे फंक्शन्स के कॉल होने से पहले किसी भी प्रकार के इनिशियलाइज़ेशन को चलाने के लिए यह आदर्श है। इस मामले में, मैं इसका उपयोग हमारे Redis सर्वर के लिए एक कनेक्शन पूल बनाने और साझा करने के लिए कर रहा हूं:

    set_global :redis_client, ConnectionPool.new(size: 5, timeout: 5) { Redis.new }

    यह हमें एकाधिक समवर्ती फंक्शन इनवोकेशन में Redis कनेक्शन ऑब्जेक्ट्स के पूल को बिना किसी डर के साझा करने में सक्षम बनाता है। कई स्टार्टअप परिभाषित किए जा सकते हैं। वे उस क्रम में चलेंगे जिसमें वे परिभाषित हैं। यह भी ध्यान रखना महत्वपूर्ण है कि Functions Framework फंक्शन पूरा होने के बाद चलाने के लिए कोई विशेष हुक प्रदान नहीं करता है।

  • Functions_Framework.http 'otp' do |request| हमारे फंक्शन्स के अनुरोध और प्रतिक्रिया प्रोसेसिंग को संभालता है। यह फंक्शन तीन अलग-अलग रूट पैटर्न का समर्थन करता है। अन्य प्रकार के फंक्शन्स (जैसे, Functions_Framework.cloud_event 'otp' do |event|) को परिभाषित करना संभव है जो अन्य Google सेवाओं से घटनाओं को संभालते हैं। एक ही फाइल में कई फंक्शन्स को परिभाषित करना भी संभव है लेकिन स्वतंत्र रूप से डेप्लॉय किया जाता है।

  • store = Store.new(global(:redis_client)) में, global विधि का उपयोग ग्लोबल साझा राज्य में संग्रहीत किसी भी ऑब्जेक्ट को पुनः प्राप्त करने के लिए किया जाता है। जैसा कि ऊपर उपयोग किया गया है, हम अपने startup ब्लॉक में परिभाषित कनेक्शन पूल से Redis क्लाइंट को पुनः प्राप्त करते हैं।

  • Response और Models::OtpResponse active_model_serializers के साथ प्रतिक्रिया सीरियलाइज़ेशन को संभालते हैं ताकि उचित रूप से फॉर्मेट किए गए JSON प्रतिक्रियाएं दी जा सकें।

स्थानीय रूप से हमारे फंक्शन का परीक्षण

Functions Framework लाइब्रेरी हमें क्लाउड पर तैनात करने से पहले अपने फंक्शन्स को स्थानीय रूप से आसानी से टेस्ट करने में सक्षम बनाती है। स्थानीय रूप से टेस्ट करने के लिए, हम चलाते हैं

bundle exec functions-framework-ruby --target=otp --port=3000

--target का उपयोग डेप्लॉय करने के लिए फंक्शन का चयन करने के लिए किया जाता है।

जबकि मैन्युअल टेस्टिंग बहुत अच्छी है, स्वचालित टेस्ट और सेल्फ-टेस्टिंग सॉफ्टवेयर टेस्टिंग में पवित्र कब्र है। Functions Framework Minitest और RSpec दोनों के लिए हेल्पर मेथड्स प्रदान करता है ताकि हमारे फंक्शन्स को http और cloudevents हैंडलर्स दोनों के लिए टेस्ट किया जा सके। यहां एक टेस्ट का उदाहरण है:

require './spec/spec_helper.rb'
require 'functions_framework/testing'

describe 'OTP Functions' do
  include FunctionsFramework::Testing
  
  describe 'Send OTP', redis: true do
    let(:phone_number) { "+2347012345678" }
    let(:body) { { phone_number: phone_number }.to_json }
    let(:headers) { ["Content-Type: application/json"] }
    
    it 'should send OTP successfully' do
      load_temporary "app.rb" do
        request = make_post_request "/otp", body, headers
        response = call_http "otp", request
        expect(response.status).to eq 200
        expect(response.content_type).to eq("application/json")
        parsed_response = JSON.parse(response.body.join)
        expect(parsed_response['status']).to eq true
        expect(parsed_response['message']).to eq 'OTP sent successfully'
      end
    end
  end
end

हमारे फंक्शन को तैनात करना

सबसे पहले, हमें Google Cloud Memorystore का उपयोग करके एक Redis सर्वर डेप्लॉय करने की आवश्यकता है, जिस पर हमारा फंक्शन निर्भर है। मैं यहां GCP पर Redis सर्वर को तैनात करने के तरीके पर आगे विस्तार से नहीं जाऊंगा, क्योंकि यह इस लेख के दायरे से बाहर है।

हमारे फंक्शन को Google Cloud Function के वातावरण में तैनात करने के कई तरीके हैं: अपनी मशीन से तैनात करना, GCP कंसोल से तैनात करना, और हमारे कोड रिपॉजिटरी से तैनात करना। आधुनिक सॉफ्टवेयर इंजीनियरिंग हमारे अधिकांश विकास के लिए CI/CD प्रक्रियाओं को प्रोत्साहित करती है, और इस लेख के उद्देश्य के लिए, मैं Github Actions का उपयोग करके deploy-cloud-functions के साथ Github से अपने क्लाउड फंक्शन को तैनात करने पर ध्यान केंद्रित करूंगा।

आइए अपनी डेप्लॉयमेंट फाइल (.github/workflows/deploy.yml) सेटअप करें।

name: Deployment
on:
  push:
    branches:
      - main
jobs:
  deploy:
    name: Function Deployment
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - id: deploy
        uses: google-github-actions/deploy-cloud-functions@main
        with:
          name: otp-cloud-function
          runtime: ruby26
          credentials: ${{ secrets.gcp_credentials }}
          env_vars: "TWILIO_ACCOUNT_SID=${{ secrets.TWILIO_ACCOUNT_SID }},TWILIO_AUTH_TOKEN=${{ secrets.TWILIO_AUTH_TOKEN }},TWILIO_PHONE_NUMBER=${{ secrets.TWILIO_PHONE_NUMBER }},REDIS_URL=${{ secrets.REDIS_URL }}"

पर्यावरण चर

उपरोक्त कोड में, अंतिम पंक्ति हमें पर्यावरण चर निर्दिष्ट करने की अनुमति देती है जो Google Cloud वातावरण में हमारे फंक्शन के लिए उपलब्ध होंगे। ध्यान दें कि सुरक्षा कारणों से, हम इन चरों को अपने कोड-बेस में उजागर नहीं कर रहे हैं; इसके बजाय, हम इस जानकारी को निजी रखने के लिए Github Actions सीक्रेट्स का उपयोग कर रहे हैं। यह जांचने के लिए कि क्या हमारे टोकन ठीक से तैनात किए गए हैं, नीचे दिखाए अनुसार Google Console में अपने क्लाउड फंक्शन की जांच करें:

Google Cloud Functions पर Ruby में महारत हासिल करें: निर्बाध रूप से निर्माण, परीक्षण और तैनात करें

प्रमाणीकरण

Cloud Functions Admin और Service Account User भूमिकाओं के साथ एक Service Account बनाएं।

एक सर्विस अकाउंट मशीन-टू-मशीन IAM के लिए उपयोग किया जाता है। इस प्रकार, जब एक सिस्टम, चाहे वह Google Cloud पर चल रहा हो या नहीं, Google Cloud पर दूसरे सिस्टम से बात करता है, तो हमारी Google संसाधन तक पहुंच का अनुरोध करने वाले की पहचान करने में मदद के लिए एक सर्विस अकाउंट की आवश्यकता होती है। Cloud Functions Admin और Service Account User भूमिकाएं हमें यह निर्धारित करने में सक्षम बनाती हैं कि उपयोगकर्ता संसाधन तक पहुंचने के लिए अधिकृत है या नहीं। इस परिदृश्य में, एक Github Action रनर Google Cloud के साथ संचार करता है, एक सर्विस अकाउंट के रूप में प्रमाणित होता है जिसमें हमारे फंक्शन को तैनात करने के लिए आवश्यक अनुमतियां होती हैं।

Google Cloud Functions पर Ruby में महारत हासिल करें: निर्बाध रूप से निर्माण, परीक्षण और तैनात करें

Google Cloud Functions पर Ruby में महारत हासिल करें: निर्बाध रूप से निर्माण, परीक्षण और तैनात करें

एक सर्विस अकाउंट कुंजी बनाएं, JSON डाउनलोड करें, और इसे GitHub Secrets में जोड़ें।

Google Cloud Functions पर Ruby में महारत हासिल करें: निर्बाध रूप से निर्माण, परीक्षण और तैनात करें

Google Cloud Functions पर Ruby में महारत हासिल करें: निर्बाध रूप से निर्माण, परीक्षण और तैनात करें

वोइला! 🎉 हमारा क्लाउड फंक्शन सफलतापूर्वक तैनात किया गया है।

क्लाउड फंक्शन्स सीमाएं बनाम AWS सीमाएं

दो सबसे बड़े सर्वरलेस फंक्शन प्रोवाइडर्स की विस्तृत तुलना नीचे दी गई है:

Google Cloud Functions पर Ruby में महारत हासिल करें: निर्बाध रूप से निर्माण, परीक्षण और तैनात करें

Functions Framework अनुबंध बनाम Serverless Framework

इस लेख में, हमने Google Cloud Functions के लिए क्लाउड फंक्शन्स बनाने पर ध्यान केंद्रित किया है। इस खंड में, मैं Functions Framework बनाम Serverless Framework के साथ निर्माण की तुलना करना चाहता हूं।

  • Serverless Framework serverless.yml पर आधारित है, जबकि Functions Framework Functions Framework Contract पर आधारित है, जिसका उपयोग Google Cloud इन्फ्रास्ट्रक्चर में सर्वरलेस फंक्शन्स को तैनात करने के लिए किया जाता है।
  • Serverless Framework के साथ, केवल कुछ उदाहरण हैं, और यह बिल्कुल स्पष्ट नहीं है कि Ruby के साथ विभिन्न Google सर्वरलेस वातावरण (क्लाउड फंक्शन्स, क्लाउड रन, और Knative वातावरण) में सर्वरलेस फंक्शन्स कैसे बनाएं और तैनात करें। Functions Framework Contract फंक्शन के साथ, इन विभिन्न Google उत्पादों में Ruby के साथ निर्माण सीधा है।
    • पिछले बिंदु से, Functions Framework Contract आपके फंक्शन के पीछे की भाषा को बदलना बहुत आसान बनाता है बिना आपके डेप्लॉयमेंट प्रक्रिया में बहुत कुछ बदले।
  • इस लेखन के अनुसार, Functions Framework केवल Google Cloud सर्वरलेस वातावरण और Knative वातावरण में अंतरसंचालनीयता का समर्थन करता है। Serverless Framework, हालांकि, कई प्रदाताओं में कई प्लेटफार्मों का समर्थन करता है।

संदर्भ के लिए, पूरा कोड यहां उपलब्ध है।

  1. Vue, Vuex, और रेल्स के साथ फुल-स्टैक डेवलपमेंट में महारत: एक स्केलेबल दृष्टिकोण Vue, Vuex, और रेल्स के साथ फुल-स्टैक डेवलपमेंट में महारत: एक स्केलेबल दृष्टिकोण

    स्केलेबिलिटी को ध्यान में रखते हुए फुल-स्टैक एप्लिकेशन बनाना डराने वाला हो सकता है, खासकर जब Vue और Vuex के नवीनतम संस्करण के साथ निर्माण किया जा रहा हो, जिसमें पूर्ण टाइपस्क्रिप्ट समर्थन है। यह लेख अपने पाठकों को Vuex 4.0 के साथ स्टेट मैनेजमेंट से लेकर API अनुरोधों और डेटाबेस इंटरैक्शन को संभालने त

  1. Fluentd और ObjectRocket के साथ हाइब्रिड क्लाउड लॉगिंग को सुव्यवस्थित करें Fluentd और ObjectRocket के साथ हाइब्रिड क्लाउड लॉगिंग को सुव्यवस्थित करें

    यह पोस्ट Hart Hoover और Ryan Walker द्वारा सह-लिखित है हाल ही में, Rackspace DevOps ऑटोमेशन टीम ने एक सेवा की घोषणा की जो New Relic से Rackspace सपोर्ट को अलर्ट भेजती है। ये अलर्ट हमारे DevOps इंजीनियरों के जवाब देने के लिए टिकट जनरेट करेंगे, ताकि हमारे ग्राहक 3 बजे अलर्ट जनरेट होने पर चैन की नींद

  1. Google Cloud Print समझाया: कहीं भी, कभी भी प्रिंट करें Google Cloud Print समझाया: कहीं भी, कभी भी प्रिंट करें

    Google Cloud Print Google द्वारा विकसित एक सेवा है जो आपको किसी भी डिवाइस से कहीं भी फाइल प्रिंट करने में मदद करती है। आपकी फाइलें क्लाउड के माध्यम से कनेक्ट करके आपके स्थान से दूर एक प्रिंटर द्वारा प्रिंट की जाएंगी। यह आपके ऑफिस असाइनमेंट, अपने बच्चों के लिए तस्वीरें और अपने प्रियजनों के लिए प्रिंट