מעבר מ-Go 1.11 לזמן הריצה העדכני של Go

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

‫Go 1.11 יצא משימוש. לא תוכלו לפרוס אפליקציות של Go 1.11, גם אם הארגון שלכם השתמש בעבר במדיניות ארגונית כדי להפעיל מחדש פריסות של סביבות ריצה מדור קודם. האפליקציות הקיימות שלכם ב-Go 1.11 ימשיכו לפעול ולקבל תנועה. מומלץ לעבור לגרסה נתמכת עדכנית של Go.

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

שינויים בסביבות זמן הריצה מדור שני

כשמשדרגים לזמן ריצה של Go מהדור השני שנתמך, חשוב להביא בחשבון את ההבדלים הבאים:

הבדלים בשימוש בזיכרון

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

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

הבדלים בשימוש במעבד

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

הבדלים בכותרות הבקשה

סביבות זמן ריצה מהדור הראשון מאפשרות להעביר לאפליקציה כותרות של בקשות עם קווים תחתונים (למשל X-Test-Foo_bar). בסביבות זמן ריצה מהדור השני,‏ Nginx מוצגת בארכיטקטורת המארח. כתוצאה מהשינוי הזה, סביבות זמן ריצה מהדור השני מוגדרות להסרה אוטומטית של כותרות עם קווים תחתונים (_). כדי למנוע בעיות באפליקציה, מומלץ להימנע משימוש בקווים תחתונים בכותרות של בקשות לאפליקציה.

שינויים בקובץ app.yaml

ההתנהגות של חלק מהאלמנטים בקובץ ההגדרות app.yaml השתנתה:

רכיב סוג השינוי תיאור
app_engine_bundled_services נדרש באפליקציות שמשתמשות בשירותים מדור קודם מגדירים את השדה הזה כדי לגשת לשירותים ספציפיים בחבילה מדור קודם לגרסאות נתמכות של Go. מידע נוסף על הגדרות התצורה של app_engine_bundled_services זמין במאמר בנושא קובץ app.yaml.
login האפשרות הזו נתמכת אם מפעילים את Users API על ידי הגדרת האפשרות user ברשימה app_engine_bundled_services. אם אתם לא משתמשים בשירותים המצורפים מדור קודם לזמני הריצה מהדור השני, אתם יכולים להשתמש ב שיטות החלופיות האלה לאימות משתמשים.
runtime השתנה משנים את הרכיב runtime לזמן ריצה מדור שני.

מידע נוסף מפורט בapp.yaml.

יצירת חבילה של main

השירות שלכם צריך לכלול הצהרה על package main לפחות בקובץ מקור אחד.

שירותים בחבילה מדור קודם של App Engine

אם השירות שלכם משתמש בחבילות שירותים מדור קודם לזמני ריצה מדור שני:

  • השירות שלכם חייב להשתמש רק בחבילות גרסה 2 (google.golang.org/appengine/v2). שימוש בחבילות גרסה 1 (google.golang.org/appengine) הישנות יותר גורם לשגיאות.

  • בפונקציה main(), קוראים ל-appengine.Main() במקום ל-http.ListenAndServe(). כך תוכלו לוודא שלממשקי ה-API של user ושל appengine יש גישה להקשר הנוכחי של הבקשה.

כתיבת חבילה ראשית

אם השירות שלכם עדיין לא מכיל חבילת main, מוסיפים את ההצהרה package main וכותבים פונקציית main(). לפחות, פונקציית main() צריכה:

  • קוראים את משתנה הסביבה PORT וקוראים לפונקציה http.ListenAndServe():

    port := os.Getenv("PORT")
    if port == "" {
    	port = "8080"
    	log.Printf("Defaulting to port %s", port)
    }
    
    log.Printf("Listening on port %s", port)
    if err := http.ListenAndServe(":"+port, nil); err != nil {
    	log.Fatal(err)
    }

רישום של handlers של HTTP

אפשר לרשום את מטפלי ה-HTTP על ידי בחירה באחת מהאפשרויות הבאות:

  • השיטה המומלצת היא להעביר באופן ידני את כל הקריאות של http.HandleFunc() מהחבילות לפונקציה main() בחבילה main.
  • אפשר גם לייבא את החבילות של האפליקציה לחבילה main, ולוודא שכל פונקציה init() שמכילה קריאות ל-http.HandleFunc() מופעלת בהפעלה.

    אפשר למצוא את כל החבילות שמשתמשות בקריאה http.HandleFunc() באמצעות סקריפט ה-Bash הבא, ולהעתיק את הפלט לבלוק import של החבילה main:

    gp=$(go env GOPATH) && p=$(pwd) && pkg=${p#"$gp/src/"} && find . -name "*.go" | xargs grep "http.HandleFunc" --files-with-matches | grep -v vendor/ | grep -v '/main.go' | sed "s#\./\(.*\)/[^/]\+\.go#\t_ \"$pkg/\1\"#" | sort | uniq
    

הגדרת מבנה הקבצים

ב-Go, כל חבילה צריכה להיות בספרייה משלה. אפשר לציין ל-App Engine איפה נמצא חבילת main באמצעות main: בקובץ app.yaml של הפרויקט. לדוגמה, אם מבנה הקבצים של האפליקציה נראה כך:

myapp/
├── app.yaml
├── foo.go
├── bar.go
└── web/
    └── main.go

הקובץ app.yaml יכלול:

main: ./web # Relative filepath to the directory containing your main package.

מידע נוסף על הדגל main זמין במאמר app.yaml.

העברת קבצים אל GOPATH

כדי למצוא את GOPATH, משתמשים בפקודה הבאה:

go env GOPATH

מעבירים את כל הקבצים והייבוא הרלוונטיים אל GOPATH. אם משתמשים בייבוא יחסי, כמו import ./guestbook, צריך לעדכן את הייבוא כך שישתמש בנתיב המלא: import github.com/example/myapp/guestbook.