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

1. সংক্ষিপ্ত বিবরণ

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

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

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

তুমি শিখবে কিভাবে

  • অ্যাপ ইঞ্জিন ব্লবস্টোর এপিআই/লাইব্রেরির ব্যবহার যোগ করুন
  • ব্যবহারকারীর আপলোডগুলি Blobstore পরিষেবাতে সংরক্ষণ করুন
  • ক্লাউড স্টোরেজে স্থানান্তরের পরবর্তী পদক্ষেপের জন্য প্রস্তুত হন

তোমার যা লাগবে

জরিপ

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

শুধু পুরোটা পড়ুন এটি পড়ুন এবং অনুশীলনগুলি সম্পূর্ণ করুন।

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

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

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

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

2. পটভূমি

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

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

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

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

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

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

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

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

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

মডিউল ১৫ এর স্টার্টিং ফাইলের ডিরেক্টরিটি এইরকম দেখাবে:

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

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

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

আপনার এখন কার্যকর করার জন্য বাকি প্রিওয়ার্ক ধাপগুলি:

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

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

f5b5f9f19d8ae978.png সম্পর্কে

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

f5ac6b98ee8a34cb.png সম্পর্কে

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

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

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

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

অ্যাপ.ইয়ামল

libraries বিভাগটি আপডেট করে আপনার app.yaml ফাইলটি সম্পাদনা করুন। jinja2 মুছে ফেলুন এবং grpcio , setuptools , এবং ssl যোগ করুন। তিনটি লাইব্রেরির জন্য উপলব্ধ সর্বশেষ সংস্করণটি চয়ন করুন। এছাড়াও Python 3 runtime নির্দেশিকা যোগ করুন, কিন্তু মন্তব্য করা হয়নি। আপনার কাজ শেষ হয়ে গেলে, এটি দেখতে এইরকম হওয়া উচিত (যদি আপনি Python 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 সরিয়ে দিয়েছি কারণ এটি Flask এর সাথে আসে, যা আমরা reqs.txt এ যুক্ত করতে যাচ্ছি। যখনই Google ক্লাউড ক্লায়েন্ট লাইব্রেরি, যেমন ক্লাউড NDB এবং ক্লাউড স্টোরেজের জন্য, ব্যবহার করা হয়, তখন grpcio এবং setuptools প্রয়োজন হয়। অবশেষে, ক্লাউড স্টোরেজের জন্য নিজেই ssl লাইব্রেরি প্রয়োজন। উপরে মন্তব্য করা রানটাইম নির্দেশিকাটি আপনি যখন এই অ্যাপটি Python 3 এ পোর্ট করার জন্য প্রস্তুত তখনই। আমরা এই টিউটোরিয়ালের শেষে এই বিষয়টি কভার করব।

requirements.txt ফাইল

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

flask
google-cloud-ndb
google-cloud-storage

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

pip install -t lib -r requirements.txt

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

অ্যাপইঞ্জিন_কনফিগ.পি

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

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)

এইমাত্র সম্পন্ন হওয়া ধাপগুলি App Engine ডক্সের Installing libraries for Python 2 apps বিভাগে তালিকাভুক্ত ধাপগুলির অনুরূপ বা অভিন্ন হওয়া উচিত, এবং আরও স্পষ্টভাবে বলতে গেলে, appengine_config.py এর বিষয়বস্তু ধাপ ৫-এ যা আছে তার সাথে মিল থাকা উচিত।

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

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

আমদানি

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

  1. webapp2 ফ্লাস্ক দ্বারা প্রতিস্থাপিত হয়
  2. webapp2_extras থেকে Jinja2 ব্যবহার করার পরিবর্তে, Flask এর সাথে আসা Jinja2 ব্যবহার করুন।
  3. অ্যাপ ইঞ্জিন ব্লবস্টোর এবং এনডিবি ক্লাউড এনডিবি এবং ক্লাউড স্টোরেজ দ্বারা প্রতিস্থাপিত হয়েছে।
  4. webapp ব্লবস্টোর হ্যান্ডলারগুলি io স্ট্যান্ডার্ড লাইব্রেরি মডিউল, ফ্লাস্ক এবং werkzeug ইউটিলিটিগুলির একটি কম্বো দ্বারা প্রতিস্থাপিত হয়।
  5. ডিফল্টরূপে, Blobstore আপনার অ্যাপের 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 এর ব্যবহার নির্দিষ্ট করে। এটি অপ্রয়োজনীয় কারণ Jinja2 Flask এর সাথে আসে এবং এটি এর ডিফল্ট টেমপ্লেটিং ইঞ্জিন, তাই এটি সরিয়ে ফেলুন।

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

আগে:

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 ক্লায়েন্টের পাইথন কনটেক্সট ম্যানেজার দ্বারা নিয়ন্ত্রিত হওয়া প্রয়োজন। মূলত, এর অর্থ হল ক্লাউড এনডিবি ক্লায়েন্ট লাইব্রেরি ব্যবহার করে সমস্ত ডেটাস্টোর অ্যাক্সেস কল কেবল ব্লক with পাইথনের মধ্যেই ঘটতে পারে।

এটি একটি পরিবর্তন; অন্যটি হল Blobstore এবং এর অবজেক্টগুলি, যেমন BlobKey , ক্লাউড স্টোরেজ দ্বারা সমর্থিত নয়, তাই 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 এর হ্যান্ডলারগুলো হলো ক্লাস, যখন Flask এ এগুলো হলো ফাংশন। HTTP ক্রিয়া পদ্ধতির পরিবর্তে, Flask ফাংশনটি সাজানোর জন্য ক্রিয়াপদটি ব্যবহার করে। Blobstore এবং এর webapp হ্যান্ডলারগুলো ক্লাউড স্টোরেজের কার্যকারিতা এবং Flask এবং এর ইউটিলিটি দ্বারা প্রতিস্থাপিত হয়:

আগে:

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

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

ডাউনলোড হ্যান্ডলার আপডেট করার পদ্ধতি আপলোড হ্যান্ডলারের মতোই, শুধুমাত্র দেখার জন্য অনেক কম কোড থাকে। ব্লবস্টোর এবং 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)

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

  • আবার, Flask হ্যান্ডলার ফাংশনগুলিকে তাদের রুট দিয়ে সাজায় যখন webapp নীচের রাউটিং টেবিলে এটি করে, তাই পরবর্তীটির প্যাটার্ন ম্যাচিং সিনট্যাক্স ('/view/([^/]+)?' ) বনাম Flask এর ( '/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 সম্পর্কে

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

তাহলে উপরে তৈরি করা সমাধানটি নিখুঁতভাবে কাজ করবে... কিন্তু শুধুমাত্র যদি আপনি শুরু থেকে শুরু করেন এবং Blobstore দ্বারা তৈরি ফাইল না থাকে। যেহেতু আমরা BlobKey এর পরিবর্তে filename দ্বারা ফাইল সনাক্ত করার জন্য অ্যাপটি আপডেট করেছি, তাই সম্পূর্ণ Module 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 প্রোপার্টিটি Blobstore-তৈরি ফাইলগুলি সনাক্ত করতে ব্যবহৃত হবে যখন 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 (অথবা কোনটিই নয়) এর অস্তিত্ব নিশ্চিত করুন। যদি কোন ফাইল উপলব্ধ থাকে, তাহলে বিদ্যমান একটিটি বেছে নিন এবং সেই শনাক্তকারীটি ব্যবহার করুন ( BlobKey for Blobstore-created files অথবা filename for Cloud Storage-created files)। যখন আমরা "Cloud Storage-created files" বলি, তখন আমরা Cloud Storage ক্লায়েন্ট লাইব্রেরি ব্যবহার করে তৈরি করা ফাইলগুলিকে বোঝাই। Blobstore ক্লাউড স্টোরেজকেও লেখে, তবে এই ক্ষেত্রে, সেগুলি Blobstore-created files হবে।

এখন আরও গুরুত্বপূর্ণ বিষয় হল, এই 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 সম্পর্কে

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

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

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

অ্যাপ্লিকেশন স্থাপন এবং যাচাই করুন

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

f5b5f9f19d8ae978.png সম্পর্কে

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

f5ac6b98ee8a34cb.png সম্পর্কে

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

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

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

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

পরিষ্কার কর

সাধারণ

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

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

  • 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 *ation এর উপর নির্ভর করে, উদাহরণস্বরূপ, " us " যদি আপনার অ্যাপটি মার্কিন যুক্তরাষ্ট্রে হোস্ট করা হয়।

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

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

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

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

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

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

  • মডিউল ২ : অ্যাপ ইঞ্জিন ndb থেকে ক্লাউড এনডিবিতে স্থানান্তর
  • মডিউল ৭-৯ : অ্যাপ ইঞ্জিন টাস্ক কিউ থেকে ক্লাউড টাস্কে পুশ টাস্ক স্থানান্তর করুন
  • মডিউল ১২-১৩ : অ্যাপ ইঞ্জিন মেমক্যাশ থেকে ক্লাউড মেমোরিস্টোরে স্থানান্তর করুন
  • মডিউল ১৮-১৯ : অ্যাপ ইঞ্জিন টাস্ক কিউ (টাস্ক টানুন) থেকে ক্লাউড পাব/সাবে স্থানান্তর করুন

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

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

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

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

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

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

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

মাইগ্রেশন রিসোর্স

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

কোডল্যাব

পাইথন ২

পাইথন ৩

মডিউল ১৫

কোড

নিষিদ্ধ

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

কোড

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

অনলাইন রিসোর্স

এই টিউটোরিয়ালের জন্য প্রাসঙ্গিক হতে পারে এমন অনলাইন রিসোর্সগুলি নীচে দেওয়া হল:

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

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

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

পাইথন

ভিডিও

লাইসেন্স

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