예제 #1
0
// 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
	}
}
예제 #2
0
// 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
	}
}
예제 #3
0
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
		}
	}
}