Ежедневное начисление бонуса пользователю PHP

passshift

Новичок
Здравствуйте!

Долго гуглил вопрос, но так ничего для себя и не нашел.

Суть вот в чем:

Есть 2 таблицы: users и history

Юзер регистрируется на сайте, данные, включая дату регистрации заносятся в MySQL в таблицу users. На бонусном балансе юзера стандартно при регистрации 1 балл (строка об этом заносится в history сразу после регистрации).

Необходимо чтобы каждые сутки к балансу юзера прибавлялся еще 1 балл и информация об этом заносилась в таблицу history и так каждые сутки.

Как это лучше реализовать? Если учесть что число юзеров будет примерно 2000-3000 человек.

Подскажите пожалуйста, мне не нужен готовый скрипт, просто хотелось бы для себя изложить в голове фронт работы. Я понимаю что лучше через cron-job, но 2000-3000 строк одновременно в history каждые сутки как-то жестко по-моему ((
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
Берем крон, пишем скрипт, который будет раз в день выбирать твоих юзеров и вписывать им в баланс данные.
 

passshift

Новичок
Берем крон, пишем скрипт, который будет раз в день выбирать твоих юзеров и вписывать им в баланс данные.
Вот добавил: "Я понимаю что лучше через cron-job, но 2000-3000 строк одновременно в history каждые сутки как-то жестко по-моему (("

Баланс конкретного юзера хотел вычислять через выборку значений из history т.е.: select все значения юзера такого-то и сложение их = баланс - насколько это правильно?
 

hell0w0rd

Продвинутый новичок
UPDATE table2 SET money = money + 1 - для юзеров.
А зачем каждый раз писать в history на каждого юзера? Это лог? Если лог - почему не написать что всем юзерам начислен бонус?
 

passshift

Новичок
UPDATE table2 SET money = money + 1 - для юзеров.
А зачем каждый раз писать в history на каждого юзера? Это лог? Если лог - почему не написать что всем юзерам начислен бонус?
Да, что-то вроде лога и вместе с тем история начислений. Юзер будет нажимать на кнопку "История" у себя в кабинете, а ему будет выдавать список зачислений за каждый день по дате...
 

passshift

Новичок
Я обучаюсь, за ночь мне удалось написать вот такой скрипт:

PHP:
<?
require_once('config.php'); // Подключение к базе
$profit = 1; // Размер бонуса

$query = mysql_query("SELECT user_id, status FROM users WHERE status = 'on'");  // Выбор активных юзеров (чей статус = ON)
while($data=mysql_fetch_array($query))
{
$query2 = mysql_query("UPDATE users SET balance = balance + '$profit' WHERE user_id = '$data[user_id]'"); // Обновляем баланс юзеров, добавляя +1
$query3 = mysql_query("INSERT INTO history SET user = '$data[user_id]', bonus = '$profit', date = now()"); // Заносим данные в историю
}
?>
База с таблицами создана и скрипт впринцепе работает, но насколько он правильный? Если его положить за пределы директории WWW и запускать раз в сутки через cron, насколько это будет удачным решением?
 

Andkorol

Новичок
Апдейтить можно одним запросом:
PHP:
$query = mysql_query("UPDATE `users` SET `balance` = (`balance` + '$profit') WHERE `status` = 'on'");
INSERT позволяет добавлять несколько результатов в одном запросе:
PHP:
"INSERT INTO `history` (`user`, `bonus`, `date`) VALUES 
('userID_1', 'bonus', NOW()), 
('userID_2', 'bonus', NOW()),
...
('userID_N', 'bonus', NOW())"
Но сначала желательно определиться, нужен ли такой лог вообще – дата регистрации юзера зафиксирована, размер бонуса известен и постоянен (судя по вашему примеру), потому не составит особого труда сформировать "псевдо-статистику" начислений юзеру, основываясь только на количестве дней с момента регистрации и сумме ежедневного бонуса.
 

hell0w0rd

Продвинутый новичок
Вот-вот не очень понимаю зачем действительно нужен ТАКОЙ лог.
Можно создать таблицу bonus_history и в случае если у юзера на пример штраф, или еще чего-то - уже записывать туда, что бонус не был зачислен. может я и не прав)
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
passshift
У меня виртуалка вытягивает пару миллионов инсертов при перестройке одного хитрого индекса, так что твои 2-3 тысячи это капля в море.

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

keltanas

marty cats
И вообще, начислять юзеру бонус, если он зашел в кабинет спустя несколько дней, сразу за все дни отсутствия.
А то если из 3000 юзеров живых будет только 10%, будет производится много лишней работы.
С ростом ресурса их может стать и 3000000, и они могу стать расшардены по серверам. И придется гулять по всем шардам кроном, начисляя бонусы....
 

passshift

Новичок
Всем спасибо за ответы!

Хочу немного пояснить:

1) Размер бонуса будет зависеть от статуса пользователя и от ряда других достижений, т.е. он будет всегда разным
2) Как заметил keltanas, у каждого пользователя будет статус ON или OFF, таким образом будет происходить фильтрация активных

hell0w0rd, к сожалению история пополнений нужна :-( так бы конечно проблем не было (

Andkorol, спасибо, так и вправду проще...

Т.е. впринцепи допустимо по этой схеме реализовать и перейти к следующему этапу?

Я никогда до этого не работал с cron, хотя впринцепи начитался и все понятно там, проблем думаю не будет, вот только как "защитить" скрипт от выполнения несколько раз под ряд?
 

keltanas

marty cats
passshift
Под неактивными я понимал тех, кто зашел на сайт пару раз и забыл про него. На основании чего ты будешь предполагать его статус?
вот только как "защитить" скрипт от выполнения несколько раз под ряд?
Вот тут начинается самое интересное :p
Есть еще вопрос: "как защитить скрипт, чтобы он не выполнялся параллельно в несколько копий?"
 

passshift

Новичок
Каждой записи в history присваивается уникальный ID, он не повторяется, возможно это и есть определенная "защита" от повторной записи? Или я не прав и в случае повторного выполнения (или параллельного) ID без проблем будет уникальным, а время зачисление с разницей в 1 секунду :(

Или может есть какая-то внутренняя "защита" от повторного выполнения на уровне CRON?

Почитал, нашел только один похожий параметр:

« -t 1 » — выполнить лишь одну (« 1 ») попытку соединения (а не 20, которые установлены по умолчанию)

- выручит?
 

Gas

может по одной?
passshift
гугли например по: php cron pid lock
сразу находится
http://abhinavsingh.com/blog/2009/12/how-to-use-locks-in-php-cron-jobs-to-avoid-cron-overlaps/

при запуске скрипта раз в сутки и дублей быть не должно, а если сомневаешся, ну сделай уникальный ключ по полям (user,operation,date), а в этом скрипте в date ставь например 'Y-m-d 00:00:00'
 

passshift

Новичок
passshift
гугли например по: php cron pid lock
сразу находится
http://abhinavsingh.com/blog/2009/12/how-to-use-locks-in-php-cron-jobs-to-avoid-cron-overlaps/

при запуске скрипта раз в сутки и дублей быть не должно, а если сомневаешся, ну сделай уникальный ключ по полям (user,operation,date), а в этом скрипте в date ставь например 'Y-m-d 00:00:00'
Так и делаю. Спасибо!
 
Сверху