@mcakaneo
Я люблю пиццу

Как выборочно удалить устаревшие кэшированные результаты из базы данных?

Допустим в классе UserRepository есть методы:
findByFirstname($firstname)
findByCity($city)
findByAge($minAge, $maxAge)

Также, допустим, есть PostRepository с методом:
findByUser($id)
findByName($postName)

Допустим все эти методы уже выполнялись и результаты их выполнения уже находятся в кэше. При этом стоит заметить, что, например, если метод findByCity() выполнился несколько раз с разными параметрами, то соответственно после каждого выполнения в кэш добавлялся новый результат.

Допустим пользователь(User) удаляет свою учётную запись, а вместе с ней удаляются его посты(не знаю можно ли так делать, но суть не в этом). Теперь нужно удалить результаты из кэша, в которых присутствует этот пользователь, чтобы никто не получил устаревшие данные. Но как это правильно сделать? Есть ли в Doctrine такая функциональность, чтобы из кэша автоматически удалялись только те результаты, в которых присутствует этот пользователь, которого уже не существует?
Я знаю, что в Doctrine есть QueryBuilder, который и используется в методах выше. Этот объект строит запрос в базу данных и возвращает объект запроса(Query), у которого можно вызвать метод useResultCache() и передать в этот метод ID, по которому потом можно удалить из кэша результат(ы) этого запроса. Я знаю, что можно разным запросам(объектам Query) передавать в useResultCache() один и тот же ID и удалять из кэша все результаты этих запросов по этому ID.
Я использовал EventManager и создал слушателя, метод которого срабатывает после отработки EntityManager::flush(), но печаль в том, что логику удаления нужно писать самому, то есть смотреть какая entity была сохранена, удалена или обновлена и на основе этой информации удалять определённые результаты из кэша, которые содержат устаревшие данные. Я сомневаюсь что Doctrine сама может с этим разобраться, но может есть какие-то способы, которые облегчают это?

И еще очень важная деталь: допустим в кэше находятся 2 разных результата, которые возвратил метод findByCity(), в первом результате, который возвратил метод findByCity( 'Moscow'), находится User, который уже на самом деле удалён, а во втором результате, который возвратил метод findByCity( 'Kyev'), этого User нет, ведь он из Москвы. То есть второй результат удалять не нужно, в нём нет несуществующего User, а значит нет и устаревших данных.
Но чтобы выборочно удалить только те результаты, которые точно содержат устаревшие данные, нужно проверить находится ли в них удалённый User. Это всё слишком гемморно, поэтому мне кажется, что лучше таких проверок не делать, а просто удалять все результаты, которые потенциально могут содержать устаревшие данные. Но даже это кажется мне слишком неприятным делом, которое займёт много времени и в котором можно допустить кучу ошибок.

Если есть литература или статья где об этом адекватно написано, то подскажите такую. Я вот нашел такую статью https://www.gregfreeman.io/2012/invalidating-the-r... пока еще не опробовал, ведь еще надеюсь, что есть способы получше.
  • Вопрос задан
  • 88 просмотров
Решения вопроса 1
gzhegow
@gzhegow
aka "ОбнимиБизнесмена"
Именно так, инвалидация кеша довольно "весёлое" занятие.
Немного упрощает работу с этим на мой взгляд группировка кешей - это когда кеш хранится не просто в файле или редисе с ключем в виде хеша, а когда он хранится типа такой строкой "models.users.find.city", еще я юзаю бывает константу __METHOD__ магическую - там неймспейс сразу есть (хотя это годится в основном для будущей ручной очистки, чем для автоудаления), осталось примесь добавить в виде параметров под юзера, кстати эта примесь тоже может например base64 стать потом и служить ключем (user:1 -> base64) и потом найти запись где есть такой-то base64. По крайней мере ты получаешь возможность найти все кеши связанные с city и их снести руками.

Дальше начинается весёлая игра, которая называется - добавишь лишний тег - кеш будет бесполезен, не добавишь тег - и каждый раз будешь чистить то, что чистить не нужно. Думаю это можно хэндлить как ты сказал - слушателями.

Опять же есть колхоз на тему сохрани номер сотни пользователя для 912-го - девять. И снеси сотню кешей например. Или тысячу. Всяко лучше чем 100%. Ну и конечно подумать над необходимостью кешировать данные юзеров. Может есть возможность кешировать только неизменяемую часть. Или не кешировать вовсе то, что юзеры постоянно меняют.

Так например кеш дерева категорий который показывается всем имеет смысл кешировать и очищать. А кеш профиля юзера приведет к тому что для миллиона юзеров миллион кешей, и лучше пусть загружается чем выжрет гиг оперативки под хранение того, что вот вот изменится

Чем больше тегов - тем менее эффективный кеш и больше занятой памяти на хранение одинаковых вещей, но в то же время тем проще его точечно найти и снести. С другой стороны чем больше слушателей даже очень простых - тем больше система хочет превратиться в шину сообщений (черт ногу сломает какой слушатель что делает и поскольку логи анализируются потом вручную - то здравствуйте "что-то сломалось") и заставить тебя написать сагу.

Однако думаю общий принцип здесь только в том, что при удалении чего-то запускается дополнительно удаление кеша чего-то. Хочешь это отдельно положить - делай листенеры и так далее. Но я бы это запхал туда же где делается само удаление. Помоему если ты знаешь что удаление вот тут - то разумнее чтобы и кеш тут же удалялся, а не где-то в папке с лиснерами.

Но наверняка кто-нибудь знает как проще.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
19 апр. 2024, в 18:38
1500 руб./в час
19 апр. 2024, в 18:36
1500 руб./за проект
19 апр. 2024, в 18:36
30000 руб./за проект