1

GoogleAppEngineで成績表を作成しています。私は、評価期間ごとに各学生の成績を追跡します。採点期間は重複する可能性があります。一度に数百のこれらの成績を表示する可能性があるため、サーバーで成績を事前に計算します。したがって、1人の学生に対して、私は多くの計算された成績を持っている可能性があります-各成績期間に1つ。

これで、教師はクイズから新しいスコアを入力します。そのスコアは、多くの評価期間に分類される可能性があるため、計算された評価の多くに影響を与える可能性があります。影響を受けるすべてのグレードを再計算する必要があります。採点期間ごとに、関連するすべてのスコアを取得し、それらのスコアに対して複雑なルーチンを実行する必要があるため、これには長い時間がかかる可能性があります。30秒では不十分だと思います。特に、今日のデータストアの速度が遅い場合はなおさらです。さらに、失敗はオプションではありません。一部のグレードが更新され、他のグレードが黙って古くなることは容認できません。

ですから、タスクキューについて学ぶのに最高の時間だと思います。

私はDB構造などの専門家ではありませんが、私がやりたいことの概要は次のとおりです。

public ReturnCode addNewScore(Float score, Date date, Long studentId)
{
    List<CalculatedGrade> existingGrades = getAllRelevantGradesForStudent(studentId, date);

    for (CalculatedGrade grade : existingGrades)
    {
        grade.markDirty(); //leaves a record that this grade is no longer up to date
    }

    persistenceManager.makePersistentAll(existingGrades);
    //DANGER ZONE?
    persistenceManager.makePersistent(new IndividualScore(score, date, studentId));

    tellTheTaskQueueToStartCalculating();

    return OMG_IT_WORKED;
}

これは、関連するすべてのグレードをダーティとしてマークするための迅速な方法のようです。途中で失敗した場合は、失敗が返され、クライアントは再試行することを認識します。クライアントが後でダーティグレードをフェッチしようとすると、そこでエラーを返すことができます。

次に、タスクキューコードは次のようになります。

public void calculateThemGrades()
{
    List<CalculatedGrade> dirtyGrades = getAllDirtyGrades();

    try
    {
        for (CalculatedGrade grade : dirtyGrades)
        {
            List<Score> relevantScores = getAllRelevantScores();
            Float cleanGrade = calculateGrade(relevantScores);
            grade.setGrade(cleanGrade);
            grade.markClean();

            persistenceManager.flush();
        }
    }
    catch(Throwable anything)
    {
        //if there was any problem, like we ran out of time or the datastore is down or whatever, just try again
        tellTheTaskQueueToStartCalculating()
    }
}

これが私の質問です:これは、新しいスコアが追加された後、クリーンとマークされた計算されたグレードが決してないことを保証しますか?

特定の懸念事項:

  • 危険ゾーンの周りの最初のスニペットでは、existingGrades常に新しいものの前に保持されますか?IndividualScore
  • IndividualScore別のスレッドが危険ゾーンでタスクキューコードを開始して、新しいものが実際に入力される前に、それらの既存のグレードが再びクリーンとマークされる可能性はありますか?もしそうなら、どうすればそれが起こらないようにすることができますか(すべてのグレードのトランザクションがアウトになっています)?
  • persistenceManager.flush()午後が閉じていなくても、部分的に行われた計算を保存するのに十分ですか?

これは一般的な種類の問題であるに違いありません。チュートリアル、特にappengineのチュートリアルへのリンクをいただければ幸いです。たくさん読んでくれてありがとう!

4

1 に答える 1

2

競合状態が心配な場合は、ブール値のダーティ フラグを使用しないでください。代わりに、タイムスタンプのペアを使用してください。レコードをダーティとしてマークする場合は、「ダーティ」タイムスタンプを更新します。

成績の計算を開始するときは、「ダーティ」タイムスタンプが何であったかを書き留めてください。

成績の計算が終了したら、開始時に読み取った「ダーティ」タイムスタンプの値と等しくなるように「クリーン」タイムスタンプを更新します。これは、そのタイムスタンプの時点でその成績を新しいデータと同期したことを示します。

「ダーティ」タイムスタンプが「クリーン」タイムスタンプより大きいレコードはすべてダーティです。2 つが一致するレコードはすべてクリーンです。シンプルで効果的。タスクキュー タスクが既に成績を計算している間に、別のリクエストが特定の成績に影響を与える新しいデータを追加した場合、「ダーティ」タイムスタンプは更新された「クリーン」タイムスタンプと一致しないため、タスクキューはレコードを考慮します。まだ汚れているので、もう一度処理してください。

于 2011-02-24T23:08:34.400 に答える