PHP несоответствие времени скручивания - PullRequest
2 голосов
/ 01 июня 2010

Я запускаю скрипт php, который:

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

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

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

Я думал о сохранении значения в базе данных, которое указывает, что инструкция curl выполняется в это время, и предотвращает выполнение любых других операторов curl до его завершения. Как только первый оператор curl был выполнен, флаг базы данных обновляется и может запускаться следующий. Если это поле «заблокировано», то я мог бы перебирать код и спать в течение (5) секунд, а затем снова проверить, был ли флаг сброшен. Если после (3) зацикливается, сбросьте флаг автоматически (я никогда не видел, чтобы скручивание занимало более 5 секунд) и продолжите обработку.

Существуют ли другие (более изящные) способы решения этой проблемы?

Ответы [ 3 ]

2 голосов
/ 01 июня 2010

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

$lockfile = 'foo.bar';
$fd = fopen($lockfile, "w");
if (flock($fd, LOCK_EX)) {
    do_your_stuff();
}
else
    die("error"); //should not happen; flock should block until the lock is acquired

fclose($fd);

EDIT:

PHP не является Java EE, простого способа реализации распределенных транзакций не существует.

0 голосов
/ 04 июня 2010

curl поддерживает параллельные запросы к N ресурсам с помощью curl_multi_exec (). Если вы хотите сделать эти вызовы (среди которых несколько вызовов curl_ *) последовательно и сделать приведенные выше операторы атомарной операцией, не используйте curl_multi в случае, если вы используете его.

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

Использование механизма псевдо-транзакций со столбцом, помечающим запись как «заблокированную», может помочь вам, как вы говорите, но я не могу быть уверен (есть метод для псевдо-транзакций, использующий временные метки, которые вы можете узнать в Google ).

0 голосов
/ 04 июня 2010

То, что вам нужно, называется Управление параллелизмом . Многие люди уделяют много времени и усилий исследованию этой проблемы.

Эта проблема не так проста, как вы надеетесь. Некоторые движки форума ( кашель Stackoverflow кашель ) также реализуют нечто похожее на это, поэтому он может отображать сообщения в том порядке, в котором они были созданы (не опубликованы). Это делается путем создания случайного токена, который конечный пользователь должен использовать для уведомления сервера о том, что он все еще активен, и время от времени обрабатывает запись, которая в данный момент редактируется / добавляется. Наиболее распространенными проблемами с этим являются проблемы тайм-аута соединения и времени ожидания пользователя. Тайм-аут соединения фиксируется тем, что клиент отправляет сердцебиение (в Интернете это обычно делается путем выдачи HTTP-запроса просто для уведомления сервера о том, что соединение все еще живое & ndash; открывать) на сервер через равные промежутки времени; если клиент перестает отправлять звуковые сигналы на длительный период времени, сервер считает, что это истекло время ожидания. В то же время клиент должен также знать, достигло ли сердцебиение сервера или нет, и он должен подумать, что делать в случае истечения времени ожидания соединения. Существует также случай тайм-аута пользователя, когда пользователь просто блокирует запись и покидает компьютер на длительный период времени. В этом случае и клиент, и сервер должны знать о том факте, что запись была заблокирована, но она не использовалась (не редактировалась) в течение длительного периода времени, и они оба должны принять меры.

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

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