проблема с cron

mixas

Новичок
проблема с cron

у меня следующая проблема: есть скрипт, который вызывается через cron:
PHP:
include 'config.php';
$start_1 = strtok(microtime(), " ") + strtok(" ");

$result = mysql_query('SELECT * FROM users WHERE to_send = 1 LIMIT 150');
$i=0;
while($row=mysql_fetch_array($result)) {
send($row);
$i++;
}

$end_1= strtok(microtime(), " ") + strtok(" ");
$total = number_format($end_1 - $start_1,6);
send_email($superadmin_email, date("H:i:s")."\n".'send '.$i.' messages in '.$total.' sek.');

function send($row)
{
   mysql_query('UPDATE users  SET to_send = 0 WHERE  uid = '.$row['uid']);
   $text = 'привет '.$row['name'];
   send_email($row['email'],$text); 

}
проблема в том, что всё время отсылается по 2 письма каждому юзеру. почему так получается?
вернее не всё время, а иногда одно письмо, но чаще по 2.
после того, как я добавил отправку письма на мой адрес получаю я вот:
14:51:16
send 150 messages in 74.242626 sek.
14:53:14
send 150 messages in 72.828910 sek.
14:53:19
send 150 messages in 77.463905 sek.
14:56:51
send 150 messages in 50.266515 sek.
14:59:12
send 150 messages in 70.398172 sek.
15:03:04
send 150 messages in 63.251978 sek.
15:07:11
send 150 messages in 69.387002 sek.
15:10:27
send 150 messages in 146.001755 sek.
15:10:27
send 150 messages in 145.883577 sek.
15:11:26
send 150 messages in 85.099325 sek.
15:13:09
send 137 messages in 67.506306 sek.
15:14:01
send 0 messages in 0.000081 sek.
15:16:01
send 0 messages in 0.005948 sek.
15:16:01
send 0 messages in 0.000085 sek.
 

TutanXamoN

Новичок
function send_email
в студию

-~{}~ 10.03.09 00:02:

А юзвери почту часом не через аутглюк берут? Ибо есть у него интересные моменты...
 

mixas

Новичок
send_email в порядке, она используется не только по крону, и всегда оправляет почту только в одном экземпляре.
 

TutanXamoN

Новичок
Интересно смотреть на лог:
Код:
14:53:14
send 150 messages in 72.828910 sek.
14:53:19
send 150 messages in 77.463905 sek.
____________________________
Судя по времени события и по продолжительности работы оба скрипта стартовали одновременно.
____________________________
Код:
15:10:27
send 150 messages in 146.001755 sek.
15:10:27
send 150 messages in 145.883577 sek.
____________________________
Та же фигня
____________________________

Разберись что с кроном творится для начала.

Также важный момент: список сообщений для отправки ты извлекаешь весь и сразу, а статус отправлено ставишь только после фактической отсылки, в итоге сообщению №150 при записи
Код:
15:10:27
send 150 messages in 145.883577 sek.
статус отправлено будет присвоен почти через 2,5 минуты(!!!) после того как оно досталось из базы.

-~{}~ 10.03.09 00:40:

глядя на лог могу сказать что сообщения достаются(практически бесперебойно) раз в 2 минуты - то есть сообщения которые не отправились скриптом номер один за 120 секунд будет продолжать отправлять первый скрипт + запуститься второй (так как прошло две минуты) и увидит в базе сообщения, которые продолжает отправлять скрипт номер один, со статусом to_send
 

mixas

Новичок
спасибо за совет!!
значит нужно как то так?

PHP:
include 'config.php';
$jobs = array();

$result = mysql_query('SELECT * FROM users WHERE to_send = 1 LIMIT 150');
while($row=mysql_fetch_array($result)) {
	$jobs[] = $row;
       mysql_query('UPDATE users SET to_send = 0 WHERE uid = '.$row['uid']);
}
foreach($jobs as $k => $job) {
	send($job);	
}


function send($row)
{   
   $text = 'привет '.$row['name'];
   send_email($row['email'],$text); 
}
 

TutanXamoN

Новичок
Во как-то так) Не совсем так, но по идее это уже должно решить проблему.
 

MuXaJIbI41981

Новичок
mixas ну например собрать все айдишки в массив обновить потом одним запросом
 

dimagolov

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

п.с. не страдайте фигней, а делайте рассылки через менеджеров рассылки, типа mailman.
 

MuXaJIbI41981

Новичок
dimagolov да но я просто хотел человеку показать как можно уменьшить кол-во запросов .... лучше сразу писать правильно чем потом переделывать
 

mixas

Новичок
я переделал скрипт. теперь рассылает всё как надо.

PHP:
include('config.php');

if(is_file('email.pid')) {
  die("Another thread is running now. Terminated.");
}

touch('email.pid');

$result = mysql_query('SELECT * FROM table WHERE to_send=1');
while(false !== ($row = mysql_fetch_assoc($result))) {
  if(send($row)) $send[] = $row['id'];
}
$result = mysql_query('UPDATE table SET to_send=0 WHERE id IN ('.implode(', ', $send).')');

mysql_close();
unlink('email.pid');
про сбор айдишников в массив я понял, теперь буду только так делать, где возможно.
 

fixxxer

К.О.
Партнер клуба
если скрипт вылетит, то уже никогда не запустится

правильнее так как то

PHP:
define('PIDFILE', dirname(__FILE__).'/email.pid');
define('ERR_EPERM', 1); // на FreeBSD, для других ОС может отличаться
$pid = false;
if (file_exists(PIDFILE)) $pid = (int)file_get_contents(PIDFILE);
if ($pid 
    && posix_kill($pid, 0) // man 2 kill: The sig argument [...] may be 0, in which case 
                 //error checking is performed but no signal is actually sent.
    && posix_get_last_error() != ERR_EPERM // The sending process is not the super-user 
                 //and its effective user id does not match the effective user-id of the receiving process
) { 
     die("Another thread is running now. Terminated."); 
}
file_put_contents(PIDFILE, posix_getpid());
// ....work
unlink(PIDFILE);
 

Савелей

Новичок
Зря Вы собираете ID в массив,
если скрипт вылетит в момент цикла, что тогда???

если обновлять в цикле то 99% кому отправили будет флаг "send", а так все по новой.

меня из-за этого забанили на одном из free-хостингов:)
 
Сверху