質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.47%

  • Go

    541questions

    Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

  • Google App Engine

    134questions

    Google App Engineは、Googleの管理するデータセンター上でウェブアプリケーションの開発が可能なクラウドコンピュータ技術です。Java、Python、Go用にSDKが用意されています。

【GAE/Go】initでのDatastoreへのアクセス

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 990

musharna000

score 12

Google App Engine for Go を利用してWebサービスを開発しています。
Datastoreへのアクセスを減らすために、
リクエスト毎にDatastoreにクエリをとばすのではなく、
init関数内で読み込んでおきそれを利用しようと考えています。

しかしながら、Datasotreへのアクセスに利用する
appengine.Contextの取得(func NewContext(req *http.Request) Context)をするのに
http.Requestが必要なため、httpリクエストがあった時しか
Datastoreへのアクセスができないので困っています。

対処法として、
データを読み込んだかをbool型のグローバル変数で記録して、
httpリクエストがあった際にこれをチェックして
まだ読み込まれていなかったらDatastoreから読み込む、
という方法を考えたのですが、
httpリクエストをハンドルしている関数ひとつひとつに
このためのif文を書き込むというのがスマートでなく感じたのと
読み込んでいないときに同時にアクセスがあった場合に
二重に読み込まれるなど危ない事になりそうだと考え
他に何か方法がないかと考えている次第です。

何か代替する方法はありますでしょうか。
皆様の知識をお借りしたいです。
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

Singletonパターンを適用してみてはいかがでしょうか。

package singleton

import (
    "net/http"
    "sync"
)

type singleton struct {
    //ここでDatastoreから取得したデータを保持
}

var instance *singleton
var once sync.Once

func newSingleton(r *http.Request) *singleton {
    s := new(singleton)
    // ここでGAEを用いてDatastoreからデータを取得する
    return s
}
func GetInstance(r *http.Request) *singleton {
    once.Do(func() {
        instance = newSingleton(r)   // <-初回呼び出し時のみここが呼ばれる
    })
    return instance
}

ハンドラ側からの呼び出しコードは以下のようになります。

func SomeHandler(w http.ResponseWriter, r *http.Request) {
    data := singleton.GetInstance(r)
    // データを使用した処理
}
出典:
Singleton Pattern in Go(英文)
http://marcio.io/2015/07/singleton-pattern-in-go/

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/08/04 21:15

    回答ありがとうございます。
    シングルトンで書けばスレッドセーフできますね!思いつきませんでした。
    追加での質問になってしまい申し訳ないのですが、
    このパターンでinstanceの生成に失敗した場合(Datastoreへのアクセスで何かあった場合)
    ひとまずそのリクエストには500(Internal Server Error)でも返しておいて
    次のリクエストでもう一度トライするという形にしたい場合はどうしたらいいでしょうか。
    sysc.Onceを調べてみたもののOnceをリセットするような関数は見つからなくて.......
    宜しくお願いします。

    キャンセル

  • 2015/08/04 23:10 編集

    sync.Onceのソースコードを読む限り、リセットするにはプライベートメンバであるOnce.doneを書き換える必要があり、パッケージ外からリセットするのは難しそうです。
    unsafeパッケージを駆使すれば不可能ではないとは思いますが、あまりお勧めはできません。

    次善の策としては、Once構造体を作り直すという手がありそうです。


    package singleton

    // 省略

    func Reset() {
    once = sync.Once{}
    }


    どちらにせよ、once.Doが呼ばれてからリセットまでの間に次のリクエストが発生すると、
    GetInstanceがnilを返す可能性が残ります。完全なスレッドセーフを目指すならばもう一工夫必要そうですね・・・。

    キャンセル

  • 2015/08/12 20:40

    返信送れてしまい申し訳ありません。
    スレッドセーフな書き方についてもう少し勉強してみようと思います。
    とても助かりました。ありがとうございます。

    キャンセル

関連した質問

同じタグがついた質問を見る

  • Go

    541questions

    Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

  • Google App Engine

    134questions

    Google App Engineは、Googleの管理するデータセンター上でウェブアプリケーションの開発が可能なクラウドコンピュータ技術です。Java、Python、Go用にSDKが用意されています。