Example #1
0
func MatchIncomingBids(c appengine.Context, articleId bitwrk.ArticleId) error {
	incomingBids := make([]hotBid, 0, 16)

	if tasks, err := taskqueue.LeaseByTag(c, 200, "hotbids", 20, string(articleId)); err != nil {
		return err
	} else {
		defer func() {
			if err := taskqueue.DeleteMulti(c, tasks, "hotbids"); err != nil {
				c.Errorf("Couldn't delete from task queue: %v", err)
			}
		}()
		for index, task := range tasks {
			var hot hotBid
			if err := json.Unmarshal(task.Payload, &hot); err != nil {
				c.Errorf("Couldn't unmarshal task #%v: %v", index, err)
			} else {
				incomingBids = append(incomingBids, hot)
			}
		}
	}

	f := func(c appengine.Context) error {
		now := time.Now()
		if err := matchIncomingBids(c, now, articleId, incomingBids); err != nil {
			return err
		} else {
			return deleteExpiredHotBids(c, now, articleId)
		}
	}

	return datastore.RunInTransaction(c, f, nil)
}
Example #2
0
func StreamingInsertHandler(rw http.ResponseWriter, req *http.Request) {
	c := appengine.NewContext(req)

	// ログの種類一覧を取得する
	logInfos := model.GetBigQueries()
	for _, logInfo := range logInfos {
		//key := model.NewBigQueryInfoKey(c, logInfo)

		for {
			if isShuttingDown {
				c.Warningf("The instance is shutting down for some reason.")
				return
			}

			tasks, err := taskqueue.LeaseByTag(c, TASK_COUNT, QUEUE_NAME, LEASE_TIME, logInfo.LogID)
			if err != nil {
				c.Errorf("%s", err.Error())
				return
			}

			taskSize := len(tasks)
			if taskSize > 0 {
				handlesMap := map[string][]*taskqueue.Task{}
				for _, task := range tasks {
					params := unmarshalPayload(task)

					registerDate := params.Date
					// TODO: LocationをAsia/Tokyoにズラした時刻を取得する方法が分からない。
					registerYmd := registerDate.Format(YYYYMMDD)

					handles, ok := handlesMap[registerYmd]
					if !ok {
						handles = []*taskqueue.Task{}
						handlesMap[registerYmd] = handles
					}
					handlesMap[registerYmd] = append(handlesMap[registerYmd], task)

					// debug. ok.
					c.Infof("logID: %s task count: %d", logInfo.LogID, len(handlesMap[registerYmd]))
				}

				// 362行目相当
				for registerYmd, handles := range handlesMap {
					// TODO: 下記テーブルのローテートは、ローテート無しでBigQueryへのInsert確認後に実装。
					/*
						date := time.Parse(constants.YYYYMMDD, registerYmd)
						slashedYmd := date.Format(constants.DATE_FORMAT_SLASHED)

						if この日付のテーブルが有るか {
							BigQueryに新しくテーブルを作成
							// DatastoreUtilityがない・・・後で池田さんに聞こう。
						}
					*/

					// InsertAll用のデータ構築と、insertIDの有無を確認してpanic処理
					rows := make([]*model.Task, len(handles))
					for i, taskHandle := range handles {
						rows[i] = unmarshalPayload(taskHandle)

						if len(rows[i].InsertID) == 0 {
							panic(fmt.Sprintln("log key not found."))
						}
					}

					c.Debugf("inserting! logID:%s, ymd:%s, rows:%d", logInfo.LogID, registerYmd, len(rows))

					service := gaebigquery.NewService(c)
					res, err := service.TableData.InsertAll(logInfo.DatasetID, logInfo.TableID, rows)
					// insertAllでエラーが出たら、次のループへ。(ここはJavaと異なる)
					if err != nil {
						c.Errorf("%s", err.Error())
						for _, ft := range handles {
							c.Debugf("modify task lease...")
							taskqueue.ModifyLease(c, ft, QUEUE_NAME, 5)
						}
						break
					}

					failures := make([]*taskqueue.Task, 0)
					if res.InsertErrors != nil && len(res.InsertErrors) > 0 {
						for _, insertErrors := range res.InsertErrors {
							// TableDataInsertAllResponseInsertErrors.Index は int64です。
							// そのためzero valueの場合と、値が0である場合を区別できません。
							// よってErrorsの有無で判別することにしました。
							if insertErrors.Errors == nil {
								continue
							}
							for _, errProto := range insertErrors.Errors {
								errJson, err := json.Marshal(errProto)
								if err != nil {
									c.Warningf("json error: %s", err.Error())
								} else {
									c.Debugf("%s", string(errJson))
								}
							}
							failures = append(failures, handles[int(insertErrors.Index)])
						}
					}

					succeeds := make([]*taskqueue.Task, 0)
					for _, taskHandle := range handles {
						ifIn := func() bool {
							for _, f := range failures {
								if taskHandle == f {
									return true
								}
							}
							return false
						}()
						if ifIn == false {
							succeeds = append(succeeds, taskHandle)
						}
					}

					c.Debugf("succeeds:%d", len(succeeds))
					c.Debugf("failures:%d", len(failures))

					if len(succeeds) > 0 {
						c.Debugf("delete tasks...")
						err = taskqueue.DeleteMulti(c, succeeds, QUEUE_NAME)
						if err != nil {
							multiError, ok := err.(appengine.MultiError)
							if ok {
								for _, err = range multiError {
									c.Errorf("%s", err.Error())
								}
							} else {
								c.Errorf("%s", err.Error())
							}
						}
					}

					for _, ft := range failures {
						c.Debugf("modify task lease...")
						taskqueue.ModifyLease(c, ft, QUEUE_NAME, 5)
					}
				}
			}

			// if BigQueryのテーブル作成でエラー吐いた {
			//		break
			// }
			if len(tasks) < TASK_COUNT {
				break
			}
		}
	}
	/***
	  for(ログの種類) {
	  	cron自体のログの記録を取るエンティティを取得	// 必要?

	  	datastoreに保存してあるログの種類のBigQuery定義を取得する。

	  	キューからタスクを取得
	  	for {
	  		if isShuttingDown {	// backendインスタンスが落ちる30秒前か否か
					map[string]string{"result":"shutdown"}を返す // どこに返してんの?
	  		}

	  		taskをleaseする。

				if taskが有る {
					handlesMap := map[string][]*taskqueue.Task	// keyは何だ? → 日付のようだ。
					// illegalTasks関連の処理は今回要らないので除いてます。
					for リースしたtask {
						タスクのパラメータを取得

						タスクのpayloadから、タスクの登録日時を取得
						取得した日時を基に、フォーマットとタイムゾーンを指定してDate型変数に変換

						Date型の日時を文字列に変換
						handles := handlesMap[日時文字列]
						if handlesが無かった(nil) {
							handlesMap[日時文字列] = make([]*taskqueue.Task)
						}
						handlesMap[日時文字列] = append(handlesMap[日時文字列], task)
					}

					for 登録日時, taskのslice := range handlesMap {	// 362行目
						handlesMapから日付ごとのTaskを取得
						年/月/日のフォーマットに文字列変更

						// TODO: 下記テーブルのローテートは、ローテート無しでBigQueryへのInsert確認後に実装。
						if この日付のテーブルが有るか {
							BigQueryに新しくテーブルを作成
							// DatastoreUtilityがない・・・後で池田さんに聞こう。
						}

						インサートIDを入れるスライス変数
						行を入れるスライス変数
						for 個別タスク := range 日付ごとのTask {
							taskのパラメータを取得(payloadのこと)
							パラメータをスキーマに合わせたmapに変換
							行を格納するスライスに追加

							パラメータmapからInsertIDを取得
							if InsertIDがnull {
								例外を投げる(GoではpanicでもOK)
							}
							インサートIDのスライスに追加
						}

						ログ出力

						InsertAllの実行	// TODO: bigquery apiのエラー処理を細かにする
						失敗したtask一覧を入れるスライス
						if エラーがあれば {
							for エラー一覧 {
								if エラーのインデックスがnull {
									continue
								}
								for エラーの中身 {
									エラーの中身をログに出力
								}
								エラーのインデックスを基に、失敗したタスクを取得して、失敗したタスク一覧に追加
							}
						}

						成功したtask一覧用変数
						for 日付ごとのTask {
							if 失敗したタスク一覧に入っていない {
								成功したタスク一覧に追加する
							}
						}

						成功したタスク数をログ出力
						失敗したタスク数をログ出力

						if 成功したタスク数 > 0 {
							ログにタスクを削除する旨を出力
							成功したタスクをキューから削除
						}

						for 失敗したタスク一覧 {
							失敗したタスクはキューに戻す旨をログに出力
							失敗したタスクをキューに戻す
						}
					}
				}
				if タスクの数が500件以下 {
					ログに次へと出力
					break
				}
	  	}
	  }
	  ***/
}
Example #3
0
func batchBulkUpdateUnique(c appengine.Context, w http.ResponseWriter, r *http.Request) {
	tasks, err := taskqueue.LeaseByTag(c, 100, "updateUniquePull", 3600, "")
	if err != nil {
		c.Errorf("Error leasing: %v", err)
		http.Error(w, err.Error(), 500)
		return
	}
	if len(tasks) == 0 {
		c.Infof("No tasks found")
		w.WriteHeader(204)
		return
	}
	uuid := tasks[0].Tag

	mckey := "ulock." + uuid
	item := memcache.Item{
		Key:        mckey,
		Expiration: time.Minute,
	}

	if memcache.Add(c, &item) == memcache.ErrNotStored {
		c.Errorf("Already processing %v, skipping", uuid)
		http.Error(w, "Already processing item", 503)
		return
	}

	c.Infof("Processing %v things for %v", len(tasks), uuid)
	uk := datastore.NewKey(c, "Unique", uuid, 0, nil)

	chu := make(chan uniqueFetch)

	go func() {
		rv := uniqueFetch{}
		rv.u, rv.err = loadUnique(c, uk)
		chu <- rv
	}()

	keys := []*datastore.Key{}
	obs := make([]oldLoader, len(tasks))
	for i, t := range tasks {
		key, err := datastore.DecodeKey(string(t.Payload))
		if err != nil {
			c.Errorf("Error decoding key: %s: %v", t.Payload, err)
			http.Error(w, err.Error(), 500)
			return
		}
		keys = append(keys, key)
		obs[i] = oldLoader{c: c, into: &Stats{}}
	}
	err = datastore.GetMulti(c, keys, obs)
	if err != nil {
		c.Errorf("Error grabbing all the stats: %v", err)
		http.Error(w, err.Error(), 500)
		return
	}

	uf := <-chu
	if uf.err != nil {
		c.Errorf("Error fetching unique: %v", err)
		http.Error(w, err.Error(), 500)
		return
	}

	cherr := make(chan error, 5)

	// We're probably safe enough to count these now
	go func() {
		cherr <- sharded_counter.IncrementBy(c, "unique_"+uuid, len(tasks))
	}()

	for _, wst := range obs {
		st := wst.into.(*Stats)
		st.uncompress()
		err := uf.u.Update(*st)
		if err != nil {
			c.Warningf("Problem updating a unique: %v (continuing)", err)
		}
	}

	go func() {
		cherr <- uf.u.compress()
		_, err = datastore.Put(c, uk, &uf.u)
		if err != nil {
			c.Errorf("Error storing unique: %v", err)
		}
		cherr <- err
	}()

	go func() {
		memcache.Delete(c, mckey)
		cherr <- couchit(c, uk, url.Values{
			"isnew": []string{fmt.Sprintf("%t", uf.u.isNew)}})
	}()

	go func() {
		cherr <- taskqueue.DeleteMulti(c, tasks, "updateUniquePull")
	}()

	go func() {
		st, err := taskqueue.QueueStats(c, []string{"updateUniquePull", "bulkupdateunique"}, 0)
		if err != nil {
			c.Errorf("Error getting queue stats: %v", err)
			cherr <- err
			return
		}
		if st[0].Tasks > 5000 && st[1].Tasks < 1000 {
			c.Infof("There's more to go, resubmitting: %v", err)
			taskqueue.Add(c, taskqueue.NewPOSTTask("/submit/bulkUpdateUnique",
				url.Values{"times": []string{"100"}}),
				"default")
		}
		cherr <- nil
	}()

	err = anyErr(<-cherr, <-cherr, <-cherr, <-cherr, <-cherr)
	if err != nil {
		c.Errorf("Error in batch processing: %v", err)
		http.Error(w, err.Error(), 500)
		return
	}
	w.WriteHeader(204)
}