Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Не удаляется файл блокировки (падает процесс аггрегации) .../AggregateCommand.php.lock file #61

Closed
mobilesfinks opened this issue Feb 17, 2014 · 31 comments

Comments

@mobilesfinks
Copy link

After some time cant see data in web.
After try start Crontab task manually get error:

Cannot run data aggregating: the another instance of this script is already executing. Otherwise, remove /var/www/pinboard/src/Pinboard/Command/AggregateCommand.php.lock file

but nothing running at this time.
to resolve this issue, to the end of aggregate command in crontab add
&& rm -rf /%PATH_to_lockFIle%/AggregateCommand.php.lock

pinboard v.1.1

@muxx
Copy link
Member

muxx commented Feb 17, 2014

File AggregateCommand.php.lock creates in the begin of aggregate command and deleted at the end of this command. If it don't removed, other aggregate command is running or last execution failed.

@mobilesfinks
Copy link
Author

(можно по русски? Язык сломаю объяснять)
В общем ничего не аггрегируется, пока не удалю этот файл. После этого опять всё начинает работать. Видимо в какой то момент он не удаляется.

@muxx
Copy link
Member

muxx commented Feb 17, 2014

Этот файл создается вначале команды агрегации и должен удаляться в конце. Он создается на случай, если параллельно решили запустить еще один command, или если команда сломалась, чтобы больше не запускалась сломанная команда. Может у тебя часто запускается это крон и они накладываются?

@mobilesfinks
Copy link
Author

Это я понял, что он создаётся и должен удаляться. Но отработка при ручном запуске происходит в течении 1-2 секунд - т.е. всё ОК. Крон стоит раз в 5 минут - т.е. тут вообще не должно быть проблем. Но вот случается, что то и файлик не удаляется.
После этого при запуске руками получаем такую ошибку. Соответственно дальше аггрегация не отрабатывает. В почту сыпется эта самая ошибка.

@ofedoryshyn
Copy link

у меня тоже раз в пару дней такое случалось, я добавил в cron
/1 * * * * /usr/bin/find /mnt/web/pinboard/src/Pinboard/Command/ -name '.lock' -type f -mmin +5 -exec mv {} /mnt/web/pinboard/src/Pinboard/Command/ ;

@gotlium
Copy link

gotlium commented Feb 20, 2014

это проблема самого пхп. видать что-то падает. и потому стоит использовать posix_kill.
вот вам простенький пример с php docs:

$PrevPid = file_get_contents($PathToPidFile);
if(($PrevPid !== FALSE) && posix_kill(rtrim($PrevPid),0)) {
    echo "Error: Server is already running with PID: $PrevPid\n";
    exit(-99);
} else {
    echo "Starting Server...";
}

@muxx
Copy link
Member

muxx commented Feb 20, 2014

@gotlium, а почему $PrevPid получается из file_get_contents()?

@gotlium
Copy link

gotlium commented Feb 20, 2014

Пример из доки. Объясню: Вы сохраняете pid процесса в файл, после пытаетесь проверить запущен ли процесс с таким PID, и если не запущен, то в этом случае запускаете команду.
В python есть модуль atexit. За предыдущий стаж работы с php, я ничего подобного не видел. Если процесс сигфолтится, то только PID поможет. Но надо так же проверять и имя процесса, для большой точности. Можно не заморачиваться. Просто сделать if (system('ps -aux|grep PROCESS') === 0) {echo "Still working";} else { echo "Starting"; }. Но именно в C/C+/Python/Bash - задача решается именно так.

@mbIkola
Copy link

mbIkola commented Feb 20, 2014

to resolve this issue, to the end of aggregate command in crontab add
&& rm -rf /%PATH_to_lockFIle%/AggregateCommand.php.lock

if (system('ps -aux|grep PROCESS') === 0) {echo "Still working";} else { echo "Starting"; }.

Но именно в C/C+/Python/Bash - задача решается именно так.

Мне хотелось бы вставить своих 5 копеек, и предостеречь вас от необдуманных решениях подобного рода. В юникс системах для процессов, которые не должны запускатся конкурентно, если этот процесс запускается но одном хосте - принято использовать flock
Как для bash скриптов, так и cron/php/c/c++/python.

Использование достаточно тривиально:
Bash:

(
         flock -n 9 || exit 1
         pinba-console aggregate  # your command here
) 9>/var/lock/mylockfile

PHP класс который мы используем в продакшине для этих целей

/**
 * @example
 * <code>
 *         $flock = new FLock(__CLASS__);
 *           if(!$flock->isLocked()){
 *                     $output->writeln("<error> Command ". $this->getName(). " already running in this system. Kill it or try again later </error>", OutputInterface::VERBOSITY_QUIET);                                                                    
 *           return -1;
 *           }
 * </code>
 *  This class wont work in case of php segfault. 
 */
class FLock {

    private $_lock = null;
    private $_lockfilepath = null;
    private $_is_locked = false;
    public function __construct($lock_name, $throw_exception = false) {
        $this->_lockfilepath = "/dev/shm/" . md5($lock_name);
        $this->_lock = fopen($this->_lockfilepath, "w+");
        if ( ! $this->_lock ) {
            throw new \Exception("Could not create lock file for writing "  . $this->_lockfilepath);
        }
        $this->_is_locked = flock($this->_lock, LOCK_NB + LOCK_EX);
        if ($this->_is_locked) {
            ftruncate($this->_lock, 0);
            fwrite($this->_lock, posix_getpid());
            fflush($this->_lock);
        } else if ( $throw_exception ) {
            throw new \Exception("Could not acquire exclusive lock for " . $lock_name);
        }

    }

    public function isLocked() {
        return $this->_is_locked;
    }

    public function __destruct() {
        if ( $this->_lock  && $this->_is_locked ) {
            flock($this->_lock, LOCK_UN);
            unlink($this->_lockfilepath);
        }
    }
}

Flock однако не поможет если необходимо запретить конкурентный запуск программы в кластере (более чем на одном хосте). В этом случае вам придется искать решения в виде реализации семафоров на базе memcache/redis
По озвученной issue мы решили проблему с пинбой следующим кронтабом:

*/5 * * * * flock -n /dev/shm/console.aggregate.lock -c '/home/pinboard/console aggregate'

@muxx
Copy link
Member

muxx commented Feb 24, 2014

@mbIkola А в каких ситуациях текущий механизм не срабатывал? Хочется выяснить, я ни разу не сталкивался с этой проблемой и не могу ее воспроизвести.

@mbIkola
Copy link

mbIkola commented Feb 24, 2014

Ну дык, как и описано в самом начале - проблемы возникали когда AggregateCommand.php.lock оставался после работы скрипта (неудалялся)
Вот такая банальная штука:
http://ubuntuone.com/6abVO5CmrKEg5cdEkS43Uw
в случае если пхп засегфолтится в середине работы скрипта (или свалится по нехватке памяти к примеру или таймауту на выполнение, или будет убит недобросовестынм админом потому что "грузит базу данных" ) не позволит команде запустится еще раз. Было выпилено из пхп кода и заменено на flock в кронтабе.

@muxx
Copy link
Member

muxx commented Feb 24, 2014

А почему обернули flock-ом в кронтабе, а не внутри через

$flock = new FLock(__CLASS__);
if(!$flock->isLocked()){
    $output->writeln("<error> Command ". $this->getName(). " already running in this system. Kill it or try again later </error>", OutputInterface::VERBOSITY_QUIET);                                                                    
    return -1;
}

Так в принципе нельзя или просто сделали как побыстрее?

@muxx
Copy link
Member

muxx commented Feb 24, 2014

Я к тому, что можно это внедрить в Pinboard, чтобы работало из коробки :)

@mbIkola
Copy link

mbIkola commented Feb 24, 2014

А почему обернули flock-ом в кронтабе, а не внутри через new Flock(__CLASS__)

это подразумевает модификацию кода пинборды. Стоит так же учесть что FLock отанлочит лок файл в случае сегфолта/killall -9 только на линукс системах (ядро релизит все локи в процессе закрытия файловых дескрипторов, что происходит вроде как автоматически). FLock не использовался ибо : необходимо редачить код пинбы (это дольше чем удалить пару строк из AggregateCommand и требует небольших навыков), и я не очень уверен даже в своем пхп коде. Просто потому что пхп, и люди бывает ошибаются.

@muxx
Copy link
Member

muxx commented Feb 24, 2014

Ок, я изучу детальнее данный подход. В целом он мне импонирует. Если у кого-то есть мысли по поводу подводных камней использования Flock, то велкам.

@muxx
Copy link
Member

muxx commented Feb 27, 2014

@mobilesfinks у меня будет просьба все же попробовать выяснить из-за чего падает aggregate. Можешь в файле console раскомментировать строки

//ini_set('display_errors', 'on');

//$app['debug'] = true;

и в команду крона добавить, чтобы получилось примерно так:

console aggregate > ~/pinboard.info.log 2>~/pinboard.error.log

И когда снова возникнет ситуация с неудаленным локом скинуть мне содержимое логов.

@mobilesfinks
Copy link
Author

Включил логгирование, вот что выдало в ошибку

[PDOException]
SQLSTATE[HY000] [2002] Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111)

aggregate

По поводу того как убивать файл - flock мне не помогает, сейчас заметил, что аггрегирование не работало нормально с момента как в крон поставил

*/1 * * * * flock -n /dev/shm/console.aggregate.lock -c '/var/www/pinboard/console aggregate'
Пока что вернул строку с rm -rf....

@muxx
Copy link
Member

muxx commented Mar 3, 2014

Может тебе прописать что-то подобное host: 127.0.0.1 в настройках parameters.yml?

@muxx
Copy link
Member

muxx commented Mar 3, 2014

Ребят, а у остальных такая же ошибка? Я так понимаю, все упирается в количество подключений через сокет, подключение по tcp должно решать эту проблему.

@mobilesfinks
Copy link
Author

[PDOException]
SQLSTATE[HY000] [2003] Can't connect to MySQL server on '127.0.0.1' (111)

Не помогло

@muxx
Copy link
Member

muxx commented Mar 3, 2014

Это уже другая ошибка. У тебя стоят настройки типа:

# skip-networking
bind-address = 127.0.0.1

?

@mobilesfinks
Copy link
Author

Настройки чего?
Если оставить в parameters.yml хост дб 127.0.0.1, то при использовании rf -rf в кроне после выполнения команды всё нормально отрабатывает.

@muxx
Copy link
Member

muxx commented Mar 3, 2014

[PDOException]
SQLSTATE[HY000] [2003] Can't connect to MySQL server on '127.0.0.1' (111)

Эта ошибка возникает постоянно или периодически?

@mobilesfinks
Copy link
Author

Если постоянно удаляется файл блокировки, то её не возникает. Как только отключаю принудительное удаление, через несколько запусков эта ошибка и аггрегация блокируется файлом блокировки.

@muxx
Copy link
Member

muxx commented Mar 3, 2014

А точно не возникает? Можешь сделать на кроне и удаление лока, и запись логов?

@mobilesfinks
Copy link
Author

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

@mobilesfinks
Copy link
Author

В общем ситуация такая:
Ровно каждый десятый запуск (Каждые 10 минут) выпадает эта ошибка. Сейчас в конфиге указан хост бд 127.0.0.1
После того как поменял на localhost последовательность осталась - каждые 10 минут ошибка.
Теперь соотвественно пишет, что не может подключиться к mysql.sock

UPD:
c 22 часов (МСК) ошибка пропала. Возможно зависит от нагруженности базы или количества запросов. У нас база не нагружена и pinba+mysql+pinboard стоят на отдельной VPS, на пустом (практическе) гипервизоре.

@mobilesfinks
Copy link
Author

UPD2:
Перезагружал машину. mysql не стоял автоматом в загрузку поэтому не стартанул. В итоге в логе те же ошибки. Естественно в такой ситуации они валятся постоянно.
После запуска mysql всё стало отрабатывать корректно (в конце команды в кроне rm -rf ...lock)

У нас на гипервизорах для более плотного размещения виртуалок используется скрипт динамического контроля памяти виртуальных машин. Каждый раз когда он отрабатывает mysql крашится и перезапускается. Именно в этот момент отрабатывает аггрегатор - после падения mysql аггрегатор сам падает. Вышеуказанный скрипт запускается каждые 10 минут.

Падение mysql я могу избежать увеличением выделения оперативной памяти виртуальной машине.
Ну а обработку исключения пинборды делать думаю нужно вам.

@muxx
Copy link
Member

muxx commented Mar 5, 2014

Я думаю, правильнее сделать в начале агрегации что-то вроде проверки коннекта к mysql, и завершать работу (удаляя lock-файл), если коннекта нет. В остальных случаях текущая логика с lock-файлом мне кажется корректной. Можно еще сделать отправку письма на служебную почту, если пинбоард натыкается на lock-файл.

@mobilesfinks
Copy link
Author

Согласен.

@muxx muxx closed this as completed in 70514bf Mar 17, 2014
muxx added a commit that referenced this issue Mar 17, 2014
@muxx
Copy link
Member

muxx commented Mar 17, 2014

  1. Добавил проверку коннекта к БД в начале работы скрипта
  2. Добавил отправку письма о найденном .lock-файле.

Пока в мастере, после закрытия еще пары задач сформирую v1.2


  1. Added checking of DB connection before aggregate running
  2. Added email notification about .lock file finding

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants