יצירת משימות Push

בדף הזה מתואר איך ליצור משימות ולהוסיף אותן לתורים של הודעות בדחיפה. כדי לעבד משימה, צריך ליצור אובייקט משימה חדש ולהוסיף אותו לתור. אפשר לציין באופן מפורש את השירות ואת המטפל שמעבדים את המשימה, ואפשר גם להעביר למטפל נתונים ספציפיים למשימה. אפשר גם לכוונן את ההגדרה של המשימה, למשל לתזמן זמן עתידי שבו היא תתבצע או להגביל את מספר הפעמים שבהן המערכת תנסה לבצע את המשימה מחדש אם היא תיכשל.

יצירת משימה חדשה

כדי ליצור משימה ולהוסיף אותה לתור, קוראים לפונקציה taskqueue.add().

ציון שירות העובדים

כשמשימה נשלפת מהתור שלה, שירות תור המשימות שולח אותה לשירות של עובד. לכל משימה יש יעד וכתובת URL, שקובעים איזה שירות ומטפל יבצעו בסופו של דבר את המשימה.

target

היעד מציין את השירות שיקבל את בקשת ה-HTTP כדי לבצע את המשימה. זוהי מחרוזת שמציינת שירות/גרסה/מופע באחד מהפורמטים הקנוניים. הטפסים הכי נפוצים הם:

    service
    version.service
    instance.version.service

מחרוזת היעד מתווספת לפני שם הדומיין של האפליקציה. יש שלוש דרכים להגדיר את היעד של משימה:

  • מצהירים על היעד כשיוצרים את המשימה. אפשר להגדיר את היעד באופן מפורש באמצעות הפרמטר target בפונקציה taskqueue.add(). דוגמה: ראו למעלה.

  • כשמגדירים תור ב-queue.yaml, צריך לכלול הנחיית target, כמו בהגדרה של queue-blue. כל המשימות שנוספות לתור עם target ישתמשו ביעד הזה, גם אם הוקצה למשימה יעד אחר בזמן היצירה.

  • אם לא מציינים יעד באף אחת משתי השיטות הקודמות, היעד של המשימה הוא גרסת השירות שמוסיפה אותה לתור. שימו לב: אם מוסיפים משימה לתור מהשירות ומהגרסה שמוגדרים כברירת מחדל באופן הזה, וגרסת ברירת המחדל משתנה לפני שהמשימה מופעלת, היא תופעל בגרסת ברירת המחדל החדשה.

url

הפונקציה url בוחרת באחד מהמטפלים בשירות היעד, שיבצע את המשימה.

הערך של url צריך להתאים לאחת מתבניות כתובות ה-URL של ה-handler בשירות היעד. הפרמטר url יכול לכלול פרמטרים של שאילתה אם השיטה שצוינה במשימה היא GET או PULL. אם לא מציינים url, המערכת משתמשת בכתובת ה-URL שמוגדרת כברירת מחדל /_ah/queue/[QUEUE_NAME], כאשר [QUEUE_NAME] הוא שם התור של המשימה.

העברת נתונים אל ה-handler

אפשר להעביר נתונים ל-handler כפרמטרים של שאילתה בכתובת ה-URL של המשימה, אבל רק אם השיטה שצוינה במשימה היא GET או PULL.

אפשר גם להשתמש בכל אחד מהשדות הבאים כדי להוסיף נתונים למשימה:

  • payload, שמעביר את נתוני המשימה בגוף בקשת ה-HTTP.
  • params

שלושת הקריאות האלה שוות ערך:

taskqueue.add(method=GET, url='/update-counter?key=blue', target='worker')
taskqueue.add(url='/update-counter', params={'key': 'blue'}, target='worker')
taskqueue.add(url='/update-counter', payload="{'key': 'blue'}", target='worker')

מתן שם למשימה

כשיוצרים משימה חדשה, App Engine מקצה למשימה שם ייחודי כברירת מחדל. עם זאת, אפשר להקצות שם משלכם למשימה באמצעות הפרמטר name. יתרון בהקצאת שמות משלכם למשימות הוא שמשימות עם שמות לא משוכפלות, כלומר אתם יכולים להשתמש בשמות של משימות כדי להבטיח שמשימה תתווסף רק פעם אחת. הסרת הכפילויות נמשכת 9 ימים אחרי שהמשימה מסתיימת או נמחקת.

שימו לב: לוגיקת ביטול הכפילויות יוצרת תקורה משמעותית בביצועים, וכתוצאה מכך עלולות להיות עליות בזמני האחזור ובשיעורי השגיאות שקשורים למשימות עם שמות. העלויות האלה יכולות להיות גבוהות במיוחד אם שמות המשימות הם עוקבים, כמו חותמות זמן. לכן, אם אתם מקצים שמות משלכם, מומלץ להשתמש בקידומת עם פיזור טוב לשמות המשימות, כמו גיבוב של התוכן.

אם אתם מקצים שמות משלכם למשימות, שימו לב שהאורך המקסימלי של השם הוא 500 תווים, והשם יכול להכיל אותיות רישיות וקטנות, מספרים, קווים תחתונים ומקפים.

הוספת משימות באופן אסינכרוני

כברירת מחדל, הקריאות שמוסיפות משימות לתורים הן סינכרוניות. ברוב התרחישים, קריאות סנכרוניות פועלות בצורה תקינה. הוספת משימה לתור היא בדרך כלל פעולה מהירה. יש אחוז קטן של פעולות להוספת משימות שיכולות להימשך הרבה יותר זמן, אבל הזמן החציוני להוספת משימה הוא פחות מ-5 אלפיות השנייה.

אי אפשר להוסיף פעולות של משימות לתורים שונים באצווה, ולכן Task Queue API מספק גם קריאות אסינכרוניות שמאפשרות להוסיף את המשימות האלה במקביל, וכך לצמצם עוד יותר את זמן האחזור. זה שימושי אם אתם מפתחים אפליקציה שרגישה מאוד לזמן האחזור וצריכה לבצע כמה פעולות של הוספת משימות לתורים שונים בו-זמנית.

כדי לבצע קריאות אסינכרוניות לתור משימות, צריך להשתמש בשיטות האסינכרוניות שסופקו על ידי המחלקה Queue של המחלקה Queue ואובייקט RPC. צריך לקרוא ל-get_result() באובייקט RPC שמוחזר כדי לאלץ את השלמת הבקשה. כשמוסיפים משימות באופן אסינכרוני בעסקה, צריך לקרוא ל-get_result() באובייקט RPC לפני שמבצעים את העסקה כדי לוודא שהבקשה הסתיימה.

הוספת משימות לתור בטרנזקציות של Cloud Datastore

אפשר להוסיף משימה לתור כחלק מטרנזקציית Datastore, כך שהמשימה תתווסף לתור – ומובטח שהיא תתווסף לתור – רק אם הטרנזקציה תאושר בהצלחה. משימות שנוספו ב טרנזקציה נחשבות לחלק ממנה, ויש להן את אותה רמה של טרנזקציה .

אפליקציה לא יכולה להוסיף יותר מחמש משימות טרנזקציונליות לתורי משימות במהלך טרנזקציה אחת. למשימות טרנזקציונליות אסור להכיל שמות שצוינו על ידי המשתמש.

בדוגמת הקוד הבאה אפשר לראות איך מוסיפים משימות טרנזקציונליות לתור דחיפה (push queue) כחלק מטרנזקציה של Datastore:

from google.appengine.api import taskqueue
from google.appengine.ext import ndb

@ndb.transactional
def do_something_in_transaction():
  taskqueue.add(url='/path/to/my/worker', transactional=True)
  #...

do_something_in_transaction()

שימוש בחבילת העיכוב

הגדרת handler לכל משימה נפרדת (כפי שמתואר בקטעים הקודמים) יכולה להיות מסורבלת, וכך גם סדרות וביטול סדרות של ארגומנטים מורכבים למשימה – במיוחד אם יש לכם הרבה משימות מגוונות אבל קטנות שאתם רוצים להריץ בתור. ערכת ה-SDK של Python כוללת ספרייה (google.appengine.ext.deferred) שחושפת פונקציה פשוטה שמאפשרת לעקוף את כל העבודה של הגדרת מטפלים ייעודיים במשימות וסדרות וביטול סדרות של הפרמטרים.

כדי להשתמש בספרייה הזו, צריך להוסיף את deferred המובנה ל-app.yaml. מידע נוסף זמין בקטע בנושא רכיבי Handler מובנים במאמר בנושא app.yaml.

כדי להשתמש בספרייה deferred, פשוט מעבירים את הפונקציה ואת הארגומנטים שלה אל deferred.defer():

import logging

from google.appengine.ext import deferred

def do_something_expensive(a, b, c=None):
    logging.info("Doing something expensive!")
    # Do your work here

# Somewhere else
deferred.defer(do_something_expensive, "Hello, world!", 42, True)

ספריית deferred אורזת את בקשת הפעלת הפונקציה ואת הארגומנטים שלה, ואז מוסיפה אותה לתור המשימות. כשהמשימה מבוצעת, ספריית deferred מבצעת את do_something_expensive("Hello, world!", 42, True).

עבודה עם משימות באפליקציה לפי עקרון ה-Multi-tenancy

כברירת מחדל, תורי הודעות מסוג Push משתמשים במרחב השמות הנוכחי שהוגדר במנהל מרחבי השמות בזמן יצירת המשימה. אם האפליקציה משתמשת בגישה מרובת דיירים, כדאי לעיין ב-Namespaces API.

המאמרים הבאים