Как мне получить текущее пространство имен и функцию задержки App Engine с помощью Go?

# #google-app-engine #go

#google-app-engine #Вперед

Вопрос:

Если я установлю пространство имен my context.Context и вызову функцию задержки:

 ctx := appengine.NewContext(r)
ctx, err := appengine.Namespace(ctx, "mynamespace")

delayFunc.Call(ctx)
  

Как я могу найти его имя:

 var delayFunc = delay.Func("my-func", func(ctx context.Context) {
    // How do I extract "mynamespace" from ctx?
})
  

Является ли следующая приемлемая практика?

 var delayFunc = delay.Func("my-func", func(ctx context.Context) {
    n := datastore.NewKey(ctx, "E", "e", 0, nil).Namespace()
    // n == "mynamespace"
})
  

Это работает, но похоже на взлом.

Ответ №1:

К сожалению, вам не повезло. Appengine не предоставляет (экспортированный) вызов API для доступа к пространству имен, связанному с контекстом.

Связь пространства имен с контекстом обрабатывается appengine/internal пакетом, но «программы не должны использовать этот пакет напрямую». Контекст с пространством имен получается internal.NamespacedContext() вызовом, и в нем реализуется «извлечение» пространства имен из контекста internal.NamespaceFromContext() . Они не являются частью общедоступного API, поэтому вы не можете (не должны) их использовать.

В основном у вас есть 2 варианта. Один из них — это «хакерский» способ, который вы представили, который работает, и вы можете продолжать его использовать.

Другой способ — обработать его вручную, например, вручную поместив пространство имен в контекст с помощью вашего собственного ключа, например:

 var namespaceKey = "myNsKey"


ctx = context.WithValue(ctx, namespaceKey, "mynamespace")
  

И когда вам это нужно, вы можете получить его следующим образом:

 ns := ctx.Value(namespaceKey)
  

Да, это связано с необходимостью обновлять его вручную, и если вы забыли, вы получите «недопустимое» или пустое пространство имен. Так что лично я бы пока пошел по вашему «хакерскому» пути (пока эта функциональность не будет добавлена в общедоступный API, если вообще когда-либо).

Если вы выберете ручной способ, чтобы избавиться от фактора «риска», вы могли бы создать вспомогательную функцию, которая могла бы позаботиться об этом вместе с appengine.Namespace() вызовом, чтобы вы не забыли об этом, и это было бы безопасно. Это может выглядеть так:

 func SetNS(ctx context.Context, ns string) context.Context {
    ctx = ctx, err := appengine.Namespace(ctx, ns)
    if err != nil {
        // handle error
    }
    ctx = context.WithValue(ctx, namespaceKey, ns)
    return ctx
}
  

И используя его:

 ctx = SetNS(ctx, "mynamespace")
  

Но это может быть редкий случай, когда вам нужно получить доступ к пространству имен из контекста, так как, когда вам это понадобится, может быть достаточно просто передать контекст в соответствующий вызов API (Appengine), который может извлечь его из контекста.