// Call invokes a delayed function. // f.Call(c, ...) // is equivalent to // t, _ := f.Task(...) // taskqueue.Add(c, t, "") func (f *Function) Call(c appengine.Context, args ...interface{}) { t, err := f.Task(args...) if err != nil { c.Errorf("%v", err) return } if _, err := taskqueueAdder(c, t, queue); err != nil { c.Errorf("delay: taskqueue.Add failed: %v", err) return } }
// FetchToken fetches a new access token for the provided scopes. // Tokens are cached locally and also with Memcache so that the app can scale // without hitting quota limits by calling appengine.AccessToken too frequently. func makeAppEngineTokenFetcher(ctx appengine.Context, opts *oauth2.Options) func(*oauth2.Token) (*oauth2.Token, error) { return func(existing *oauth2.Token) (*oauth2.Token, error) { mu.Lock() defer mu.Unlock() key := ":" + strings.Join(opts.Scopes, "_") now := time.Now().Add(safetyMargin) if t, ok := tokens[key]; ok && !t.Expiry.Before(now) { return t, nil } delete(tokens, key) // Attempt to get token from Memcache tok := new(oauth2.Token) _, err := memcacheGob.Get(ctx, key, tok) if err == nil && !tok.Expiry.Before(now) { tokens[key] = tok // Save token locally return tok, nil } token, expiry, err := accessTokenFunc(ctx, opts.Scopes...) if err != nil { return nil, err } t := &oauth2.Token{ AccessToken: token, Expiry: expiry, } tokens[key] = t // Also back up token in Memcache if err = memcacheGob.Set(ctx, &memcache.Item{ Key: key, Value: []byte{}, Object: *t, Expiration: expiry.Sub(now), }); err != nil { ctx.Errorf("unexpected memcache.Set error: %v", err) } return t, nil } }
func runFunc(c appengine.Context, w http.ResponseWriter, req *http.Request) { defer req.Body.Close() var inv invocation if err := gob.NewDecoder(req.Body).Decode(&inv); err != nil { c.Errorf("delay: failed decoding task payload: %v", err) c.Warningf("delay: dropping task") return } f := funcs[inv.Key] if f == nil { c.Errorf("delay: no func with key %q found", inv.Key) c.Warningf("delay: dropping task") return } ft := f.fv.Type() in := []reflect.Value{reflect.ValueOf(c)} for _, arg := range inv.Args { var v reflect.Value if arg != nil { v = reflect.ValueOf(arg) } else { // Task was passed a nil argument, so we must construct // the zero value for the argument here. n := len(in) // we're constructing the nth argument var at reflect.Type if !ft.IsVariadic() || n < ft.NumIn()-1 { at = ft.In(n) } else { at = ft.In(ft.NumIn() - 1).Elem() } v = reflect.Zero(at) } in = append(in, v) } out := f.fv.Call(in) if n := ft.NumOut(); n > 0 && ft.Out(n-1) == errorType { if errv := out[n-1]; !errv.IsNil() { c.Errorf("delay: func failed (will retry): %v", errv.Interface()) w.WriteHeader(http.StatusInternalServerError) return } } }