מעבר מ-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

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

  • השירות יכול להשתמש רק בחבילות v2 ‏ (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.