অ্যাপ ইঞ্জিন ব্লবস্টোর থেকে ক্লাউড স্টোরেজে স্থানান্তর করুন (মডিউল 16)

1. ওভারভিউ

কোডল্যাবগুলির সার্ভারলেস মাইগ্রেশন স্টেশন সিরিজ (স্ব-গতিসম্পন্ন, হ্যান্ড-অন টিউটোরিয়াল) এবং সম্পর্কিত ভিডিওগুলির লক্ষ্য হল Google ক্লাউড সার্ভারহীন বিকাশকারীদের তাদের অ্যাপ্লিকেশনগুলিকে এক বা একাধিক মাইগ্রেশনের মাধ্যমে গাইড করে আধুনিকীকরণ করতে সাহায্য করা, প্রাথমিকভাবে উত্তরাধিকার পরিষেবাগুলি থেকে দূরে সরে যাওয়া৷ এটি করা আপনার অ্যাপগুলিকে আরও বহনযোগ্য করে তোলে এবং আপনাকে আরও বিকল্প এবং নমনীয়তা দেয়, যা আপনাকে ক্লাউড পণ্যগুলির একটি বিস্তৃত পরিসরের সাথে একীভূত করতে এবং অ্যাক্সেস করতে এবং আরও সহজে নতুন ভাষা প্রকাশগুলিতে আপগ্রেড করতে সক্ষম করে৷ প্রাথমিকভাবে প্রথম দিকের ক্লাউড ব্যবহারকারীদের উপর ফোকাস করার সময়, প্রাথমিকভাবে অ্যাপ ইঞ্জিন (স্ট্যান্ডার্ড এনভায়রনমেন্ট) ডেভেলপারদের, এই সিরিজটি ক্লাউড ফাংশন এবং ক্লাউড রানের মতো অন্যান্য সার্ভারহীন প্ল্যাটফর্মগুলিকে অন্তর্ভুক্ত করার জন্য যথেষ্ট বিস্তৃত, বা অন্য কোথাও প্রযোজ্য হলে।

এই কোডল্যাব আপনাকে শেখায় কিভাবে অ্যাপ ইঞ্জিন ব্লবস্টোর থেকে ক্লাউড স্টোরেজে স্থানান্তর করতে হয়। এছাড়াও এর থেকে অন্তর্নিহিত স্থানান্তর রয়েছে:

আরও ধাপে ধাপে তথ্যের জন্য যেকোনো সম্পর্কিত মাইগ্রেশন মডিউল পড়ুন।

আপনি কিভাবে শিখবেন

  • অ্যাপ ইঞ্জিন ব্লবস্টোর API/লাইব্রেরির ব্যবহার যোগ করুন
  • ব্লবস্টোর পরিষেবাতে ব্যবহারকারীর আপলোডগুলি সংরক্ষণ করুন৷
  • ক্লাউড স্টোরেজে মাইগ্রেট করার জন্য পরবর্তী ধাপের জন্য প্রস্তুত হন

আপনি কি প্রয়োজন হবে

সমীক্ষা

আপনি কিভাবে এই টিউটোরিয়াল ব্যবহার করবেন?

শুধুমাত্র মাধ্যমে এটি পড়ুন এটি পড়ুন এবং ব্যায়াম সম্পূর্ণ করুন

পাইথনের সাথে আপনার অভিজ্ঞতাকে আপনি কীভাবে মূল্যায়ন করবেন?

নবজাতক মধ্যবর্তী দক্ষ

আপনি Google ক্লাউড পরিষেবাগুলি ব্যবহার করার সাথে আপনার অভিজ্ঞতাকে কীভাবে মূল্যায়ন করবেন?

নবজাতক মধ্যবর্তী দক্ষ

2. পটভূমি

এই কোডল্যাবটি মডিউল 15 থেকে নমুনা অ্যাপ দিয়ে শুরু হয় এবং ব্লবস্টোর (এবং এনডিবি) থেকে ক্লাউড স্টোরেজে (এবং ক্লাউড এনডিবি) কীভাবে স্থানান্তর করতে হয় তা প্রদর্শন করে। মাইগ্রেশন প্রক্রিয়ার মধ্যে রয়েছে অ্যাপ ইঞ্জিনের লিগ্যাসি বান্ডেল করা পরিষেবাগুলির উপর নির্ভরতা প্রতিস্থাপন করা, যা আপনাকে আপনার অ্যাপগুলিকে অন্য ক্লাউড সার্ভারহীন প্ল্যাটফর্মে বা অন্য হোস্টিং প্ল্যাটফর্মে স্থানান্তর করার অনুমতি দেয় যদি ইচ্ছা হয়।

এই সিরিজের অন্যান্য মাইগ্রেশনের তুলনায় এই মাইগ্রেশনের জন্য একটু বেশি পরিশ্রমের প্রয়োজন। ব্লবস্টোরের মূল ওয়েবঅ্যাপ ফ্রেমওয়ার্কের উপর নির্ভরতা রয়েছে এবং সে কারণেই নমুনা অ্যাপটি ফ্লাস্কের পরিবর্তে webapp2 ফ্রেমওয়ার্ক ব্যবহার করে। এই টিউটোরিয়ালটিতে ক্লাউড স্টোরেজ, ক্লাউড এনডিবি, ফ্লাস্ক এবং পাইথন 3-এ স্থানান্তরিত করার বৈশিষ্ট্য রয়েছে।

অ্যাপটি এখনও শেষ-ব্যবহারকারীর "ভিজিট" নিবন্ধন করে এবং সাম্প্রতিক দশটি প্রদর্শন করে, তবে আগের (মডিউল 15) কোডল্যাব ব্লবস্টোর ব্যবহারের জন্য মিটমাট করার জন্য নতুন কার্যকারিতা যুক্ত করেছে: অ্যাপটি শেষ ব্যবহারকারীদের অনুরূপ একটি আর্টিফ্যাক্ট (একটি ফাইল) আপলোড করতে অনুরোধ করে তাদের "দর্শন।" ব্যবহারকারীরা তা করতে পারেন বা অপ্ট-আউট করতে "এড়িয়ে যান" নির্বাচন করতে পারেন৷ ব্যবহারকারীর সিদ্ধান্ত নির্বিশেষে, পরবর্তী পৃষ্ঠাটি এই অ্যাপের পূর্ববর্তী অবতারগুলির মতো একই আউটপুট রেন্ডার করে, সাম্প্রতিক পরিদর্শনগুলি প্রদর্শন করে৷ একটি অতিরিক্ত মোড় হল যে সংশ্লিষ্ট নিদর্শনগুলির সাথে ভিজিটগুলি একটি ভিজিটের আর্টিফ্যাক্ট প্রদর্শনের জন্য একটি "ভিউ" লিঙ্ক বৈশিষ্ট্যযুক্ত। এই কোডল্যাব বর্ণিত কার্যকারিতা সংরক্ষণ করার সময় পূর্বে উল্লিখিত স্থানান্তরগুলি প্রয়োগ করে।

3. সেটআপ/প্রিওয়ার্ক

আমরা টিউটোরিয়ালের মূল অংশে যাওয়ার আগে, আসুন আমাদের প্রকল্প সেট আপ করি, কোড পাই, তারপর বেসলাইন অ্যাপটি স্থাপন করি যাতে আমরা জানি যে আমরা কাজের কোড দিয়ে শুরু করেছি।

1. সেটআপ প্রকল্প

আপনি যদি ইতিমধ্যে মডিউল 15 অ্যাপ স্থাপন করে থাকেন, আমরা সেই একই প্রকল্প (এবং কোড) পুনরায় ব্যবহার করার পরামর্শ দিই। বিকল্পভাবে, আপনি একটি একেবারে নতুন প্রকল্প তৈরি করতে পারেন বা অন্য একটি বিদ্যমান প্রকল্প পুনরায় ব্যবহার করতে পারেন। প্রজেক্টের একটি সক্রিয় বিলিং অ্যাকাউন্ট আছে এবং অ্যাপ ইঞ্জিন চালু আছে তা নিশ্চিত করুন।

2. বেসলাইন নমুনা অ্যাপ পান

এই কোডল্যাবের পূর্বশর্তগুলির মধ্যে একটি হল একটি কার্যকরী মডিউল 15 নমুনা অ্যাপ থাকা। আপনার কাছে এটি না থাকলে, আপনি মডিউল 15 "START" ফোল্ডার থেকে এটি পেতে পারেন (নীচের লিঙ্ক)। এই কোডল্যাবটি আপনাকে প্রতিটি ধাপের মধ্য দিয়ে নিয়ে যায়, কোড দিয়ে শেষ করে যা মডিউল 16 "FINISH" ফোল্ডারে যা আছে তার অনুরূপ।

মডিউল 15 স্টার্টিং ফাইলের ডিরেক্টরিটি এইরকম হওয়া উচিত:

$ ls
README.md       app.yaml        main-gcs.py     main.py         templates

main-gcs.py ফাইলটি হল মডিউল 15 থেকে main.py এর একটি বিকল্প সংস্করণ যা প্রকল্পের ID: PROJECT_ID .appspot.com এর উপর ভিত্তি করে একটি অ্যাপের নির্ধারিত URL-এর ডিফল্ট থেকে আলাদা একটি ক্লাউড স্টোরেজ বাকেট নির্বাচন করার অনুমতি দেয়। এই ফাইলটি এই (মডিউল 16) কোডল্যাবে কোন অংশ গ্রহন করে না, অনুরূপ মাইগ্রেশন কৌশল ব্যতীত অন্য কোন ফাইলটি ইচ্ছা হলে প্রয়োগ করা যেতে পারে।

3. (পুনরায়) বেসলাইন অ্যাপ স্থাপন করুন

এখন চালানোর জন্য আপনার অবশিষ্ট প্রিওয়ার্ক পদক্ষেপগুলি:

  1. gcloud কমান্ড-লাইন টুলের সাথে নিজেকে পুনরায় পরিচিত করুন
  2. gcloud app deploy সাথে নমুনা অ্যাপটি পুনরায় স্থাপন করুন
  3. অ্যাপটি অ্যাপ ইঞ্জিনে সমস্যা ছাড়াই চলে তা নিশ্চিত করুন

একবার আপনি সফলভাবে এই পদক্ষেপগুলি সম্পাদন করেছেন এবং আপনার মডিউল 15 অ্যাপটি কাজ করে তা নিশ্চিত করুন। প্রারম্ভিক পৃষ্ঠাটি ব্যবহারকারীদের একটি ফর্মের সাথে স্বাগত জানায় যা একটি ভিজিট আর্টিফ্যাক্ট ফাইল আপলোড করার জন্য অনুরোধ করে একটি বিকল্প, একটি "এড়িয়ে যান" বোতাম, অপ্ট আউট করার জন্য:

f5b5f9f19d8ae978.png

একবার ব্যবহারকারীরা একটি ফাইল আপলোড করলে বা এড়িয়ে গেলে, অ্যাপটি পরিচিত "সবচেয়ে সাম্প্রতিক পরিদর্শন" পৃষ্ঠাটি রেন্ডার করে:

f5ac6b98ee8a34cb.png

একটি আর্টিফ্যাক্টের বৈশিষ্ট্যযুক্ত ভিজিটগুলিতে আর্টিফ্যাক্টটি প্রদর্শন (বা ডাউনলোড) করার জন্য ভিজিট টাইমস্ট্যাম্পের ডানদিকে একটি "ভিউ" লিঙ্ক থাকবে। একবার আপনি অ্যাপটির কার্যকারিতা নিশ্চিত করলে, আপনি অ্যাপ ইঞ্জিনের লিগ্যাসি পরিষেবাগুলি (webapp2, NDB, Blobstore) থেকে সমসাময়িক বিকল্পগুলিতে (ফ্লাস্ক, ক্লাউড এনডিবি, ক্লাউড স্টোরেজ) স্থানান্তর করতে প্রস্তুত৷

4. কনফিগারেশন ফাইল আপডেট করুন

আমাদের অ্যাপের আপডেট হওয়া সংস্করণের জন্য তিনটি কনফিগারেশন ফাইল কার্যকর হয়। প্রয়োজনীয় কাজগুলি হল:

  1. app.yaml এ বিল্ট-ইন থার্ড-পার্টি লাইব্রেরি আপডেট করার পাশাপাশি Python 3 মাইগ্রেশনের দরজা খোলা রেখে দিন
  2. একটি requirements.txt যোগ করুন, যা বিল্ট-ইন নয় এমন সমস্ত প্রয়োজনীয় লাইব্রেরি নির্দিষ্ট করে
  3. appengine_config.py যোগ করুন যাতে অ্যাপটি বিল্ট-ইন এবং নন-বিল্ট-ইন থার্ড-পার্টি লাইব্রেরি উভয়কেই সমর্থন করে

app.yaml

libraries বিভাগ আপডেট করে আপনার app.yaml ফাইল এডিট করুন। jinja2 সরান এবং grpcio , setuptools এবং ssl যোগ করুন। তিনটি লাইব্রেরির জন্য উপলব্ধ সর্বশেষ সংস্করণ চয়ন করুন। এছাড়াও পাইথন 3 runtime নির্দেশিকা যোগ করুন, কিন্তু মন্তব্য আউট. আপনার কাজ শেষ হলে, এটি এইরকম হওয়া উচিত (যদি আপনি পাইথন 3.9 নির্বাচন করেন):

আগে:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

libraries:
- name: jinja2
  version: latest

পরে:

#runtime: python39
runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

libraries:
- name: grpcio
  version: latest
- name: setuptools
  version: latest
- name: ssl
  version: latest

পরিবর্তনগুলি প্রাথমিকভাবে অ্যাপ ইঞ্জিন সার্ভারগুলিতে উপলব্ধ পাইথন 2 বিল্ট-ইন লাইব্রেরিগুলির সাথে মোকাবিলা করে (তাই আপনাকে সেগুলি স্ব-বান্ডিল করতে হবে না)। আমরা Jinja2 সরিয়ে দিয়েছি কারণ এটি ফ্লাস্কের সাথে আসে, যা আমরা reqs.txt এ যোগ করতে যাচ্ছি। যখনই Google ক্লাউড ক্লায়েন্ট লাইব্রেরি, যেমন ক্লাউড এনডিবি এবং ক্লাউড স্টোরেজের জন্য ব্যবহার করা হয়, তখন grpcio এবং সেটআপ টুলের প্রয়োজন হয়। অবশেষে, ক্লাউড স্টোরেজের জন্যই এসএসএল লাইব্রেরি প্রয়োজন। উপরে মন্তব্য করা রানটাইম নির্দেশিকাটি হল যখন আপনি এই অ্যাপটি পাইথন 3-এ পোর্ট করার জন্য প্রস্তুত। আমরা এই টিউটোরিয়ালের শেষে এই বিষয়টি কভার করব।

requirements.txt

ফ্লাস্ক ফ্রেমওয়ার্ক এবং ক্লাউড এনডিবি এবং ক্লাউড স্টোরেজ ক্লায়েন্ট লাইব্রেরিগুলির প্রয়োজনের জন্য একটি requirements.txt ফাইল যোগ করুন, যার কোনোটিই বিল্ট-ইন নয়। এই কন্টেন্ট দিয়ে ফাইল তৈরি করুন:

flask
google-cloud-ndb
google-cloud-storage

পাইথন 2 অ্যাপ ইঞ্জিন রানটাইমের জন্য নন-বিল্ট-ইন 3য়-পার্টি লাইব্রেরিগুলির স্ব-বান্ডলিং প্রয়োজন, তাই এই লাইব্রেরিগুলি lib ফোল্ডারে ইনস্টল করতে নিম্নলিখিত কমান্ডটি চালান:

pip install -t lib -r requirements.txt

যদি আপনার ডেভেলপমেন্ট মেশিনে পাইথন 2 এবং 3 উভয়ই থাকে, তাহলে এই লাইব্রেরিগুলির পাইথন 2 সংস্করণ পাওয়া নিশ্চিত করতে আপনাকে pip2 কমান্ড ব্যবহার করতে হতে পারে। একবার আপনি Python 3 এ আপগ্রেড করলে, আপনাকে আর স্ব-বান্ডেল করার দরকার নেই।

appengine_config.py

একটি appengine_config.py ফাইল যোগ করুন যা বিল্ট-ইন এবং নন-বিল্ট-ইন 3য়-পার্টি লাইব্রেরি সমর্থন করে। এই কন্টেন্ট দিয়ে ফাইল তৈরি করুন:

import pkg_resources
from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
# Add libraries to pkg_resources working set to find the distribution.
pkg_resources.working_set.add_entry(PATH)

এইমাত্র সম্পন্ন করা ধাপগুলি অ্যাপ ইঞ্জিন ডক্সের পাইথন 2 অ্যাপের জন্য লাইব্রেরি ইনস্টল করার জন্য তালিকাভুক্ত ধাপগুলির অনুরূপ বা অভিন্ন হওয়া উচিত, এবং আরও নির্দিষ্টভাবে, appengine_config.py এর বিষয়বস্তুগুলি ধাপ 5-এ যা আছে তার সাথে মেলে।

কনফিগারেশন ফাইলের কাজ সম্পূর্ণ হয়েছে, তাই অ্যাপ্লিকেশনে এগিয়ে যাওয়া যাক।

5. অ্যাপ্লিকেশন ফাইলগুলি পরিবর্তন করুন

আমদানি

main.py এর পরিবর্তনের প্রথম সেটের মধ্যে রয়েছে প্রতিস্থাপন করা সমস্ত জিনিস অদলবদল করা। এখানে কি পরিবর্তন হচ্ছে:

  1. webapp2 ফ্লাস্ক দ্বারা প্রতিস্থাপিত হয়
  2. webapp2_extras থেকে জিনজা 2 ব্যবহার করার পরিবর্তে, ফ্লাস্কের সাথে আসা জিঞ্জা 2 ব্যবহার করুন
  3. অ্যাপ ইঞ্জিন ব্লবস্টোর এবং এনডিবি ক্লাউড এনডিবি এবং ক্লাউড স্টোরেজ দ্বারা প্রতিস্থাপিত হয়েছে
  4. webapp ব্লবস্টোর হ্যান্ডলারগুলি io স্ট্যান্ডার্ড লাইব্রেরি মডিউল, ফ্লাস্ক এবং werkzeug ইউটিলিটিগুলির একটি কম্বো দ্বারা প্রতিস্থাপিত হয়
  5. ডিফল্টরূপে, ব্লবস্টোর আপনার অ্যাপের URL ( PROJECT_ID.appspot.com ) এর নামানুসারে একটি ক্লাউড স্টোরেজ বাকেট লিখে। যেহেতু আমরা ক্লাউড স্টোরেজ ক্লায়েন্ট লাইব্রেরিতে পোর্ট করছি, ঠিক একই বাকেটের নাম নির্দিষ্ট করতে প্রকল্প আইডি পেতে google.auth ব্যবহার করা হয়। (আপনি বালতির নাম পরিবর্তন করতে পারেন কারণ এটি আর হার্ডকোড করা হয়নি।)

আগে:

import webapp2
from webapp2_extras import jinja2
from google.appengine.ext import blobstore, ndb
from google.appengine.ext.webapp import blobstore_handlers

নীচের কোড স্নিপেট দিয়ে main.py এ বর্তমান আমদানি বিভাগ প্রতিস্থাপন করে উপরের তালিকার পরিবর্তনগুলি বাস্তবায়ন করুন।

পরে:

import io

from flask import (Flask, abort, redirect, render_template,
        request, send_file, url_for)
from werkzeug.utils import secure_filename

import google.auth
from google.cloud import exceptions, ndb, storage

প্রাথমিককরণ এবং অপ্রয়োজনীয় Jinja2 সমর্থন

প্রতিস্থাপন করার জন্য কোডের পরবর্তী ব্লক হল BaseHandler webapp2_extras থেকে Jinja2 এর ব্যবহার নির্দিষ্ট করে। এটি অপ্রয়োজনীয় কারণ জিনজা 2 ফ্লাস্কের সাথে আসে এবং এটি এটির ডিফল্ট টেমপ্লেটিং ইঞ্জিন, তাই এটি সরিয়ে দিন।

মডিউল 16 এর দিকে, পুরানো অ্যাপে আমাদের কাছে থাকা বস্তুগুলিকে তাৎক্ষণিকভাবে দেখান। এর মধ্যে রয়েছে ফ্লাস্ক অ্যাপ শুরু করা এবং ক্লাউড এনডিবি এবং ক্লাউড স্টোরেজের জন্য এপিআই ক্লায়েন্ট তৈরি করা। অবশেষে, আমরা আমদানি বিভাগে উপরে বর্ণিত ক্লাউড স্টোরেজ বাকেটের নামটি একসাথে রাখি। এই আপডেটগুলি বাস্তবায়নের আগে এবং পরে এখানে রয়েছে:

আগে:

class BaseHandler(webapp2.RequestHandler):
    'Derived request handler mixing-in Jinja2 support'
    @webapp2.cached_property
    def jinja2(self):
        return jinja2.get_jinja2(app=self.app)

    def render_response(self, _template, **context):
        self.response.write(self.jinja2.render_template(_template, **context))

পরে:

app = Flask(__name__)
ds_client = ndb.Client()
gcs_client = storage.Client()
_, PROJECT_ID = google.auth.default()
BUCKET = '%s.appspot.com' % PROJECT_ID

ডেটাস্টোর অ্যাক্সেস আপডেট করুন

ক্লাউড এনডিবি বেশিরভাগ অ্যাপ ইঞ্জিন এনডিবির সাথে সামঞ্জস্যপূর্ণ। একটি পার্থক্য ইতিমধ্যে আচ্ছাদিত একটি API ক্লায়েন্ট প্রয়োজন. আরেকটি হল পরেরটির জন্য ডেটাস্টোর অ্যাক্সেস API ক্লায়েন্টের পাইথন প্রসঙ্গ পরিচালক দ্বারা নিয়ন্ত্রিত হওয়া প্রয়োজন। মূলত, এর অর্থ হল ক্লাউড এনডিবি ক্লায়েন্ট লাইব্রেরি ব্যবহার করে সমস্ত ডেটাস্টোর অ্যাক্সেস কল শুধুমাত্র ব্লক with পাইথনের মধ্যে ঘটতে পারে।

এটি একটি পরিবর্তন; অন্যটি হল ব্লবস্টোর এবং এর বস্তুগুলি, যেমন, BlobKey s, ক্লাউড স্টোরেজ দ্বারা সমর্থিত নয়, তাই পরিবর্তে file_blob একটি ndb.StringProperty হিসাবে পরিবর্তন করুন। নীচে ডেটা মডেল ক্লাস এবং আপডেট করা store_visit() এবং fetch_visits() ফাংশনগুলি এই পরিবর্তনগুলিকে প্রতিফলিত করে:

আগে:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)
    file_blob = ndb.BlobKeyProperty()

def store_visit(remote_addr, user_agent, upload_key):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent),
            file_blob=upload_key).put()

def fetch_visits(limit):
    'get most recent visits'
    return Visit.query().order(-Visit.timestamp).fetch(limit)

পরে:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)
    file_blob = ndb.StringProperty()

def store_visit(remote_addr, user_agent, upload_key):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent),
                file_blob=upload_key).put()

def fetch_visits(limit):
    'get most recent visits'
    with ds_client.context():
        return Visit.query().order(-Visit.timestamp).fetch(limit)

এখানে এখন পর্যন্ত করা পরিবর্তনগুলির একটি সচিত্র উপস্থাপনা রয়েছে:

a8f74ca392275822.png

হ্যান্ডলার আপডেট করা হচ্ছে

আপলোড হ্যান্ডলার

webapp2 এর হ্যান্ডলাররা ক্লাস হয় যখন তারা ফ্লাস্কে কাজ করে। HTTP ক্রিয়া পদ্ধতির পরিবর্তে, Flask ফাংশনটি সাজাতে ক্রিয়া ব্যবহার করে। ব্লবস্টোর এবং এর webapp হ্যান্ডলারগুলিকে ক্লাউড স্টোরেজ এবং ফ্লাস্ক এবং এর ইউটিলিটিগুলির কার্যকারিতা দ্বারা প্রতিস্থাপিত করা হয়েছে:

আগে:

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    'Upload blob (POST) handler'
    def post(self):
        uploads = self.get_uploads()
        blob_id = uploads[0].key() if uploads else None
        store_visit(self.request.remote_addr, self.request.user_agent, blob_id)
        self.redirect('/', code=307)

পরে:

@app.route('/upload', methods=['POST'])
def upload():
    'Upload blob (POST) handler'
    fname = None
    upload = request.files.get('file', None)
    if upload:
        fname = secure_filename(upload.filename)
        blob = gcs_client.bucket(BUCKET).blob(fname)
        blob.upload_from_file(upload, content_type=upload.content_type)
    store_visit(request.remote_addr, request.user_agent, fname)
    return redirect(url_for('root'), code=307)

এই আপডেট সম্পর্কিত কিছু নোট:

  • একটি blob_id এর পরিবর্তে, ফাইল আর্টিফ্যাক্টগুলি এখন ফাইলের নাম ( fname ) দ্বারা চিহ্নিত করা হয় যদি উপস্থিত থাকে এবং অন্যথায় None (ব্যবহারকারী একটি ফাইল আপলোড করা থেকে অপ্ট আউট করেন)৷
  • ব্লবস্টোর হ্যান্ডলাররা তার ব্যবহারকারীদের কাছ থেকে আপলোড প্রক্রিয়াটি বিমূর্ত করে দেয়, কিন্তু ক্লাউড স্টোরেজ তা করে না, তাই আপনি নতুন-সংযোজিত কোডটি দেখতে পারেন যা ফাইলের ব্লব অবজেক্ট এবং অবস্থান (বালতি) সেট করে এবং সেই সাথে কল যা প্রকৃত আপলোড সম্পাদন করে। ( upload_from_file() )।
  • webapp2 অ্যাপ্লিকেশন ফাইলের নীচে একটি রাউটিং টেবিল ব্যবহার করে যখন প্রতিটি সজ্জিত হ্যান্ডলারে ফ্লাস্ক রুট পাওয়া যায়।
  • উভয় হ্যান্ডলারই একটি HTTP 307 রিটার্ন কোড সহ POST অনুরোধ সংরক্ষণ করার সময় হোম ( / ) এ পুনঃনির্দেশ করে তাদের কার্যকারিতা গুটিয়ে নেয়।

হ্যান্ডলার ডাউনলোড করুন

ডাউনলোড হ্যান্ডলার আপডেট করা আপলোড হ্যান্ডলারের অনুরূপ প্যাটার্ন অনুসরণ করে, শুধুমাত্র দেখার জন্য অনেক কম কোড আছে। ক্লাউড স্টোরেজ এবং ফ্লাস্ক সমতুল্য দিয়ে Blobstore এবং webapp কার্যকারিতা প্রতিস্থাপন করুন:

আগে:

class ViewBlobHandler(blobstore_handlers.BlobstoreDownloadHandler):
    'view uploaded blob (GET) handler'
    def get(self, blob_key):
        self.send_blob(blob_key) if blobstore.get(blob_key) else self.error(404)

পরে:

@app.route('/view/<path:fname>')
def view(fname):
    'view uploaded blob (GET) handler'
    blob = gcs_client.bucket(BUCKET).blob(fname)
    try:
        media = blob.download_as_bytes()
    except exceptions.NotFound:
        abort(404)
    return send_file(io.BytesIO(media), mimetype=blob.content_type)

এই আপডেটে নোট:

  • আবার, ফ্লাস্ক হ্যান্ডলারের ফাংশনগুলিকে তাদের রুট দিয়ে সাজায় যখন webapp এটি নীচের দিকে একটি রাউটিং টেবিলে করে, তাই পরবর্তীটির প্যাটার্ন ম্যাচিং সিনট্যাক্স ('/view/([^/]+)?' ) বনাম ফ্লাস্কের ( '/view/<path:fname>' )।
  • আপলোড হ্যান্ডলারের মতো, ব্লবস্টোর হ্যান্ডলারদের দ্বারা বিমূর্ত কার্যকারিতার জন্য ক্লাউড স্টোরেজের দিকে আরও কিছু কাজ করতে হবে, যেমন প্রশ্নে থাকা ফাইল (ব্লব) সনাক্ত করা এবং স্পষ্টভাবে বাইনারি বনাম ব্লবস্টোর হ্যান্ডলারের একক send_blob() পদ্ধতি ডাউনলোড করা। কল
  • উভয় ক্ষেত্রেই, একটি HTTP 404 ত্রুটি ব্যবহারকারীকে ফেরত দেওয়া হয় যদি একটি আর্টিফ্যাক্ট পাওয়া না যায়।

প্রধান হ্যান্ডলার

প্রধান অ্যাপ্লিকেশনের চূড়ান্ত পরিবর্তনগুলি প্রধান হ্যান্ডলারে সঞ্চালিত হয়। webapp2 HTTP ক্রিয়া পদ্ধতিগুলি তাদের কার্যকারিতা একত্রিত করে একটি একক ফাংশন দ্বারা প্রতিস্থাপিত হয়। MainHandler ক্লাসটিকে root() ফাংশন দিয়ে প্রতিস্থাপন করুন এবং webapp2 রাউটিং টেবিলটি সরান যা নীচে দেখানো হয়েছে:

আগে:

class MainHandler(BaseHandler):
    'main application (GET/POST) handler'
    def get(self):
        self.render_response('index.html',
                upload_url=blobstore.create_upload_url('/upload'))

    def post(self):
        visits = fetch_visits(10)
        self.render_response('index.html', visits=visits)

app = webapp2.WSGIApplication([
    ('/', MainHandler),
    ('/upload', UploadHandler),
    ('/view/([^/]+)?', ViewBlobHandler),
], debug=True)

পরে:

@app.route('/', methods=['GET', 'POST'])
def root():
    'main application (GET/POST) handler'
    context = {}
    if request.method == 'GET':
        context['upload_url'] = url_for('upload')
    else:
        context['visits'] = fetch_visits(10)
    return render_template('index.html', **context)

পৃথক get() এবং post() পদ্ধতির পরিবর্তে, এগুলি মূলত root() এ একটি if-else বিবৃতি। এছাড়াও, যেহেতু root() একটি একক ফাংশন, তাই GET এবং POST উভয়ের জন্য টেমপ্লেট রেন্ডার করার জন্য শুধুমাত্র একটি কল আছে যেখানে webapp2 এ এটি সত্যিই সম্ভব নয়।

এখানে main.py তে পরিবর্তনের এই দ্বিতীয় এবং চূড়ান্ত সেটটির একটি সচিত্র উপস্থাপনা রয়েছে:

5ec38818c32fec2.png

(ঐচ্ছিক) পিছনের সামঞ্জস্য "বর্ধিতকরণ"

সুতরাং উপরে তৈরি করা সমাধানটি পুরোপুরি কাজ করে... কিন্তু শুধুমাত্র যদি আপনি স্ক্র্যাচ থেকে শুরু করেন এবং ব্লবস্টোর দ্বারা তৈরি করা ফাইল না থাকে। যেহেতু আমরা BlobKey এর পরিবর্তে ফাইলের নাম দিয়ে ফাইল শনাক্ত করার জন্য অ্যাপটি আপডেট করেছি, তাই সম্পূর্ণ মডিউল 16 অ্যাপটি Blobstore ফাইল দেখতে সক্ষম হবে না। অন্য কথায়, আমরা এই স্থানান্তর সম্পাদন করার জন্য একটি পিছনের-অসঙ্গত পরিবর্তন করেছি। আমরা এখন main.py এর একটি বিকল্প সংস্করণ উপস্থাপন করছি যার নাম main-migrate.py (রেপোতে পাওয়া গেছে) যা এই ব্যবধান পূরণ করার চেষ্টা করে।

ব্লবস্টোর তৈরি করা ফাইলগুলিকে সমর্থন করার জন্য প্রথম "এক্সটেনশন" হল একটি ডেটা মডেল যার একটি BlobKeyProperty রয়েছে (ক্লাউড স্টোরেজ-তৈরি করা ফাইলগুলির জন্য একটি StringProperty ছাড়াও):

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)
    file_blob = ndb.BlobKeyProperty()  # backwards-compatibility
    file_gcs  = ndb.StringProperty()

ক্লাউড স্টোরেজ ফাইলের জন্য file_blob file_gcs ব্যবহার করা হবে ব্লবস্টোর তৈরি করা ফাইল শনাক্ত করতে। এখন নতুন ভিজিট তৈরি করার সময়, file_blob এর পরিবর্তে file_gcs এ স্পষ্টভাবে একটি মান সঞ্চয় করুন, তাই store_visit একটু ভিন্ন দেখায়:

আগে:

def store_visit(remote_addr, user_agent, upload_key):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent),
                file_blob=upload_key).put()

পরে:

def store_visit(remote_addr, user_agent, upload_key):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent),
                file_gcs=upload_key).put()

সাম্প্রতিক ভিজিটগুলি আনার সময়, টেমপ্লেটে পাঠানোর আগে ডেটা "সাধারণ করুন":

আগে:

@app.route('/', methods=['GET', 'POST'])
def root():
    'main application (GET/POST) handler'
    context = {}
    if request.method == 'GET':
        context['upload_url'] = url_for('upload')
    else:
        context['visits'] = fetch_visits(10)
    return render_template('index.html', **context)

পরে:

@app.route('/', methods=['GET', 'POST'])
def root():
    'main application (GET/POST) handler'
    context = {}
    if request.method == 'GET':
        context['upload_url'] = url_for('upload')
    else:
        context['visits'] = etl_visits(fetch_visits(10))
    return render_template('index.html', **context)

এর পরে, file_blob বা file_gcs (বা কোনটিই) এর অস্তিত্ব নিশ্চিত করুন। যদি একটি ফাইল উপলব্ধ থাকে, বিদ্যমান একটি বাছুন এবং সেই শনাক্তকারী ব্যবহার করুন ( Blobstore-তৈরি করা ফাইলগুলির জন্য BlobKey বা ক্লাউড স্টোরেজ-তৈরি ফাইলগুলির জন্য ফাইলের নাম)৷ যখন আমরা বলি "ক্লাউড স্টোরেজ-তৈরি করা ফাইল" আমরা বুঝি ক্লাউড স্টোরেজ ক্লায়েন্ট লাইব্রেরি ব্যবহার করে তৈরি করা ফাইল৷ ব্লবস্টোর ক্লাউড স্টোরেজকেও লেখে, তবে এই ক্ষেত্রে, সেগুলি হবে ব্লবস্টোর-তৈরি করা ফাইল।

এখন আরও গুরুত্বপূর্ণ, এই etl_visits() ফাংশনটি কী যা শেষ-ব্যবহারকারীর ডেটা স্বাভাবিক করতে বা ETL (এক্সট্রাক্ট, ট্রান্সফর্ম এবং লোড) করতে ব্যবহৃত হয়? এটি এই মত দেখায়:

def etl_visits(visits):
    return [{
            'visitor': v.visitor,
            'timestamp': v.timestamp,
            'file_blob': v.file_gcs if hasattr(v, 'file_gcs') \
                    and v.file_gcs else v.file_blob
            } for v in visits]

এটি সম্ভবত আপনি যা প্রত্যাশা করেছিলেন তার মতো দেখাচ্ছে: কোডটি সমস্ত ভিজিটের মাধ্যমে লুপ করে, এবং প্রতিটি ভিজিটের জন্য, ভিজিটর এবং টাইমস্ট্যাম্প ডেটা শব্দার্থে নেয়, তারপর file_gcs বা file_blob বিদ্যমান কিনা তা পরীক্ষা করে, এবং যদি তাই হয়, তাদের মধ্যে একটি বাছাই করা (বা None হলে কোনটিরই অস্তিত্ব নেই)।

এখানে main.py এবং main-migrate.py এর মধ্যে পার্থক্যের একটি দৃষ্টান্ত রয়েছে:

718b05b2adadb2e1.png

আপনি যদি ব্লবস্টোর-তৈরি করা ফাইলগুলি ছাড়াই স্ক্র্যাচ থেকে শুরু করেন তবে main.py ব্যবহার করুন, কিন্তু আপনি যদি ট্রানজিশন করছেন এবং Blobstore এবং ক্লাউড স্টোরেজ উভয়ের দ্বারা তৈরি করা সমর্থনকারী ফাইল চান, তাহলে কীভাবে মোকাবেলা করবেন তার উদাহরণ হিসাবে main-migrate.py দেখুন আপনার নিজের অ্যাপের জন্য মাইগ্রেশনের পরিকল্পনা করতে সাহায্য করার মতো দৃশ্যের সাথে। জটিল স্থানান্তর করার সময়, বিশেষ ক্ষেত্রে উদ্ভূত হওয়ার সম্ভাবনা থাকে, তাই এই উদাহরণটি বাস্তব ডেটার সাথে বাস্তব অ্যাপগুলিকে আধুনিকীকরণের জন্য একটি বৃহত্তর সখ্যতা দেখানোর জন্য বোঝানো হয়েছে৷

6. সারাংশ/পরিষ্কার

এই বিভাগটি এই কোডল্যাবটিকে অ্যাপ স্থাপন করে, যাচাই করে এটিকে উদ্দেশ্য করে এবং যে কোনো প্রতিফলিত আউটপুটে কাজ করে। অ্যাপ্লিকেশান যাচাইকরণের পরে, যেকোন পরিচ্ছন্নতার পদক্ষেপগুলি সম্পাদন করুন এবং পরবর্তী পদক্ষেপগুলি বিবেচনা করুন৷

প্রয়োগ এবং আবেদন যাচাই

আপনার অ্যাপ পুনঃনিয়োগ করার আগে, lib ফোল্ডারে সেই স্ব-বান্ডেলড 3য়-পার্টি লাইব্রেরিগুলি পেতে pip install -t lib -r requirements.txt চালাতে ভুলবেন না। আপনি যদি পিছনের-সামঞ্জস্যপূর্ণ সমাধান চালাতে চান, তাহলে main-migrate.py প্রথমে main.py হিসাবে পুনঃনামকরণ করুন। এখন gcloud app deploy চালান, এবং নিশ্চিত করুন যে অ্যাপটি মডিউল 15 অ্যাপে একইভাবে কাজ করছে। ফর্ম পর্দা এই মত দেখায়:

f5b5f9f19d8ae978.png

সাম্প্রতিক পরিদর্শন পৃষ্ঠাটি এইরকম দেখাচ্ছে:

f5ac6b98ee8a34cb.png

ক্লাউড স্টোরেজের সাথে অ্যাপ ইঞ্জিন ব্লবস্টোর, ক্লাউড NDB-এর সাথে অ্যাপ ইঞ্জিন NDB, এবং ফ্লাস্কের সাথে webapp2 প্রতিস্থাপন করে এই কোডল্যাব সম্পূর্ণ করার জন্য অভিনন্দন। আপনার কোড এখন ফিনিশ (মডিউল 16) ফোল্ডারে যা আছে তার সাথে মেলে। বিকল্প main-migrate.py ও সেই ফোল্ডারে আছে।

পাইথন 3 "মাইগ্রেশন"

app.yaml এর শীর্ষে Python 3 runtime নির্দেশিকাটি মন্তব্য করা হয়েছে এই অ্যাপটিকে Python 3-এ পোর্ট করার জন্য যা প্রয়োজন। সোর্স কোডটি ইতিমধ্যেই Python 3 সামঞ্জস্যপূর্ণ, তাই সেখানে কোনও পরিবর্তনের প্রয়োজন নেই। এটিকে পাইথন 3 অ্যাপ হিসাবে স্থাপন করতে, নিম্নলিখিত পদক্ষেপগুলি সম্পাদন করুন:

  1. app.yaml এর শীর্ষে Python 3 runtime নির্দেশিকাটিকে মন্তব্য করুন।
  2. app.yaml এ অন্যান্য সমস্ত লাইন মুছুন।
  3. appengine_config.py ফাইলটি মুছুন। (পাইথন 3 রানটাইমে অব্যবহৃত)
  4. lib ফোল্ডারটি বিদ্যমান থাকলে মুছুন। (পাইথন 3 রানটাইমের সাথে অপ্রয়োজনীয়)

পরিষ্কার করুন

সাধারণ

আপনি যদি আপাতত কাজ শেষ করে থাকেন, তাহলে বিলিং এড়াতে আমরা আপনাকে আপনার অ্যাপ ইঞ্জিন অ্যাপটি অক্ষম করার পরামর্শ দিই। তবে আপনি যদি আরও কিছু পরীক্ষা বা পরীক্ষা করতে চান, অ্যাপ ইঞ্জিন প্ল্যাটফর্মের একটি বিনামূল্যের কোটা রয়েছে, এবং যতক্ষণ না আপনি সেই ব্যবহারের স্তরটি অতিক্রম না করেন, আপনাকে চার্জ করা উচিত নয়। এটি গণনার জন্য, তবে প্রাসঙ্গিক অ্যাপ ইঞ্জিন পরিষেবাগুলির জন্যও চার্জ হতে পারে, তাই আরও তথ্যের জন্য এর মূল্য পৃষ্ঠাটি দেখুন৷ যদি এই স্থানান্তরের সাথে অন্যান্য ক্লাউড পরিষেবা জড়িত থাকে, তবে সেগুলি আলাদাভাবে বিল করা হবে৷ উভয় ক্ষেত্রে, প্রযোজ্য হলে, নীচের "এই কোডল্যাবের জন্য নির্দিষ্ট" বিভাগটি দেখুন।

সম্পূর্ণ প্রকাশের জন্য, অ্যাপ ইঞ্জিনের মতো একটি Google ক্লাউড সার্ভারহীন গণনা প্ল্যাটফর্মে স্থাপন করার জন্য সামান্য বিল্ড এবং স্টোরেজ খরচ হয়। ক্লাউড স্টোরেজের মতো ক্লাউড বিল্ডের নিজস্ব ফ্রি কোটা রয়েছে। সেই ছবির সঞ্চয়স্থান সেই কোটার কিছু ব্যবহার করে। যাইহোক, আপনি এমন একটি অঞ্চলে বাস করতে পারেন যেখানে এই ধরনের বিনামূল্যের স্তর নেই, তাই সম্ভাব্য খরচ কমাতে আপনার স্টোরেজ ব্যবহার সম্পর্কে সচেতন থাকুন। নির্দিষ্ট ক্লাউড স্টোরেজ "ফোল্ডার" আপনার পর্যালোচনা করা উচিত:

  • console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
  • console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
  • উপরের সঞ্চয়স্থানের লিঙ্কগুলি আপনার PROJECT_ID এবং * LOC *করণের উপর নির্ভর করে, উদাহরণস্বরূপ, " us " যদি আপনার অ্যাপটি USA তে হোস্ট করা হয়৷

অন্যদিকে, আপনি যদি এই অ্যাপ্লিকেশন বা অন্যান্য সম্পর্কিত মাইগ্রেশন কোডল্যাবগুলি চালিয়ে যেতে না চান এবং সবকিছু সম্পূর্ণরূপে মুছে ফেলতে চান, তাহলে আপনার প্রকল্পটি বন্ধ করুন

এই কোডল্যাবের জন্য নির্দিষ্ট

নীচে তালিকাভুক্ত পরিষেবাগুলি এই কোডল্যাবের জন্য অনন্য৷ আরও তথ্যের জন্য প্রতিটি পণ্যের ডকুমেন্টেশন পড়ুন:

মনে রাখবেন যে আপনি যদি মডিউল 15 থেকে 16 তে স্থানান্তরিত হন, তবে আপনার কাছে এখনও ব্লবস্টোরে ডেটা থাকবে, তাই কেন আমরা উপরে এর মূল্যের তথ্য অন্তর্ভুক্ত করি।

পরবর্তী পদক্ষেপ

এই টিউটোরিয়ালের বাইরে, অন্যান্য মাইগ্রেশন মডিউল যা বিবেচনা করার জন্য লিগ্যাসি বান্ডিল পরিষেবাগুলি থেকে দূরে সরে যাওয়ার উপর ফোকাস করে:

  • মডিউল 2 : App Engine ndb থেকে Cloud NDB-তে স্থানান্তর করুন
  • মডিউল 7-9 : অ্যাপ ইঞ্জিন টাস্ক কিউ পুশ টাস্কগুলি থেকে ক্লাউড টাস্কে স্থানান্তর করুন
  • মডিউল 12-13 : অ্যাপ ইঞ্জিন মেমক্যাশ থেকে ক্লাউড মেমোরিস্টোরে স্থানান্তর করুন
  • মডিউল 18-19 : অ্যাপ ইঞ্জিন টাস্ক কিউ (টাস্ক টাস্ক) থেকে ক্লাউড পাব/সাব-এ স্থানান্তর করুন

অ্যাপ ইঞ্জিন আর Google ক্লাউডে একমাত্র সার্ভারহীন প্ল্যাটফর্ম নয়। আপনার যদি একটি ছোট অ্যাপ ইঞ্জিন অ্যাপ থাকে বা যেটির কার্যকারিতা সীমিত থাকে এবং এটিকে একটি স্বতন্ত্র মাইক্রোসার্ভিসে পরিণত করতে চান, অথবা আপনি একাধিক পুনঃব্যবহারযোগ্য উপাদানে একটি মনোলিথিক অ্যাপকে বিচ্ছিন্ন করতে চান, তাহলে ক্লাউড ফাংশনে যাওয়ার বিষয়টি বিবেচনা করার জন্য এটি ভাল কারণ। কন্টেইনারাইজেশন যদি আপনার অ্যাপ্লিকেশন ডেভেলপমেন্ট ওয়ার্কফ্লো-এর অংশ হয়ে থাকে, বিশেষ করে যদি এটি একটি CI/CD (একটানা ইন্টিগ্রেশন/কন্টিনিউয়াস ডেলিভারি বা ডিপ্লয়মেন্ট) পাইপলাইন নিয়ে থাকে, তাহলে ক্লাউড রানে মাইগ্রেট করার কথা বিবেচনা করুন। এই পরিস্থিতিতে নিম্নলিখিত মডিউল দ্বারা আচ্ছাদিত করা হয়:

  • অ্যাপ ইঞ্জিন থেকে ক্লাউড ফাংশনে স্থানান্তর করুন: মডিউল 11 দেখুন
  • অ্যাপ ইঞ্জিন থেকে ক্লাউড রানে স্থানান্তরিত করুন: আপনার অ্যাপটিকে ডকারের সাথে কনটেইনারাইজ করতে মডিউল 4 দেখুন, অথবা কন্টেইনার, ডকার জ্ঞান, বা Dockerfile ছাড়াই এটি করতে মডিউল 5 দেখুন

অন্য সার্ভারহীন প্ল্যাটফর্মে স্যুইচ করা ঐচ্ছিক, এবং আমরা কোনো পরিবর্তন করার আগে আপনার অ্যাপ এবং ব্যবহারের ক্ষেত্রে সেরা বিকল্পগুলি বিবেচনা করার পরামর্শ দিই।

আপনি পরবর্তীতে যে মাইগ্রেশন মডিউলটি বিবেচনা করুন না কেন, সমস্ত সার্ভারলেস মাইগ্রেশন স্টেশন সামগ্রী (কোডল্যাব, ভিডিও, সোর্স কোড [যখন উপলব্ধ]) এর ওপেন সোর্স রেপোতে অ্যাক্সেস করা যেতে পারে। রেপোর README কোন মাইগ্রেশন বিবেচনা করতে হবে এবং মাইগ্রেশন মডিউলের কোন প্রাসঙ্গিক "অর্ডার" তার নির্দেশিকাও প্রদান করে।

7. অতিরিক্ত সম্পদ

কোডল্যাব সমস্যা/প্রতিক্রিয়া

আপনি যদি এই কোডল্যাবের সাথে কোনো সমস্যা খুঁজে পান, অনুগ্রহ করে ফাইল করার আগে প্রথমে আপনার সমস্যাটি অনুসন্ধান করুন। অনুসন্ধান এবং নতুন সমস্যা তৈরি করার লিঙ্ক:

মাইগ্রেশন সম্পদ

মডিউল 15 (স্টার্ট) এবং মডিউল 16 (ফিনিশ) এর জন্য রেপো ফোল্ডারগুলির লিঙ্কগুলি নীচের টেবিলে পাওয়া যাবে। এগুলি সমস্ত অ্যাপ ইঞ্জিন কোডল্যাব মাইগ্রেশনের জন্য রেপো থেকে অ্যাক্সেস করা যেতে পারে যা আপনি একটি জিপ ফাইল ক্লোন বা ডাউনলোড করতে পারেন।

কোডল্যাব

পাইথন 2

পাইথন 3

মডিউল 15

কোড

N/A

মডিউল 16 (এই কোডল্যাব)

কোড

(পাইথন 2 এর মতো)

অনলাইন সম্পদ

নীচে অনলাইন সংস্থান রয়েছে যা এই টিউটোরিয়ালের জন্য প্রাসঙ্গিক হতে পারে:

অ্যাপ ইঞ্জিন ব্লবস্টোর এবং ক্লাউড স্টোরেজ

অ্যাপ ইঞ্জিন প্ল্যাটফর্ম

অন্যান্য ক্লাউড তথ্য

পাইথন

ভিডিও

লাইসেন্স

এই কাজটি ক্রিয়েটিভ কমন্স অ্যাট্রিবিউশন 2.0 জেনেরিক লাইসেন্সের অধীনে লাইসেন্সপ্রাপ্ত।