Система автообновления, как избежать многократного обновления?

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

Уровень кода работает следующим образом: когда пользователь делает запрос, приложение уменьшает его кредиты до одного, а затем проверяет, текущие кредиты == {сумма автоматического продления}. В этом случае задание отправляется в службу очереди, чтобы начать обновление.

Тест здесь критичен, я проверяю, остается ли значение EQUALS для автоматического обновления, а не когда оно НИЖЕ ИЛИ EQUAL, потому что в этом случае обновление будет выполняться каждый раз, когда пользователь запрашивает API, в то время как первое автоматическое обновление имеет не был полностью обработан.

Но у меня была странная проблема сегодня. У одного из моих клиентов было два продления вместо одного. Мое первое предположение состоит в том, что в API есть условие гонки, означающее, что два запроса выполняются одновременно, при этом «оставшиеся» кредиты идентичны и равны числу для автоматического продления, что приводит к двум автоматическим продлениям.

Мой вопрос здесь довольно прост: как я могу избежать двух обновлений?

Основная идея состоит в том, чтобы исправить проблему состояния гонки, но я не понимаю, как API написан на PHP с использованием NGinx. Сервер должен знать, что к одной и той же учетной записи сделано N запросов, чтобы рассчитать текущее использование кредитов (оставшихся — {одновременных запросов}), что кажется невозможным.

Как я могу это сделать?

1

Решение

Решение состоит в том, чтобы позволить только одному процессу PHP запускать функцию автозарядки в любой момент времени. Самый простой способ сделать это — окружить ваш код flock()/fclose():

$lock = fopen("/tmp/renew", "w+");
flock($lock, LOCK_EX);

<renew code>

fclose($lock);

Это гарантирует, что будет запущен только 1 процесс PHP <renew code> вовремя. Таким образом, даже если поступит 100 запросов на обновление, запрос № 1 запустит код обновления, а запросы № 2- # 100 прекратят работу при нажатии flock(), Когда # 1 заканчивается, # 2 запускается, когда # 2 заканчивается, # 3 запускается и так далее.

2

Другие решения

Я, наконец, пришел с этим решением:

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

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

Я думаю, что закрыл проблему, но я предпочитаю дать понять, что у @Brian with был умный способ сделать это в случае, если скрипт не вызывается из системы очередей !.

1

По вопросам рекламы [email protected]