如何使用Go获取当前名称空间和App Engine延迟功能?

If I set the namespace of my context.Context and call a delay function:

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

delayFunc.Call(ctx)

How can I find its name:

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

Is the following acceptable practice?

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

It works but feels like a hack.

Unfortunately you're out of luck. Appengine does not provide an (exported) API call to access the namespace associated with the context.

The namespace association with the context is handled by the appengine/internal package, but "programs should not use this package directly". The context with namespace is obtained by the internal.NamespacedContext() call, and the namespace "extraction" from context is implemented in internal.NamespaceFromContext(). These are not part of the public API, so you can't (shouldn't) use them.

You basically have 2 options. One is the "hacky" way you presented, which works and you may continue to use it.

Another one is to manually handle it, e.g. by manually putting the namespace into the context with your own key, e.g.:

var namespaceKey = "myNsKey"


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

And when you need it, you can get it like:

ns := ctx.Value(namespaceKey)

Yes, this has the burden of having to manually update it, and if you'd forgot, you would get an "invalid" or empty namespace. So personally I would go with your "hacky" way for now (until this functionality is added to the public API, if ever).

If you go with the manual way, to get rid of the "risk" factor, you could create a helper function which could take care of this along with the appengine.Namespace() call, so you would not forget about it and it would be safe. It could look like this:

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
}

And using it:

ctx = SetNS(ctx, "mynamespace")

But it may be a rare case when you need to access namespace from the context, as when you would need it, it might just be enough to pass the context to the proper (Appengine) API call which can extract it from the context.