func (api *MigrationAPI) Start() error { runAll := delay.Func("*MigrationService.RunAll", func(ctx context.Context) error { return api.MigrationService.RunAll(AsSuperuser(ctx)) }) api.Mutations = map[string]*graphql.Field{ "migrate": relay.MutationWithClientMutationID(relay.MutationConfig{ Name: "Migrate", InputFields: graphql.InputObjectConfigFieldMap{}, OutputFields: graphql.Fields{}, MutateAndGetPayload: func(inputMap map[string]interface{}, info graphql.ResolveInfo, ctx context.Context) (map[string]interface{}, error) { u, err := api.UserService.FromContext(ctx) if err != nil { return nil, err } if !u.IsAdmin { return nil, errors.New("user must be an admin") } err = runAll.Call(ctx) if err != nil { return nil, err } return map[string]interface{}{}, nil }, }), } return nil }
func init() { delayedGetStats = delay.Func( "my-favorite-dog", func(ctx context.Context, accessToken, username string) error { log.Infof(ctx, "delayedGetStats CALLED") api := &GithubAPI{ ctx: ctx, accessToken: accessToken, username: username, } since := time.Now().Add(-time.Hour * 24 * 30) stats, err := api.getCommitSummaryStats(since) if err != nil { return err } log.Infof(ctx, "STATS: %v", stats) key := datastore.NewKey(ctx, "Stats", username, 0, nil) _, err = datastore.Put(ctx, key, &stats) if err != nil { return err } return nil }, ) }
func init() { // created in init because it's called inside the function itself processFunc = delay.Func("process", process) // complete endpoint will be something like "/_ah/cron/process/logPhotos" cron.Get("/process/:name", processHandler) }
func init() { // created in init because it's called inside the function processPhotosFunc = delay.Func("processPhotos", processPhotos) // complete endpoint will be something like "/_ah/cron/photos/log" cron.Get("/photos/:processor", processPhotosHandler) }
func init() { reindexDelayer = delay.Func("reindex-idioms", func(c context.Context, cursorStr string) error { q := datastore.NewQuery("Idiom") if cursorStr != "" { log.Infof(c, "Starting at cursor %v", cursorStr) cursor, err := datastore.DecodeCursor(cursorStr) if err != nil { return err } q = q.Start(cursor) } iterator := q.Run(c) reindexedIDs := make([]int, 0, reindexBatchSize) defer func() { log.Infof(c, "Reindexed idioms %v", reindexedIDs) }() for i := 0; i < reindexBatchSize; i++ { var idiom Idiom key, err := iterator.Next(&idiom) if err == datastore.Done { log.Infof(c, "Reindexing completed.") return nil } else if err != nil { // ouch :( return err } err = indexIdiomFullText(c, &idiom, key) if err != nil { log.Errorf(c, "Reindexing full text idiom %d : %v", idiom.Id, err) } err = indexIdiomCheatsheets(c, &idiom) if err != nil { log.Errorf(c, "Reindexing cheatsheet of idiom %d : %v", idiom.Id, err) } reindexedIDs = append(reindexedIDs, idiom.Id) } cursor, err := iterator.Cursor() if err != nil { // ouch :( return err } log.Infof(c, "Stopping at cursor %v", cursor.String()) reindexDelayer.Call(c, cursor.String()) return nil }) }
func example() { var ctx context.Context var t *taskqueue.Task _ = t // [START deferred_tasks] var expensiveFunc = delay.Func("some-arbitrary-key", func(ctx context.Context, a string, b int) { // do something expensive! }) // Somewhere else expensiveFunc.Call(ctx, "Hello, world!", 42) // [END deferred_tasks] // [START URL_endpoints] t = &taskqueue.Task{Path: "/path/to/my/worker"} t = &taskqueue.Task{Path: "/path?a=b&c=d", Method: "GET"} // [END URL_endpoints] }
import ( "net/http" "strconv" "google.golang.org/appengine/delay" "google.golang.org/appengine/log" "github.com/gorilla/mux" "github.com/jittuu/hivepeek/internal" "golang.org/x/net/context" ) var ( delayFetchMatchesByLeagueFunc = delay.Func("fetch-matches-by-league", delayFetchMatchesByLeague) ) func AllMatchesByLeague(c context.Context, w http.ResponseWriter, r *http.Request) error { vars := mux.Vars(r) l, err := strconv.Atoi(vars["league"]) if err != nil { return err } s := vars["season"] db := &internal.DSContext{c} matches, err := db.GetAllMatchesByLeagueAndSeason(l, s) if err != nil { return err }
package controllers import ( "io" "io/ioutil" "net/http" "net/mail" "golang.org/x/net/context" "google.golang.org/appengine/delay" "google.golang.org/appengine/log" appmail "google.golang.org/appengine/mail" ) var echoMailFunc = delay.Func("echoMail", echoMail) func init() { router.Handle("/_ah/mail/", ContextHandlerFunc(ReceiveMail)) } func echoMail(ctx context.Context, m mail.Message) { from, err := m.Header.AddressList("From") if err != nil { log.Warningf(ctx, "Failed getting sender of mail: %+v", m) return } b, _ := ioutil.ReadAll(m.Body) am := &appmail.Message{
func init() { delayedPuppy = delay.Func("delayedPuppy", runLater) }
// BuildJustinCommandHandler builds an HTTP endpoint that responds to a Justin Slack "slash command" // - command is the expected Slack command, or empty string if we don't care // - token is the expected Slack token, or empty string if we don't care func BuildJustinCommandHandler(expectedCommand string, expectedToken string) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, req *http.Request) { ctx := appengine.NewContext(req) userName := req.PostFormValue("user_name") token := req.PostFormValue("token") command := req.PostFormValue("command") text := req.PostFormValue("text") responseURL := req.PostFormValue("response_url") log.Debugf(ctx, `Request: userName: %s token: %s command: %s text: %s team id: %s team domain: %s channel id: %s channel name: %s user id: %s response url: %s`, userName, token, command, text, req.PostFormValue("team_id"), req.PostFormValue("team_domain"), req.PostFormValue("channel_id"), req.PostFormValue("channel_name"), req.PostFormValue("user_id"), responseURL) // Validate if we're supposed to if expectedCommand != "" && command != expectedCommand { log.Errorf(ctx, "Forbidden - invalid command '%s'; expected '%s'", command, expectedCommand) http.Error(w, `"Forbidden"`, http.StatusForbidden) return } if expectedToken != "" && token != expectedToken { log.Errorf(ctx, "Forbidden - invalid token '%s'; expected '%s'", token, expectedToken) http.Error(w, `"Forbidden"`, http.StatusForbidden) return } // build the Slack response text response := fmt.Sprintf("Here's what I found:\n\nhttps://www.google.com/#q=%s", url.QueryEscape(strings.TrimSpace(text))) if strings.HasSuffix(text, "?") { response = fmt.Sprintf("Great question, @%s! %s", userName, response) } else { response = fmt.Sprintf("You got it, @%s! %s", userName, response) } // Create the JSON payload with the response, to send back to Slack respBytes, err := buildSlackJSON(ctx, response, true) if err != nil { // already logged http.Error(w, "Error", 500) return } // tell Slack to show the user's command w.Header().Set("Content-Type", "application/json") _, err = w.Write([]byte(`{"response_type": "in_channel"}`)) if err != nil { log.Errorf(ctx, "Error echoing the request: %s", err) } // queue up the delayed response var laterFunc = delay.Func("key", func(delayCtx context.Context, x string) { log.Debugf(delayCtx, "Sending delayed response to Slack for request: %s", text) time.Sleep(500 * time.Millisecond) err := sendSlackJSON(delayCtx, responseURL, respBytes) if err != nil { // already logged return } log.Debugf(delayCtx, "Success! Response sent back to Slack: %s", respBytes) }) laterFunc.Call(ctx, "") } }
} return nil }, &datastore.TransactionOptions{XG: true}) if err != nil { handleError(c, w, err, http.StatusInternalServerError) return } } var backupHTMLBlockFunc = delay.Func("backup", func(c context.Context, uuid string, blocks []*model.HTMLBlock) error { for i, block := range blocks { backupKey := model.NewHTMLBlockBackupKey(c, fmt.Sprintf("%s-%02d", uuid, i)) var backup model.HTMLBlockBackup backup.HTMLBlockKey = block.Key backup.HTMLBlock = *block // without nds cache if _, err := datastore.Put(c, backupKey, &backup); err != nil { log.Errorf(c, err.Error()) return err } } return nil }) func getRequestJson(w http.ResponseWriter, r *http.Request, p interface{}) error { decoder := json.NewDecoder(r.Body) err := decoder.Decode(p) if err != nil { return err } return nil
import ( "time" "math/rand" "net/http" "github.com/qedus/nds" "golang.org/x/net/context" "google.golang.org/appengine" "google.golang.org/appengine/datastore" "google.golang.org/appengine/delay" ) var ( generateRandomFn = delay.Func("generateRandom", generateRandom) photographers = []Photographer{ {1, "Mr Canon"}, {2, "Miss Nikon"}, {3, "Mrs Pentax"}, {4, "Ms Sony"}, } ) func init() { http.Handle("/_ah/warmup", http.HandlerFunc(warmupHandler)) } func warmupHandler(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r)
if errTooManyItems != nil { // Return error *after* the restoring is done return historyIdiom, errTooManyItems } return historyIdiom, nil } // Delayers registered at init time // TODO take real Idiom as parameter, not a Key or a pointer var historyDelayer = delay.Func("save-history-item", func(c context.Context, idiomKey *datastore.Key) error { var historyItem IdiomHistory // TODO check Memcache first err := datastore.Get(c, idiomKey, &historyItem.Idiom) if err != nil { return err } historyItem.ComputeIdiomOrImplLastEditor() // Saves a new IdiomHistory entity. This causes no contention on the original Idiom entity. _, err = datastore.Put(c, newHistoryKey(c), &historyItem) return err }) var indexDelayer = delay.Func("index-text-idiom", func(c context.Context, idiomKey *datastore.Key) error { var idiom Idiom // TODO check Memcache first err := datastore.Get(c, idiomKey, &idiom) if err != nil { return err } // Full text API causes no contention on the original Idiom entity. err = indexIdiomFullText(c, &idiom, idiomKey)
package backoffice import ( "net/http" "github.com/jittuu/hivepeek/internal" "google.golang.org/appengine/delay" "google.golang.org/appengine/log" "golang.org/x/net/context" ) var ( delayFetchLeaguesFunc = delay.Func("fetch-leagues", delayFetchCompetitions) ) func AllLeagues(c context.Context, w http.ResponseWriter, r *http.Request) error { db := &internal.DSContext{c} lgs, err := db.GetAllLeagues() if err != nil { return err } return internal.Json(w, lgs) } func FetchLeagues(c context.Context, w http.ResponseWriter, r *http.Request) error { err := delayFetchLeaguesFunc.Call(c) return err } func delayFetchCompetitions(c context.Context) error {
package backoffice import ( "net/http" "strconv" "github.com/gorilla/mux" "github.com/jittuu/hivepeek/internal" "golang.org/x/net/context" "google.golang.org/appengine/delay" "google.golang.org/appengine/log" ) var ( delayFetchTeamsFunc = delay.Func("fetch-teams-by-league", delayFetchTeams) ) func AllTeamsByLeague(c context.Context, w http.ResponseWriter, r *http.Request) error { vars := mux.Vars(r) l, err := strconv.Atoi(vars["league"]) if err != nil { return err } s := vars["season"] db := &internal.DSContext{c} teams, err := db.GetAllTeamsByLeagueAndSeason(l, s) if err != nil { return err }