Как работают отложенные публикации в Эгее

Смысл «отложенности» с точки зрения веб-программирования

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

Допустим, автор запланировал выход заметки на 15:00. Как добиться, чтобы в 15:00 заметка вышла? Веб-сервер умеет отвечать только на запросы, он не умеет по собственной инициативе просыпаться и что-то начинать делать. И тут почему-то многие разработчики начинают думать в сторону крона — планировщика запуска задач по расписанию.

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

Чтобы заметка вышла в 15:00, в 15:00 ничего не должно произойти, буквально ничего. Потому что что вообще значит «вышла»? Допустим вот сервер может проснуться в 15:00 и начать действовать, что он должен сделать-то? Отправить эту заметку на случайный айпи-адрес?..

Сама фраза «заметка должна выйти в 15:00» означает только одно: на все запросы, сделанные начиная с 15:00 нужно отвечать сайтом, где уже опубликована эта заметка. Если на сайт кто-то зайдёт в 14:54, а потом кто-то в 15:19, то заметку нужно будет показать по второму запросу, вот и всё.

Чтобы это работало, нужно было сделать три вещи. Первая — это дать назначать в качестве даты-времени выхода заметки дату-время из будущего. Вторая — при формировании страниц сайта отображать и вообще учитывать только заметки, время которых уже наступило. Третья — доработать систему кеширования, чтобы в 15:19 сайт не открывался в устаревшем виде из кеша.

Доработка системы кеширования

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

А тут нам нужно сделать, чтобы кеш каким-то чудом в 15:00 удалился несмотря на то, что автор ничего не редактирует. Разумеется, в 15:00 мы ничего делать не будем; решать этот вопрос мы будем в 15:19, когда читатель обратится за заметкой.

Но откуда мы узнаем, что именно запрос в 15:19 потребует пересборки кеша, а на тот, что был в 14:54, можно ещё отвечать из кеша? Ведь время публикации заметки хранится в базе данных, а если мы будем ходить в неё на каждый запрос для проверки, то это обессмыслит само существование кеша!

Чтобы решить эту задачу, пришлось реализовать запланированное устаревание кеша. Рядом с кешем на диске хранится файл с датами-временами, в которые кеш должен устаревать. Каждый раз, когда пользователь планирует выход заметки на будущее, эти дата-время записываются в этот файл. Перед тем, как выдать данные из кеша, Эгея смотрит: а нету ли в файле дат-времён устаревания даты-времени из прошлого? Если есть, значит кеш устарел, и его надо удалить, а уже потом собирать страницу по-честному, из базы.

Таким образом фича планирование заметок на будущее фактически сводится к фиче планирования устаревания кеша.

Подписаться на блог
Отправить
Запинить
Дальше
4 комментария
Александр 19 дн

И тут почему-то многие разработчики начинают думать в сторону крона — планировщика запуска задач по расписанию.

У тебя реализация абсолютно правильная с учетом требований. Думаю, многие разработчики сразу начинают переусложнять из-за прошлого опыта. Допустим, ты захочешь при публикации заметки рассылать какие-то емэйлы или пуши, чтобы юзеры узнали о ней (по аналогии с отложенными сообщениями в Телеграме). Придется делать что-то похожее на крон. А если в системе уже есть планировщик задач, то, думает разработчик, почему бы на этот же механизм не повесить публикацию заметки :)

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

Короче, надо многое взвешивать. Но у тебя есть четкое требование про шаред-хостинг, так что решение разумное.

Petr 19 дн

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

Илья Бирман 18 дн

Пример комментария, на который остаётся только схватиться за голову от бессилия.

Petr 18 дн

схватиться за голову от бессилия

Я понимаю, о чем вы: хочется, чтобы работало без крона. Конкретно в этом случае да, удалось поставить костыль. В других случаях, например при отправке письма в заданное время, так уже не получится.

Виктор Ерофеев 18 дн

Все действия, которые можно выполнить заранее, лучше выполнить заранее.

Так и в этом случае: если мы можем записать запланированное время, указать кешу что ему нужно заранее учесть время (мы его знаем), и какие-то дополнительные штуки провернуть — например, обработать содержимое заметки, рендер, медиа итд итп — надо так и сделать.

Тут остается только одобрительно кивнуть на подход.

Мои книги