Бот, который пишет вовремя
Дуа-бот присылает нужное дуа в момент, когда оно уместно: перед дорогой, в пятницу, в дождь, в затмение, перед постом. Не рассылка по расписанию, а два десятка поводов, каждый из которых нужно уметь распознать — и не ошибиться.
И что он умеет?
Двадцать поводов и ни одного спама
Человек выбирает, насколько плотно с ним разговаривать: три пресета — от коротких утренних и вечерних азкаров до редких поводов вроде затмения. Дальше бот молчит, пока повод не наступит.
Внутри — 31 дуа с огласовками, транслитерацией, русским переводом, источником и честной пометкой о степени достоверности хадиса. Времена намаза внутри Дагестана берутся из 27 таблиц муфтията на каждый день года, за его пределами считаются по координатам и помечаются как приблизительные — потому что расчёт и таблица расходятся на минуты, и делать вид, что это одно и то же, нельзя.
- Дуа в подборке
- 31, с источником и огласовками
- Города
- 5754 с часовым поясом
- Тесты
- 77 файлов, гоняются против живого Postgres
- От первого коммита до боя
- 2 дня. Дальше правки шли уже на живом боте
А что там сложного? Бот же.
Сложное начинается там, где никто не смотрит
- Не отправить дважды важнее, чем не пропустить. Сообщение помечается «отправляется» до обращения к Telegram, а не после. Если процесс упадёт в этот момент, запись останется висеть — и уборщик пометит её неудачной, а не отправит заново. Дубль в личной переписке раздражает сильнее, чем пропуск.
- Очередь живёт в PostgreSQL, Redis нет. Задачи разбираются порциями, и база сама не даёт двум процессам взять одну и ту же. Повторный запуск планировщика за те же сутки ничего не задваивает — упирается в ограничение базы. Одна база вместо двух — меньше того, что может разъехаться ночью.
- Погода: решает первый ответивший источник. Метеосводки аэропортов, норвежская модель и открытая модель опрашиваются по очереди. Голосование «видит ли хоть кто-нибудь дождь» отвергли сразу: 5 августа над Махачкалой шла настоящая гроза, а расчётные модели показывали десятые доли миллиметра мороси — большинство было бы против дождя.
- Затмения считаются локально, без единого внешнего запроса. Глобальный календарь кандидатов считается один раз на четыре года, и только рядом с датой запускается точный локальный расчёт — иначе пришлось бы перебирать новолуния для каждого человека каждые сутки.
А кто это всё потом обслуживает?
Выкатка без моего участия
Каждый push проходит проверку типов, линтер, миграции и тесты против настоящего Postgres — не заглушек. Только после зелёного прогона собирается образ. Сервер забирает его сам, таймером раз в пять минут: входящий доступ на машину не нужен, а значит нечего ломать и некуда терять ключи.
Так же собран и сайт, который ты сейчас читаешь.