За последние 24 часа нас посетили 17400 программистов и 1605 роботов. Сейчас ищут 955 программистов ...

Выполнение события в определенное время

Тема в разделе "Решения, алгоритмы", создана пользователем TheShock, 15 июл 2009.

  1. TheShock

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

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    Нет. В данном случае это интересует не изза того, что лень разбираться с кроном, или его отсутствия. И не интересует алгоритм реализующий приблизительно следующее:
    PHP:
    1. <?php
    2. sleep(3600);
    3. // Выполнить через час
    4.  
    Интересует алгоритм, напоминающий действия cron'а, а именно - запуск какого-то события в определенное время. Но время, событие и все с этим связанное должно определяться с помощью пхп-скрипта. При этом, оно должно работать независимо от наличия крона. И еще - эти события некритичны к времени. То есть, допустим, мы указываем событие и указываем, что оно должно выполниться в 2.00 ночи. Но нам не критично, чтобы это было в 2.00, главное, чтобы любой пользователь зашедший после 2 - увидел обработанный результат. Еще одно важное качество - гарантия того, что событие будет выполнено и событие будет выполнено только один раз.

    Может, чуть сумбурно объяснил, но думаю, на примере будет понятнее.

    Далее то, какой я вижу этот алгоритм. Есть таблица в базе: ID, Action, Status, Time, где Action - ссылка на событие, ну, например, какой-то аргумент для метода $eh = new EventRunner($row['Action']);, Status - tinyint поле (выполнено/выполняется/не выполнено), Time - время, когда событие нужно запустить

    Итак, пример.
    Мы хотим поздравить форумчан с Новым Годом в 00.00 1 января. Пишем сообщение "С Новым Годом всех!", ставим галочку "отправить 1 января в 00.00" и едем пить с президентом, или на речку - рыбу ловить. Стукнула полночь, наступил Новый Год, но движок пока спит. И вот в 00.27 его дёргает первый посетитель - какой то трезвенник хочет посмотреть, кто там что написал на форуме. Скрипт просыпается и смотрит: "ага. в 00.00 невыполненное событие" и выполняет его, словно оно было выполнено в полночь. Пользователь доволен - его поздравили ровно в полночь.

    Мне все нравится в этом алгоритме, но такие два момента.

    1. Допустим в 12 часов будет большой наплыв посетителей . Первый вызов скрипта - получаются все незапущенные события с бд. Второй вызов скрипта - получаются все незапущенные события с бд (те же самые), только после этого первый скрипт закрывает доступ к запущенным событиям. Таким образом события выполнятся два раза.
    2. Скрипт запущен, он блокирует нужные события, но тут происходит ребут сервера и, хотя события не выполнены - они находятся в статусе "выполняется". Каких два варианта я вижу:
    а) использовать таймаут для "выполняющегося" события. Если событие выполняется дольше чем, например, 30 секунд - попробовать выполнить его снова
    б) использовать блокировку таблиц / транзакции.

    Сердцем чую, что правильно использовать транзакции, но интересуют некоторые ньюансы.
    Если идет такая последовательность (в порядке запуска)
    0. Скрипт 1 запущен
    1. Скрипт 2 запущен
    2. Скрипт 1 начал транзакцию
    3. Скрипт 2 начал транзакцию
    4. Скрипт 1 получил нужные события
    5. Скрипт 2 получил нужные события
    6. Скрипт 1 пометил события события как "выполняющиеся"
    7. Скрипт 2 пометил события события как "выполняющиеся" ?
    8. Скрипт 1 закончил транзакцию
    9. Скрипт 2 закончил транзакцию
    Транзакция в строке 3 начнется после окончания транзакции в строке 8, или сразу же за первой?
    Получит ли в таком случае скрипт 2 в строке 5 события, которые скрипт 1 пометит как "выполняющиеся" в строке 6?

    Ну и вообще - ваше мнение по поводу данного алгоритма и предложения
     
  2. Apple

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

    С нами с:
    13 янв 2007
    Сообщения:
    4.984
    Симпатии:
    2
    LOCK TABLES -> UPDATE -> UNLOCK TABLES
     
  3. TheShock

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

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    а что, если таблицы локнуты, а потом скрипт упал?
     
  4. Apple

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

    С нами с:
    13 янв 2007
    Сообщения:
    4.984
    Симпатии:
    2
    Как упал? =)
    Локнет таблицу, проапдейтит и упадет?
    Но тогда другой скрипт, запущеный синхронно разлокнет тэйблы и будет таков =)
     
  5. TheShock

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

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    ну сервер ребутнули, или электричество выключили, или критический непойманный notice случайно вылез в скрипте. Ну всякое может быть. А таблицы локнулись.
     
  6. TheShock

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

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    смотри. один скрипт лочит таблицу, выполняет апдейт и тут падает.
    таблица залочена.
    все остальные скрипты встают в очередь в ожидании, пока таблицу разлочат. не?
     
  7. Apple

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

    С нами с:
    13 янв 2007
    Сообщения:
    4.984
    Симпатии:
    2
    Вообще, по мне использование транзакций самый оптимальный вариант, они, в конце концов, ради этого и придуманы.
    Как с анлоком таблица дела обстоят — честно не знаю как ведет себя скрипт, поскольку использовал это только в целях обучения, а в реальных проектах — транзакции.

    Можно это и на файлах ведь делать: fopen, flock :)
     
  8. TheShock

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

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    дык я ничего против транзакций не имею. просто не уверен, что они поведут себя как я ожидаю. потому и спрашиваю - каким алгоритмов воспользоваться правильнее всего.
     
  9. Apple

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

    С нами с:
    13 янв 2007
    Сообщения:
    4.984
    Симпатии:
    2
    Кстати, буквально сейчас я работаю над заказом скрипта для типографии, которая оптом продаёт разные открытки.
    Так вот у них есть разные праздники, и открытки для этих праздников в период этого праздника продаются со скидкой.
    Заказчит вводит период праздника и в этот период должно всё измениться: дизайн, цены, ...
    Практически подобная запланированность событий реализовывается при переходе от одного периода к другому: переключение может произойти только один раз и текущий праздник выбирается помеченым. =)

    Сделано простым транзакционным апдейтом текущих файлов шабов и конфигов (flock).
     
  10. TheShock

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

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    и еще вот вопрос:
    можно ли как-то узнать - занята ли определенная таблица? выполняются ли над ней транзакции, или заблокирована она.
    в данном случае достаточно проверить - занята ли и не ждать освобождения. если занята - значит все события до данного момента выполнятся и можно не ждать окончания работы с этой таблицой, а действовать себе дальше.
     
  11. Sergey89

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

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    У меня когда-то так было сделано. Скрипт выбирает события, которые ещё не в обработке. Делает апдейт и помимо статуса обработки записывает свой id. Сразу после этого делает селект и сверяет id со своим. Если они равны, значит никто не успел вклиниться и можно обрабатывать события. В этом случае придётся использоваться таймаут, чтобы зависшие события обрабатывать.
     
  12. TheShock

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

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    Скрипт 1 получает данные
    Скрипт 2 получает данные
    Скрипт 1 делает апдейт
    Скрипт 1 проверяет, не сделал ли кто апдейт
    Скрипт 2 делает апдейт
    Скрипт 2 проверяет, не сделал ли кто апдейт.

    Хотя действительно. Апдейт можно делать только для тех, кому еще апдейт не сделан. Тут даже без транзакций обойдется.
     
  13. Sergey89

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

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    Да. Апдейт таким запросом делался.
    PHP:
    1. <?php
    2. $query = '
    3.    UPDATE feeds SET
    4.        processed = 1,
    5.        procid = ' . $pid . ',
    6.        updated = UNIX_TIMESTAMP()
    7.    WHERE
    8.        id = ' . $feed['id'] . '
    9.        AND processed = 0
    10. ';
     
  14. kas1e

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

    С нами с:
    6 апр 2009
    Сообщения:
    280
    Симпатии:
    0
    Кагбе многие хостеры рубят на корню скрипты, выполняющиеся без умолку.

    Опастно.
     
  15. TheShock

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

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    kas1e, что значит "выполняющиеся без умолку"? DeferredEvent при вызове родится, выполнится и умрет и для всех хостеров они совершенно неотличимы от всех остальных скриптов, таких как viewtopic.php на этом форуме, или что-либо другое. Более того, оно плавно встраивается в viewtopic.php, viewforum.php, index.php и во все-все остальное работая совершенно незаметно для остальных.
     
  16. kas1e

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

    С нами с:
    6 апр 2009
    Сообщения:
    280
    Симпатии:
    0
    хз, когда клепал аско-бота(там был слип и цикл, крутящийся до получения команды завершения работы) - процесс вроде висел постоянно.
     
  17. TheShock

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

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    kas1e, дык в том же и суть этой идеи, чтобы отказаться от слип и цикла, о чем я и указал в начале этой темы.
     
  18. MiksIr

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

    С нами с:
    29 ноя 2006
    Сообщения:
    2.339
    Симпатии:
    44
    Не, транзакции тут совсем не к тому месту, это именно локи.

    Можно ставить флаг у каждой задачи - "взята на исполнение" и дата... а еще можно pid процесса, что бы тот, кто задачу взял по таймауту - послал kill этому задумчивому =) Остальные процессы читают задачи, и если там есть залоченные к выполнению - определяют через сколько можно задачу "перехватывать", добавляют сколько-то микросекунд рандомно против коллизий и засыпают.

    После просыпания есть 2 варианта - снова все проверить и попытаться перехватить задачу, но это не очень хорошо, ибо процесс и так уже ждал лока, а еще ему потенциально поломанную задачу на себя брать. В общем, черевато затыком системы. Так что лучше просто продолжать работу. Пользователь увидит старые данные, но зато хоть что-то увидит, а не нажмет стоп и уйдет.

    Перехват задачи можно сделать свежим процессом, который увидев, что залоченная задача повисла - перехватывает ее, киляет старого исполнителя и приступает к исполнению. Вообще, спорный момент, ибо такое вот "зависание" может быть как от падения исполнителя, так и от незапланированной тяжести задачи (мало ли что там захотели, мож кино скачать). От вечных килов можно защититься сделав лок - каунтером, и каждый перехват - увеличивая его. Тогда очередная задача, увидев что уже 3 другие пытались это сделать - не будет пытаться. Но все-равно, в случае фильма - убить 2 попытки и только на 3-ю отработать - не очень хорошо. Нужно думать... возможно, задача должна делать постоянный апдейт о том, жива ли она.

    В общем, написать свой крон ой как не просто, по-этому я за крон =)
     
  19. TheShock

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

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    MiksIr, ты уже опоздал. Я уже написал и написал без крона. И зачем может быть нужно скачать фильм с помощью этого - я не представляю.
     
  20. Koc

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

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    фильм скачать.. Я так игры качал в свое время с Инфостора. У провайдера был UA-IX на хорошей скорости. А я админил у него же игровой архив. На сайт поставил скрипт и понеслась. Правда там до крона доступа у меня не было, был демон висящий
     
  21. MiksIr

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

    С нами с:
    29 ноя 2006
    Сообщения:
    2.339
    Симпатии:
    44
    TheShock - ну написал, и что? Все в молодости ошибки делали.
    Фильм, не фильм - тебя как разработчика системы не должно волновать "зачем", а должно "а как это будет работать в той или иной ситуации".
     
  22. TheShock

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

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    MiksIr, ничего, я прощаю тебе эту ошибку, умник, на первый раз.

    А вообще, ты - толстый тролль.