Есть коллекция документов в монге, которые представляют из себя, скажем, заказы в интернет магазине.
{"_id": ..., "status": "new", "expiring_at": 2018-02-04 23:40:40.493Z}
Каждый заказ, в отсутствии оплаты, должен через определенное время протухнуть. При протухании ему нужно установить соответствующий статус (expired) и сделать запись в логе об этом. Допустимо помечать заказы протухшими чуть позже, чем указано в его свойствах, но никогда раньше.
Как это правильно реализовать?
Свои мысли:
1. Есть ttl indexes, которые, за счет фонового процесса, позволяют задавать время жизни записям, но мне не нужно их удалять, только менять статус. Кроме того, нечего будет записать в лог.
2. Каждый раз при обращении к записи, проверять не истекло ли ее время жизни (т.е. делать статус вычисляемым значением от текущего времени и свойств заказа) тоже не хочется.
3. Использовать оптимистическую блокировку. При записи данных пытаться обновлять документ с заданной версией, периодически искать и помечать устаревшие записи через findAndUpdate($set status, $inc vesion, new true). Тут смущает, что это операция над одной записью. Просто update(), который умеет обновлять документы пачками не сообщает на выходе какие именно документы он обновил.
// upd если логи хранить в БД в той же коллекции, то к третьему варианту еще можно кроме увеличения версии и смены статуса, делать $push в поле с логами. это позволит забить на единичные обновления через findAndUpdate и пользоваться просто update. + optimistic lock.
// upd 2
остановился все же на фоновом процессе и optimistic lock
if err := col.Find(query).All(items); err != nil {
return fmt.Errorf("unable to search expired orders: %s", err)
}
for _, item := range *items {
if err := item.Expire(); err != nil {
return fmt.Errorf("unable to mark the order as expired: %s", err)
}
item.Version++
if err := col.Update(bson.M{"_id": item.ID, "version": item.Version - 1}, &item); err != nil {
return fmt.Errorf("unable to store expired order: %s. possible a concurrent access issue", err)
}
}
return nil
Поскольку каждая сущность сохраняется отдельно, проблем с выяснением их итогового состояния нет.