Как я могу коснуться сеанса php во время длительного выполнения скрипта

В нашем PHP-проекте есть сценарий обслуживания, который запускается через определенные промежутки времени и выполняет ряд задач на основе отдельных расписаний, думайте об этом как CRON для php.

Проблема, с которой я сталкиваюсь, заключается в том, что некоторые задачи, которые возникают через определенные промежутки времени, выполняются в течение периодов, превышающих продолжительность нашего усиленного сеанса (30 минут), и поэтому срок действия сеанса истекает в ходе этой задачи, что преждевременно завершает работу.

К вашему сведению: я не говорю об ограничениях времени выполнения скрипта, мы уже используем set_time_limit(), чтобы разрешить длительные процессы.

Вопрос: есть ли способ "прикоснуться" к сеансу во время выполнения скрипта таким образом, чтобы сбросить время истечения сеанса? т. е. подходит ли настройка переменной сеанса или для этого требуется специальная функция PHP?


Чтобы быть более конкретным, у нас есть одно фактическое задание CRON, которое выполняется каждую минуту:

* * * * * user curl -XGET https://domain.com/maintenance.php

... который, в свою очередь, использует нашу внутреннюю систему для поиска задач, запланированных для запуска в это время, некоторые из этих задач короткие и простые, некоторые длинные и сложные. Вышеупомянутая проблема возникает во время длинных сложных (> 30 минут выполнения).


EDIT: Подводя итог многочисленным комментариям ниже...

  1. Мы хотим избежать выдачи дополнительных RPC для достижения этой цели, я ищу решение, подобное воображаемому touch_session().

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

  3. Мы используем БД для управления сеансом, поэтому мы могли бы просто написать собственный метод touch_session(), который можно вызывать и просто использовать SQL-запрос для обновления метки времени а-ля UPDATE sessions SET expiration = '###' WHERE Session_ID = 'abc123';. Есть ли в этом подводные камни?

Если нет ни одного из вышеперечисленных, есть ли другие варианты, которые не требуют дополнительных rpc?


person oucil    schedule 26.03.2014    source источник
comment
Итак, вы запускаете скрипт с заданием cron или чем-то еще? Можете ли вы объяснить, как это связано с сессиями? Не могли бы вы немного объяснить, в чем проблема на самом деле?   -  person Wesley Murch    schedule 26.03.2014
comment
Тайм-аут сеанса не прерывает выполнение скрипта; max_execution_time — единственное ограничение.   -  person Gumbo    schedule 26.03.2014
comment
@WesleyMurch Добавлены подробности о том, как работает техническое обслуживание.   -  person oucil    schedule 26.03.2014
comment
@Gumbo Наши сценарии обслуживания иногда сами используют вызовы API с использованием CURL, которые требуют, чтобы сеанс оставался в силе, это может произойти позже во время выполнения родительских сценариев, и поэтому срок их действия истекает к тому времени, когда они появляются. Сеанс содержит информацию, необходимую для проверки разрешений.   -  person oucil    schedule 26.03.2014
comment
@ Уэсли, я не буду вдаваться в подробности, это не относится к этому вопросу, давайте просто предположим, что это необходимо.   -  person oucil    schedule 26.03.2014
comment
$_SESSION должен оставаться неповрежденным, даже если запись данных сеанса удаляется сборщиком мусора, и должна восстанавливаться при завершении работы во время выполнения.   -  person Gumbo    schedule 26.03.2014
comment
@WesleyMurch Наше хранилище сеансов на самом деле находится в БД, но это не должно иметь никакого отношения к этому. Вопрос в том, будет ли обновляться временная метка, связанная с сеансом, путем простого обновления переменной, хранящейся в сеансе, или мне нужно использовать определенную функцию, чтобы из-за отсутствия лучшего термина touch сеанс.   -  person oucil    schedule 26.03.2014
comment
@Gumbo Запись сеанса может сохраняться после того, как сборщик мусора очистит data, но какой в ​​этом смысл, если срок действия сеанса истек и он больше не может получить доступ к защищенным ресурсам, необходимым для выполнения его работы? Простой факт заключается в том, что сеанс должен оставаться активным на протяжении всего процесса независимо от времени, поэтому мне нужно что-то, чтобы коснуться временной метки сеанса. Я пытаюсь избежать необходимости выполнять вызов CURL каждые N записей в течение длинного цикла, и, таким образом, мы возвращаемся к моему вопросу: достаточно ли обновить значение переменной сеанса или есть вызов функции. Если оба они ложны, есть ли другой вариант?   -  person oucil    schedule 26.03.2014
comment
Моя точка зрения такова: даже если срок действия сеанса истекает и сборщик мусора удалит данные, это не должно влиять на текущий активный сеанс, представленный $_SESSION. Данные должны быть сохранены обратно при завершении работы во время выполнения (session_write_close). Только если вам потребуется еще один вызов session_start в уже истекшем сеансе, вы получите пустой $_SESSION.   -  person Gumbo    schedule 26.03.2014
comment
@Gumbo Как я уже упоминал в комментариях выше, некоторые задачи обслуживания, которые потенциально следуют за долго выполняющейся, используют CURL для запуска задач, и поэтому, пока родительский процесс будет продолжать работать и иметь доступ к действительному сеансу, поскольку он все еще работает , любые удаленные вызовы дочерних задач, которые предполагают, что действительный сеанс все еще активен, завершатся ошибкой из-за удаления данных сеанса.   -  person oucil    schedule 26.03.2014
comment
@oucil Рассматривали ли вы перезапись длины сеанса php.ini во время выполнения в ваших заданиях cron?   -  person Andresch Serj    schedule 26.03.2014
comment
@AndreschSerj не будет работать по нескольким причинам, во-первых, это затронет всех пользователей, что является проблемой безопасности в нашей многопользовательской среде, но мы также работаем на серверах приложений N + 1, и сеансы не привязаны к нашему балансировщики нагрузки, поэтому нет гарантии, что машина, на которой запущен родительский процесс, будет той же, на которой выполняется дочерний вызов.   -  person oucil    schedule 26.03.2014
comment
@oucil Возможно, простые сеансы PHP — это не то, что вы ищете :(   -  person Andresch Serj    schedule 26.03.2014


Ответы (2)


Таким образом, несмотря на то, что было предложено несколько решений, ни одно из них не соответствовало нашим требованиям, они либо были более накладными, чем того стоили, имели проблемы с безопасностью или потребовали бы много работы для реализации в масштабном приложении.

В случае PHP $_SESSION — это просто копия данных, хранящихся в записи сеанса, пока запрос не завершится и новые данные не перезапишут старые, поэтому любые манипуляции с $_SESSION не влияют на фактическое истечение срока действия записей сеанса в системе.

Поскольку в нашем уникальном случае мы используем MySQL для управления сессиями, самым простым решением было создать собственный метод touch_session() с простым запросом:

UPDATE sessions SET expiration = NOW() WHERE Session_ID = 'ABC123'

NB, наша сборка мусора использует NOW() - 30 минут для истечения срока действия записей, поэтому в запросе выше установлено значение срока действия NOW().

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

Надеюсь, это поможет кому-то еще в подобных ситуациях.

person oucil    schedule 30.03.2014

Как сказано в комментариях, вы можете использовать curl для доступа к другому скрипту, который касается сеанса.

touch.php

<?php
session_name('theNameOfYourSessionId');
session_start();

вызовите это с помощью curl, как это, в вашем сценарии обслуживания, например:

$sid = session_id();
exec('user curl -XGET https://domain.com/maintenance.php?theNameOfYourSessionId='.$sid)

Это должно сработать.

Вместо curl вы также просто используете file_get_contents, чтобы избежать проблемы с завитком.

$sid = session_id();
file_get_contents('https://domain.com/maintenance.php?theNameOfYourSessionId='.$sid);

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

Так почему бы не использовать предоставленный идентификатор сеанса в качестве идентификатора в вашей базе данных и не хранить там содержимое сеанса? Когда вы вводите скрипт, а нужная сессия пуста, вызовите базу данных и восстановите ее.

person Andresch Serj    schedule 26.03.2014
comment
Это лучшее из худших решений из-за двух факторов: накладных расходов на выполнение дополнительных вызовов CURL, а также возможности возникновения ошибки CURL по какой-либо причине, которая остановит сценарий целиком, если только я не приложу еще больше усилий, чтобы справиться с обработка ошибок. Я надеюсь на быстрый ответ, например, конечно, используйте touch_session(); или $_SESSION['var'] = microtime(); - person oucil; 26.03.2014
comment
@oucil, насколько я знаю и что касается исследования php.net, чего-то вроде touch_session не существует. простите. Я сделал редактирование, добавив file_get_contents в качестве опции. Может быть, это лучше для вас. - person Andresch Serj; 26.03.2014
comment
Спасибо за ваши усилия, они оба действительны и будут работать на основе заданного мной вопроса. Хотя, к вашему сведению, file_get_contents() в основном основан на сокетах и ​​работает аналогично curl и, следовательно, будет подвержен тем же накладным расходам и потенциальным ошибкам связи. Тем не менее, это варианты, так что спасибо за это. - person oucil; 26.03.2014
comment
@oucil Что ж, поскольку touch_php_session отсутствует, а мой ответ действителен, рассмотрите возможность его принятия и, таким образом, пометки этого вопроса как ответа. - person Andresch Serj; 27.03.2014
comment
Я ценю ваш вклад, Андреш, но, принимая во внимание обновленную информацию в вопросе, который я также упомянул здесь, эти решения имеют серьезные подводные камни, накладные расходы, требуют много обработки ошибок и т. д. Я обязательно + 1 это, когда я буду готов выбрать ответ, но я оставлю его открытым немного дольше, чтобы посмотреть, есть ли какие-либо другие идеи. Тем временем я пошел дальше и создал свой собственный статический метод touch_session(), который вручную обновляет метку времени в нашей таблице сеансов, что является преимуществом использования БД для управления нашими сеансами. Я не думаю, что увижу лучше. - person oucil; 27.03.2014