За последние 24 часа нас посетили 16957 программистов и 1652 робота. Сейчас ищут 954 программиста ...

Помощь в блокировке процессов в php

Тема в разделе "Сделайте за меня", создана пользователем Edifanov, 11 июл 2017.

  1. Edifanov

    Edifanov Новичок

    С нами с:
    11 июл 2017
    Сообщения:
    4
    Симпатии:
    2
    * Необходимо написать класс реализующий блокировку процессов.
    * Блокировки используются для проверки параллельного запуска процессов
    * чтобы не запускать несколько одинаковых процессов тогда, когда это вредно.
    *
    * Например, скрипт импортирующий новости запускается по крону каждую минуту.
    * Необходимо проверить, что предыдущий импорт уже завершился, иначе
    * произойдёт дублирование новостей. Кроме крона могут быть и другие применения.
    *
    * Должно работать на windows и unix.
    *
    * Важно: необходимо предусмотреть ситуацию, когда скрипт импорта вылетит с FATAL
    * не дойдя до крайней строки освобождения блокировки. В этом случае блокировка
    * не должна висеть вечно.
    *
    * При выполнении этого задания, бОльшее значение имеет качество написанного вами кода.
    * Не важно сколько времени вы потратите: 15 минут или 1.5 часа, ведь вы пишете
    * универсальный класс который будет переиспользован многократно в разных проектах
    * для разных задач на потяжении многих лет.
    *
    * Пожалуйста, реализуйте класс и пришлите файл Blocker.php

    Нужна помощь в концепции, как сделать. Реализация не обязательна
     
    Алекс8 нравится это.
  2. Алекс8

    Алекс8 Активный пользователь

    С нами с:
    18 май 2017
    Сообщения:
    1.730
    Симпатии:
    359
    подпишусь на ответы) хороший топик)) интересно))
     
  3. Edifanov

    Edifanov Новичок

    С нами с:
    11 июл 2017
    Сообщения:
    4
    Симпатии:
    2
    Я вот думаю, реализовать через таблицу в БД, что бы получилось универсально для ОС. Выставлять к названиям файла скрипта флаги, типо: DONE, FAIL, START итд
     
  4. Алекс8

    Алекс8 Активный пользователь

    С нами с:
    18 май 2017
    Сообщения:
    1.730
    Симпатии:
    359
    ну у меня мыслей кроме как контроль через базу за импортом не возникает))
    я никогда не работал с скриптами у которых реализована многопоточность).. поэтому и подписался))
     
  5. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    А зачем база, если тут хватит текстового файла?
    Другой вопрос, что подразумевается под блокировкой? Выдать false/true на запуск или все-же запустить процесс, который будет отслеживать обращения к скриптам?
     
  6. Edifanov

    Edifanov Новичок

    С нами с:
    11 июл 2017
    Сообщения:
    4
    Симпатии:
    2
    lock($f, LOCK_EX + LOCK_NB) Что то типо такого? через создание файла?
     
  7. Zuldek

    Zuldek Старожил

    С нами с:
    13 май 2014
    Сообщения:
    2.381
    Симпатии:
    344
    Адрес:
    Лондон, Тисовая улица, дом 4, чулан под лестницей
    путей реализации масса, для самой рациональной нужно иметь представление о функционале PHP-FPM которая де факто становится стандартом. Всё есть в мануале. Если коротко, php позволяет осуществлять коммуникацию между мастер-процессом и дочерними процессами, запускать их от разных пользователей, даже с разными PHP.ini настройками, останавливать, вести отдельные логи и т.п.

    В простой реализации вашей задачи, объекты класса должны позволять делать следующее:

    1. Забор очереди очередь заданий.
    2. Запускать или не запускать воркеров (сколь угодно сложная логика по принятию решения о старте новых демонов в зависимости от очереди задач, свободных ресурсов и т.п.)
    3. Передать воркеру задачу
    4. Воркеры отрабатывают задачи из очереди и умирают.

    в ответе мысли правильные, поэтому нет смысла дальнейших пояснений.
    Хоть через что. Это всего лишь абстракция очереди задач. Что у вас там: реляционная база данных, RabbitMQ, Gearman - не важно

    С формулировкой мыслей у автора задания есть проблемы. Вредно - только не хотеть. Есть слип процессов, есть кил процессов, есть вред от выполнения одними и теми же процессами одной и той же задачи (операции с общими данными), есть запуск неограниченного числа демонов и забивания ими доступной памяти что при кривых настройках может означать зависание сервера. А может быть их запускать запускать когда автор задания пьян... .

    * При выполнении этого задания, бОльшее значение имеет качество написанного вами кода задания
     
    #7 Zuldek, 11 июл 2017
    Последнее редактирование: 11 июл 2017
    Maputo нравится это.
  8. ADSoft

    ADSoft Старожил

    С нами с:
    12 мар 2007
    Сообщения:
    3.866
    Симпатии:
    753
    Адрес:
    Татарстан
    Похоже не тестовое задание при приеме на работу
     
  9. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    это не тестовое задание а бред ебанутого архитектора
    --- Добавлено ---
    не масса. там везде рейс кондишн сплошь и рядом
    блокировки делать вообще сложно и желательно делать однопоточного менеджера, иначе рейс кондишн, рейс кондишн и рейс кондишн.
     
    Dmitriy A. Arteshuk и Fell-x27 нравится это.
  10. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Блокировка с помощью блокирования файлика надежна
     
  11. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    Немного не пойму зачем блокировать файл на низком уровне?
     
  12. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    потому, что это действительно одна из тех операций, которые позволяют избежать рейс кондишн
     
    Maputo нравится это.
  13. Maputo

    Maputo Активный пользователь

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    Ну тогда не нужно никакого списка запущенных скриптов, потому что это тоже рейскондишн.
    Каждый экземпляр класса должен отвечать только за запуск одного скрипта и сверять возможность его запуска по блокировке файла.
    Если не блокирован, то запустить, заблокировать файл и отследить скрипт (завершение работы или аварийный выход), после чего разблокировать файл.

    P.S.: Нельзя ли это реализовать средствами операционной системы?
     
  14. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.771
    Адрес:
    :сердА
    Но не в случае, когда заблокировавший поток пофейлился, не успев блокировку снять. Тогда мы получаем другую проблему - deadlock.
    --- Добавлено ---
    Ну как-то так супервайзеры многопоточные и работают. Другое дело, что хз, накой это на PHP писать, е-мое? Синдром золотого молотка, чесслово.
     
    Maputo нравится это.
  15. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    рейс кондишн порождает не список, а способ работы с ним
    лочка файла имеет один плюс - не нужно запрашивать, блокирован ли файл. Именно при запросах и возникает рейс кондишн. Если ты пошёл, спросил, запомнил, что свободно и сунулся - а там уже занято, то это рейс кондишн.
    Лочка файла позволяет обойти это, т.к. ты сразу лочишь файл, и только если обломился - тогда не делаешь ничего. Он либо удачно залочился, либо уже залочен кем-то другим.

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

    А лочка файла это операция, которая менеджерится ОСью и она типа не допускает такого.
    --- Добавлено ---
    по факту это грязный хак, который позволяет заюзать безрейсовый менеджер ОСи, предназначенный для других целей :D

    в многопоточных языках есть специальные штуки, чтобы так не надо было делать. Но вот у нас пока нет.
     
    Maputo нравится это.
  16. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Здесь протестировали, что linux разблокирует файл при завершении процесса в любой ситуации, даже kill -9
    https://stackoverflow.com/questions...ock-in-case-of-errors?answertab=votes#tab-top
     
    Fell-x27 нравится это.
  17. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.771
    Адрес:
    :сердА
    Окей, принято :)
     
  18. Edifanov

    Edifanov Новичок

    С нами с:
    11 июл 2017
    Сообщения:
    4
    Симпатии:
    2
    PHP:
    1. <?php
    2.  
    3. /**
    4. * Блокератор
    5. */
    6. class Blocker
    7. {
    8.     const EXT_LOCK_FILE = '.pid';
    9.  
    10.     private $id;
    11.     private $tmpDirectory;
    12.  
    13.     private $filePath;
    14.     private $lock;
    15.  
    16.     private $fileManger;
    17.  
    18.     /**
    19.      * @param string $id Идентификатор блокировки
    20.      * @param FileManagerInterface $fileManager Файл Менеджер
    21.      */
    22.     public function __construct($id, FileManagerInterface $fileManager)
    23.     {
    24.         $this->id = $id;
    25.         $this->tmpDirectory = sys_get_temp_dir();
    26.         $this->filePath = $this->tmpDirectory . DIRECTORY_SEPARATOR . $this->id . self::EXT_LOCK_FILE;
    27.         $this->fileManger = new FileManager();
    28.     }
    29.  
    30.     public function isLock()
    31.     {
    32.         $this->lock = $this->isFileAndProcessActive();
    33.         return $this->lock;
    34.     }
    35.  
    36.     public function getLock()
    37.     {
    38.         return $this->lock;
    39.     }
    40.  
    41.     /**
    42.      * @return bool
    43.      */
    44.     public function setLock()
    45.     {
    46.         if ($this->isLock()) {
    47.             return true;
    48.         }
    49.  
    50.         try {
    51.             $pid = getmypid();
    52.  
    53.             /**
    54.              * @var File $file
    55.              */
    56.             $file = $this->fileManger->create($this->filePath, 'a');
    57.  
    58.             $file->truncate(0);
    59.             $file->write($pid);
    60.             $file->lock(LOCK_EX + LOCK_NB);
    61.             $file->close();
    62.  
    63.         } catch (Exception $e) {
    64.             echo 'Выброшено исключение: ', $e->getMessage(), "\n";
    65.             exit(-1);
    66.         }
    67.     }
    68.  
    69.  
    70.     /**
    71.      * Пытается получить блокировку
    72.      *
    73.      * @return    boolean
    74.      */
    75.     public function open()
    76.     {
    77.         if ($this->isLock()) {
    78.             return false;
    79.         }
    80.  
    81.         $this->setLock();
    82.         return true;
    83.     }
    84.  
    85.     /**
    86.      * Высвобождает блокировку
    87.      *
    88.      * @return    void
    89.      */
    90.     public function close()
    91.     {
    92.         /**
    93.          * @var File $file
    94.          */
    95.         $file = $this->fileManger->create($this->filePath, 'r+');
    96.         $file->flush();
    97.         $file->lock(LOCK_UN);
    98.         $file->close();
    99.  
    100.         $this->fileManger->delete($file);
    101.     }
    102.  
    103.     private function isFileAndProcessActive()
    104.     {
    105.         /**
    106.          * @var File $file
    107.          */
    108.         $file = $this->fileManger->create($this->filePath, 'r+');
    109.         if ($file->isExist()) {
    110.             $pid = intval($file->getContent());
    111.  
    112.             if (posix_kill($pid, 0)) {
    113.                 return true;
    114.             } else {
    115.                 if (!$this->fileManger->delete($file)) {
    116.                     exit(-1);
    117.                 }
    118.             }
    119.         }
    120.         return false;
    121.     }
    122.  
    123.  
    124. }
    Набросал код,
    Теперь проблема с posix_kill на WIndows, как на windows проверить процесс с индефикатором?
    getmypid - работает как под linux как под windows
     
    igordata нравится это.