Repository: isucon/isucon11-qualify (language: go)

Issue:
[bench] シナリオに失敗したら同じシナリオを繰り返すように
timeout とかで verify から逃げられるため


Discussion / hints:

Fix patch:
diff --git a/bench/scenario/load.go b/bench/scenario/load.go
index aa03ce33a..2fc3696b7 100644
--- a/bench/scenario/load.go
+++ b/bench/scenario/load.go
@@ -250,12 +250,13 @@ func (s *Scenario) loadNormalUser(ctx context.Context, step *isucandar.Benchmark
 			continue
 		}
 
+		var isSuccess bool
 		if nextScenarioIndex == 0 {
-			s.requestNewConditionScenario(ctx, step, user, targetIsu, &readConditionCount)
+			isSuccess = s.requestNewConditionScenario(ctx, step, user, targetIsu, &readConditionCount)
 		} else if nextScenarioIndex == 1 {
-			s.requestLastBadConditionScenario(ctx, step, user, targetIsu)
+			isSuccess = s.requestLastBadConditionScenario(ctx, step, user, targetIsu)
 		} else {
-			s.requestGraphScenario(ctx, step, user, targetIsu, randEngine)
+			isSuccess = s.requestGraphScenario(ctx, step, user, targetIsu, randEngine)
 		}
 
 		// たまに signoutScenario に入る
@@ -263,8 +264,10 @@ func (s *Scenario) loadNormalUser(ctx context.Context, step *isucandar.Benchmark
 			signoutScenario(ctx, step, user)
 		}
 
-		// 次のシナリオに
-		nextScenarioIndex += 1
+		if isSuccess {
+			// 次のシナリオに
+			nextScenarioIndex += 1
+		}
 	}
 }
 
@@ -381,7 +384,7 @@ func (s *Scenario) initViewer(ctx context.Context) model.Viewer {
 }
 
 // あるISUの新しいconditionを見に行くシナリオ。
-func (s *Scenario) requestNewConditionScenario(ctx context.Context, step *isucandar.BenchmarkStep, user *model.User, targetIsu *model.Isu, readConditionCount *ReadConditionCount) {
+func (s *Scenario) requestNewConditionScenario(ctx context.Context, step *isucandar.BenchmarkStep, user *model.User, targetIsu *model.Isu, readConditionCount *ReadConditionCount) bool {
 	// 最新の condition から、一度見た condition が帰ってくるまで condition のページングをする
 	nowVirtualTime := s.ToVirtualTime(time.Now())
 	request := service.GetIsuConditionRequest{
@@ -394,7 +397,7 @@ func (s *Scenario) requestNewConditionScenario(ctx context.Context, step *isucan
 		for _, err := range errs {
 			addErrorWithContext(ctx, step, err)
 		}
-		return
+		return false
 	}
 
 	// GETに成功したのでその分を加点
@@ -420,10 +423,11 @@ func (s *Scenario) requestNewConditionScenario(ctx context.Context, step *isucan
 	targetIsu.LastReadConditionTimestamps = nextTimestamps
 
 	// このシナリオでは修理しない
+	return true
 }
 
 // あるISUの、悪い最新のconditionを見に行くシナリオ。
-func (s *Scenario) requestLastBadConditionScenario(ctx context.Context, step *isucandar.BenchmarkStep, user *model.User, targetIsu *model.Isu) {
+func (s *Scenario) requestLastBadConditionScenario(ctx context.Context, step *isucandar.BenchmarkStep, user *model.User, targetIsu *model.Isu) bool {
 	// ConditionLevel最新の condition から、一度見た condition が帰ってくるまで condition のページングをする
 	nowVirtualTime := s.ToVirtualTime(time.Now())
 	request := service.GetIsuConditionRequest{
@@ -446,10 +450,10 @@ func (s *Scenario) requestLastBadConditionScenario(ctx context.Context, step *is
 		for _, err := range errs {
 			addErrorWithContext(ctx, step, err)
 		}
-		return
+		return false
 	}
 	if len(conditions) == 0 {
-		return
+		return true
 	}
 
 	// こっちでは加点しない
@@ -459,14 +463,14 @@ func (s *Scenario) requestLastBadConditionScenario(ctx context.Context, step *is
 
 	// すでに改善してるなら修理とかはしない
 	if targetTimestamp <= targetIsu.LastReadBadConditionTimestamps[0] {
-		return
+		return true
 	}
 	if solveCondition != model.IsuStateChangeNone {
 		// 状態改善
 		// バッファがあるのでブロック率は低い読みで直列に投げる
 		select {
 		case <-ctx.Done():
-			return
+			return false
 		case targetIsu.StreamsForScenario.StateChan <- solveCondition:
 		}
 		step.AddScore(ScoreRepairIsu)
@@ -491,6 +495,8 @@ func (s *Scenario) requestLastBadConditionScenario(ctx context.Context, step *is
 		}
 	}
 	targetIsu.LastReadBadConditionTimestamps = nextTimestamps
+
+	return true
 }
 
 //GET /isu/condition/{jia_isu_uuid} を一度見たconditionが出るまでページングする === 全てが新しいなら次のページに行く。補足: LastReadTimestamp は外で更新
@@ -627,7 +633,7 @@ func isNewData(isu *model.Isu, condition *service.GetIsuConditionResponse) bool
 }
 
 // あるISUのグラフを見に行くシナリオ
-func (s *Scenario) requestGraphScenario(ctx context.Context, step *isucandar.BenchmarkStep, user *model.User, targetIsu *model.Isu, randEngine *rand.Rand) {
+func (s *Scenario) requestGraphScenario(ctx context.Context, step *isucandar.BenchmarkStep, user *model.User, targetIsu *model.Isu, randEngine *rand.Rand) bool {
 	// 最新の condition から、一度見た condition が帰ってくるまで condition のページングをする
 	nowVirtualTime := s.ToVirtualTime(time.Now())
 	// 割り算で切り捨てを発生させている(day単位にしている)
@@ -639,7 +645,7 @@ func (s *Scenario) requestGraphScenario(ctx context.Context, step *isucandar.Ben
 		for _, err := range errs {
 			addErrorWithContext(ctx, step, err)
 		}
-		return
+		return false
 	}
 
 	// AddScoreはconditionのGETまで待つためここでタグを持っておく
@@ -683,12 +689,12 @@ func (s *Scenario) requestGraphScenario(ctx context.Context, step *isucandar.Ben
 		conditions, hres, err := getIsuConditionAction(ctx, user.Agent, targetIsu.JIAIsuUUID, request)
 		if err != nil {
 			addErrorWithContext(ctx, step, err)
-			return
+			return false
 		}
 		err = verifyIsuConditions(hres, user, targetIsu.JIAIsuUUID, &request, conditions, targetIsu.LastReadConditionTimestamps)
 		if err != nil {
 			addErrorWithContext(ctx, step, err)
-			return
+			return false
 		}
 	}
 
@@ -702,6 +708,8 @@ func (s *Scenario) requestGraphScenario(ctx context.Context, step *isucandar.Ben
 	if targetIsu.LastCompletedGraphTime < newLastCompletedGraphTime {
 		targetIsu.LastCompletedGraphTime = newLastCompletedGraphTime
 	}
+
+	return true
 }
 
 // unix timeのtimestampをその「日」に切り捨てる


Test patch: