GAE/Go機能紹介

Google App Engint/Go Introduction

20 December 2014

Daigo Ikeda

Knightso, LLC

GAEとは

GAE/Goの特徴

速い!

特にspin-upが。

もちろん実行速度も。

Built-in Concurrency!

平行処理をシンプルに書ける→パフォーマンスチューニングが容易
つまり課金が抑えられる!!

現状(2014/12現在)

各機能紹介

Datastore

Datastoreとは

Datastore - KeyでのPut

type Book struct {
    Title     string
    Author    string
    Price     int
    CreatedAt time.Time
}
    book := Book{
        "Perfect Go",
        "Some Gopher",
        1000,
        time.Now(),
    }
    key := datastore.NewKey(c, "Book", "book1", 0, nil)
    //key := datastore.NewIncompleteKey(c, "Book", nil) // 自動ID付与
    key, err := datastore.Put(c, key, &book)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

Datastore - KeyでのPut(複数)

    keys := make([]*datastore.Key, 10)
    for i, _ := range keys {
        keys[i] = datastore.NewKey(c, "Book", "", int64(i+1), nil)
    }

    books := make([]Book, 10)
    for i, _ := range books {
        number := i + 1
        books[i] = Book{
            fmt.Sprintf("book-%d", number),
            fmt.Sprintf("author-%d", number%2),
            number * 100,
            time.Now(),
        }
    }
    _, err := datastore.PutMulti(c, keys, books)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

Datastore - KeyでのGet

    key := datastore.NewKey(c, "Book", "book1", 0, nil)

    var book Book
    err := datastore.Get(c, key, &book)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

Datastore - KeyでのGet(複数)

    keys := make([]*datastore.Key, 10)
    for i, _ := range keys {
        keys[i] = datastore.NewKey(c, "Book", "", int64(i+1), nil)
    }

    books := make([]Book, 10)
    err := datastore.GetMulti(c, keys, books)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

Datastore - Query(検索)

    q := datastore.NewQuery("Book").Filter("Author=", "author-1").Order("-CreatedAt").Offset(2).Limit(5)

    var books []Book
    keys, err := q.GetAll(c, &books)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

Datastore - 複合インデックス設定

indexes:

# AUTOGENERATED

- kind: Book
  properties:
  - name: Author
  - name: CreatedAt
    direction: desc

- kind: Book
  properties:
  - name: Title
  - name: CreatedAt
    direction: desc

Datastore - Query(カーソル)

    q := datastore.NewQuery("Book").Filter("Author=", "author-1").Order("-CreatedAt")

    pCursor := r.FormValue("cursor")
    if pCursor != "" {
        cursor, err := datastore.DecodeCursor(pCursor)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        q.Start(cursor)
    }

    var books []Book

    t := q.Run(c)
    for i := 0; i < 10; i++ {
        var book Book
        key, err := t.Next(&book)
        if err == datastore.Done {
            break
        }
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }

        c.Debugf("#v", key)

        books = append(books, book)
    }
    response.Books = books
    if cursor, err := t.Cursor(); err == nil {
        response.Cursor = cursor.String()
    }

Datastore - トランザクション

    key := datastore.NewKey(c, "Book", "book1", 0, nil)

    if err := datastore.RunInTransaction(c, func(c appengine.Context) error {
        var book Book
        if err := datastore.Get(c, key, &book); err != nil {
            return err
        }

        book.Price += 200

        if _, err := datastore.Put(c, key, &book); err != nil {
            return err
        }

        return nil
    }, nil); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

Memcache

Memcacheとは

Memcache - Set

    item := memcache.Item{
        Key:   "test1",
        Value: []byte("hello memcache"),
    }
    if err := memcache.Set(c, &item); err != nil {
        fmt.Fprintf(w, "failure: %s", err)
    } else {
        fmt.Fprint(w, "success")
    }

Memcache - Get

    item, err := memcache.Get(c, "test1")
    if err != nil {
        w.Write([]byte("not found"))
        return
    }

Memcache - Set Gob

    book := Book{
        "Perfect Go",
        "Some Gopher",
        1000,
        time.Now(),
    }

    item := memcache.Item{
        Key:    "book1",
        Object: &book,
    }
    if err := memcache.Gob.Set(c, &item); err != nil {
        fmt.Fprintf(w, "failure: %s", err)
    } else {
        w.Write([]byte("success"))
    }

Memcache - Get Gob

    var book Book
    _, err := memcache.Gob.Get(c, "book1", &book)
    if err != nil {
        w.Write([]byte("not found"))
        return
    }

Memcache - その他

goon

nds

Search

Searchとは

Search - 保存

    index, err := search.Open("Book")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    for i, book := range books {
        _, err := index.Put(c, fmt.Sprintf("book%d", i), book)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
    }

Search - 検索

    index, err := search.Open("Book")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    books := make([]*Book, 0, 10)
    t := index.Search(c, "Gopher Price >= 3000", nil)
    for {
        var book Book
        _, err := t.Next(&book)
        if err == search.Done {
            break
        } else if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        books = append(books, &book)
    }

URL Fetch

URL Fetch

URL Fetch - fetch

    client := urlfetch.Client(c)
    resp, err := client.Get("http://www.google.com/")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    var buf bytes.Buffer
    if _, err := io.Copy(&buf, resp.Body); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

Mail

Mail

Mail - 送信

    msg := &mail.Message{
        Sender:  "Hoge <hoge@example.com>",
        To:      []string{"to@example.com"},
        Subject: "This is test mail.",
        Body:    "Hello Gopher!",
    }

    if err := mail.Send(c, msg); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

Mail - 受信

app.yaml

- url: /_ah/mail/.*
  script: _go_app
  login: admin

inbound_services:
- mail
    http.HandleFunc("/_ah/mail/", receive)
    defer r.Body.Close()

    var b bytes.Buffer
    if _, err := b.ReadFrom(r.Body); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

Cron

Cron - スケジュールタスク実行

cron.yaml

cron:
- description: daily summary job
  url: /tasks/summary
  schedule: every 24 hours
- description: monday morning mailout
  url: /mail/weekly
  schedule: every monday 09:00
  timezone: Australia/NSW
- description: new daily summary job
  url: /tasks/summary
  schedule: every 24 hours
  target: beta

その他の機能

その他の機能

最後に

FYI:

GAE/Goハンズオン

弊社開発ブログ

Thank you

Daigo Ikeda

Knightso, LLC