Я делаю сборник оценок на движке приложений Google. Я отслеживаю оценку каждого студента за период оценки. Оценочные периоды могут перекрываться. Поскольку я могу отображать сотни этих оценок одновременно, я предварительно рассчитываю оценки на сервере. Таким образом, для каждого учащегося у меня может быть много рассчитанных оценок - по одной на каждый оценочный период.
Теперь учитель вводит новый результат из теста. Эта оценка может повлиять на многие из рассчитанных оценок, поскольку она может приходиться на многие периоды оценки. Мне нужно пересчитать все пострадавшие оценки. Это может занять много времени, так как для каждого оценочного периода мне нужно получить все соответствующие оценки и выполнить сложную процедуру над этими оценками. Я думаю, 30 секунд недостаточно, особенно если хранилище данных сегодня работает медленно. Кроме того, отказ не вариант. Для некоторых классов недопустимо обновление, а для других - молчаливое устаревание.
Так что я думаю про себя, какое прекрасное время, чтобы узнать об очереди заданий!
Я не специалист по структуре БД или чему-то еще, но вот краткое описание того, что я хочу сделать:
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. Спасибо за прочтение!