Index: impl/prod/context.go |
diff --git a/impl/prod/context.go b/impl/prod/context.go |
index fc4a5e8fd9afc7036620e605b4f60fb2f3b85878..10ba7d1d36433213957863ea0fa3b309f8020563 100644 |
--- a/impl/prod/context.go |
+++ b/impl/prod/context.go |
@@ -11,7 +11,6 @@ import ( |
"net/url" |
"strings" |
- "github.com/luci/gae/service/info" |
"github.com/luci/gae/service/urlfetch" |
"golang.org/x/net/context" |
gOAuth "golang.org/x/oauth2/google" |
@@ -29,9 +28,8 @@ var RemoteAPIScopes = []string{ |
type key int |
var ( |
- prodContextKey key |
- prodContextNoTxnKey key = 1 |
- probeCacheKey key = 2 |
+ prodStateKey = "contains the current *prodState" |
+ probeCacheKey = "contains the current *infoProbeCache" |
) |
// AEContext retrieves the raw "google.golang.org/appengine" compatible Context. |
@@ -40,40 +38,15 @@ var ( |
// RPCs. Doesn't transfer cancelation ability though (since it's ignored by GAE |
// anyway). |
func AEContext(c context.Context) context.Context { |
- aeCtx, _ := c.Value(prodContextKey).(context.Context) |
- if aeCtx == nil { |
- return nil |
- } |
- if deadline, ok := c.Deadline(); ok { |
- aeCtx, _ = context.WithDeadline(aeCtx, deadline) |
- } |
- return aeCtx |
-} |
- |
-// AEContextNoTxn retrieves the raw "google.golang.org/appengine" compatible |
-// Context that's not part of a transaction. |
-func AEContextNoTxn(c context.Context) context.Context { |
- aeCtx, _ := c.Value(prodContextNoTxnKey).(context.Context) |
- if aeCtx == nil { |
- return nil |
- } |
- |
- if ns, has := info.Get(c).GetNamespace(); has { |
- var err error |
- aeCtx, err = appengine.Namespace(aeCtx, ns) |
- if err != nil { |
- panic(err) |
- } |
- } |
- if deadline, ok := c.Deadline(); ok { |
- aeCtx, _ = context.WithDeadline(aeCtx, deadline) |
- } |
- return aeCtx |
+ ps := getProdState(c) |
+ return ps.context(c) |
} |
func setupAECtx(c, aeCtx context.Context) context.Context { |
- c = context.WithValue(c, prodContextKey, aeCtx) |
- c = context.WithValue(c, prodContextNoTxnKey, aeCtx) |
+ c = withProdState(c, prodState{ |
+ ctx: aeCtx, |
+ noTxnCtx: aeCtx, |
+ }) |
return useModule(useMail(useUser(useURLFetch(useRDS(useMC(useTQ(useGI(useLogging(c))))))))) |
} |
@@ -123,9 +96,11 @@ func Use(c context.Context, r *http.Request) context.Context { |
// - "https://www.googleapis.com/auth/cloud.platform" |
func UseRemote(inOutCtx *context.Context, host string, client *http.Client) (err error) { |
if client == nil { |
+ aeCtx := AEContext(*inOutCtx) |
+ |
if strings.HasPrefix(host, "localhost") { |
transp := http.DefaultTransport |
- if aeCtx := AEContextNoTxn(*inOutCtx); aeCtx != nil { |
+ if aeCtx != nil { |
transp = urlfetch.Get(*inOutCtx) |
} |
@@ -147,7 +122,6 @@ func UseRemote(inOutCtx *context.Context, host string, client *http.Client) (err |
} |
defer rsp.Body.Close() |
} else { |
- aeCtx := AEContextNoTxn(*inOutCtx) |
if aeCtx == nil { |
aeCtx = context.Background() |
} |
@@ -165,3 +139,48 @@ func UseRemote(inOutCtx *context.Context, host string, client *http.Client) (err |
*inOutCtx = setupAECtx(*inOutCtx, aeCtx) |
return nil |
} |
+ |
+// prodState is the current production state. |
+type prodState struct { |
+ // ctx is the current derived GAE context. |
+ ctx context.Context |
+ |
+ // noTxnCtx is a Context maintained alongside ctx. When a transaction is |
+ // entered, ctx will be updated, but noTxnCtx will not, allowing extra- |
+ // transactional Context access. |
+ noTxnCtx context.Context |
+ |
+ // inTxn if true if this is in a transaction, false otherwise. |
+ inTxn bool |
+} |
+ |
+func getProdState(c context.Context) prodState { |
+ if v := c.Value(&prodStateKey).(*prodState); v != nil { |
+ return *v |
+ } |
+ return prodState{} |
+} |
+ |
+func withProdState(c context.Context, ps prodState) context.Context { |
+ return context.WithValue(c, &prodStateKey, &ps) |
+} |
+ |
+// context returns the current AppEngine-bound Context. Prior to returning, |
+// the deadline from "c" (if any) is applied. |
+// |
+// Note that this does not (currently) apply any other Done state or propagate |
+// cancellation from "c". |
+// |
+// Tracking at: |
+// https://github.com/luci/gae/issues/59 |
+func (ps *prodState) context(c context.Context) context.Context { |
+ aeCtx := ps.ctx |
+ if aeCtx == nil { |
+ return nil |
+ } |
+ |
+ if deadline, ok := c.Deadline(); ok { |
+ aeCtx, _ = context.WithDeadline(aeCtx, deadline) |
+ } |
+ return aeCtx |
+} |