Проблема с почтовыми рассылками drupal.ru

Аватар пользователя axel axel 16 июня 2009 в 14:04

Жалобы на почтовые рассылки подписанных материалов поступают уже часто, меня это слегка достало и я полез смотреть что там происходит. Очередное включение модуля subscriptions_mail привело к тому, что сайт начал развозить по всем адресам рассылки наверно с 1900 года :( Ещё раз мои извинения перед пользователями, которые обнаружили в почтовом ящике не очень свежие новости с drupal.ru.

Детальное изучение показало, что в таблице subscription_queue набралось уже 6.5 млн. записей - если правильно понял архитектуру модуля, это общий список, по которому регулярно идёт рассылка. Причём выборка записей для рассылки осуществляется имхо не очень удачно:

<?php
/**
* Implementation of hook_cron().
*
* Takes items from {subscriptions_queue} and generates notification emails.
*/
function subscriptions_mail_cron() {

// тут кусок пропущен

while (($mails_allowed <= 0 || $single_count + count($mails) < $mails_allowed)
&& $total_seconds - timer_read('page')/1000 > $available_seconds*variable_get('subscriptions_cron_percent', 50)/100) {
$result = db_query_range('SELECT * FROM {subscriptions_queue} WHERE last_sent + send_interval < %d ORDER BY sqid', time(), 0, 1);
if (!($s = db_fetch_array($result))) {
break; // No more subscriptions, terminate loop.
}

?>

Т.е. из этой огромной таблицы мы пробегаем число раз заданное в настройках модуля (переменная $mails_allowed) за каждый запуск крона. Один такой запрос исполняется на нашем vps ~30 сек. Т.е. минимум 30 с. получаем на отправку одного письма (3.6 млн. писем значит разошлются примерно за 3.5 года). В общем понятно тогда, почему кому-то приходят письма многомесячной давности, кому ничего.

Обновил таблицу, чтобы не было старых подписок - last_sent был везде проставлен в текущее время.

mysql> SELECT unix_timestamp() FROM dual;
+------------------+
| unix_timestamp() |
+------------------+
|       1245145244 |
+------------------+
1 ROW IN SET (0.01 sec)

mysql> UPDATE dru_subscriptions_queue SET last_sent = 1245145244;
Query OK, 6519502 ROWS affected (2 MIN 37.17 sec)
ROWS matched: 6519502  Changed: 6519502  Warnings: 0

Но сразу после этого выборка даёт:

mysql> SELECT COUNT(*) FROM dru_subscriptions_queue WHERE last_sent + send_interval < unix_timestamp();
+----------+
| COUNT(*) |
+----------+
|  3639864 |
+----------+
1 ROW IN SET (31.13 sec)

Так что помогло не сильно, т.к. send_interval у половины записей стоит 1 - "рассылка сразу при обновлении материала". По 3.6 млн. записей оно будет ходить тоже не один год.

Как вариант - сбросить все настройки подписок drupal.ru и начать заново. Только нет гарантий, что за пару лет не наберётся тоже самое. Либо с этой гигантской очередью какой-то глюк и она не должна была получиться таких размеров? Модуль стоит давно и не раз уже обновлялся, мейби что-то покосячилось в один из апгрейдов? Собственно с учётом не такого уж большого количества нодов на drupal.ru и терминов выходит слишком подозрительно много, но на первый взгляд выборка таблицы выглядит ок. В общем, жду советов от тех кто ковырялся в модуле и разбирался детально с его работой. Пока отрубил его обратно, пока в спамеры не записали.

UPD Ага, кажется начинаю понимать. Если юзер подписался на чей-то блог, в queue прописываются записи для каждой ноды этого блога что-ли? :\

0 Thanks