Laravel background jobs

Ти не ти трябва Scheduler-а за тази цел. Просто му задай delay(now()->addMinutes(time)) като time е времето, за което трябва да се построи сградата.

А иначе, за да работи правилно queue, трябва да си направиш таблица в базата данни:

PHP:
php artisan queue:table
php artisan migrate
php artisan queue:work

иначе дори и да сложиш delay няма да работи правилно и ще вика веднага dispatch().
 
Аз съм му направил таблицата, но тука проблема е че когато е извън sceduler-a трябва да му подам командата ръчно. Разбираш ли ме какво имам на предвид?

За да го обясня по цветно, в началото като стартирам scheduler-a почва да се трупа злато през една минута, но камъните си стоят нула. Целта е когато играча построи мината да се стартира втората задача и да почнат да се трупат и камъни, но това не се случва защото queue-to е извън цикъла.
 
Ще опитам да ти разясня отново стъпка по стъпка:

0. Тази задача не трябва да участва в scheduler-а. За да се изпълняват queue работите, трябва да имаш стартиран php artisan queue:work

1. Queue работата(ще я кръстя UpdateResourcesPerMinJob) има за цел да ти вземе данните(взети и подадени от контролера), да речем user_id и името на сградата - да речем gold(това ще е името и на полето ти в базата данни, което ще трябва да се ъпдейтне), както също и данни като например след като се построи сградата с колко трябва да увеличиш полето gold.

2. Правиш си контролер, на който работата му ще е да строи сгради. В него идеята е да извикаш UpdateResourcesPerMinJob и да го dispatch()-неш като на dispatch() подаваш нужните данни(user_id, building name и т.н., като ти препоръчвам building да е обект, с който да можеш да работиш в самото queue) + му закачаш един delay(), който ще е времето, което ще е нужно да се построи сградата. Така, когато натиснеш бутона за построяване, де факто dispatch()-ваш опашката. По-лесно казано, регистрираш я в базата данни и queue:work вече ще знае кога тази опашка трябва да се извика и да се изпълни.
И вече, да речем, ако на сградата са и били нужни 5мин. да се построи, след тези 5мин. опашката ще се изпълни, ще ти ъпдейтне таблицата resources_per_min за съответната колона(име на сграда) и оттам вече, теб не те интересува scheduler-а какво върши, защото той си изпълнява неговата работа да вика командата, която ъпдейтва ресурсите на потребитела. Съответно, след като се ъпдейтне таблица след построяването на сградата, при следващия тик на scheduler-а, той просто ще си вземе новите данни от базата данни ще ъпдейтва според това, какво има там.


Аз май няколко точки ги обясних в т.2, но са просто навързани.

Надявам се, че започваш да разбираш за какво говоря. Ако не, ще видя, ако ми остане някакво време да ти го реализирам, но ти препоръчвам да се справиш сам, за да разбереш процеса на работа.
 
Revelation каза:
Надявам се, че започваш да разбираш за какво говоря. Ако не, ще видя, ако ми остане някакво време да ти го реализирам, но ти препоръчвам да се справиш сам, за да разбереш процеса на работа.

Аз искам сам да си го направя. В крайна сметка целта е да се науча. Нещо не мога да схвана логиката. Значи ако разбирам правилно sheduler-a само следи дали има построена дадената мина. Ако няма не ъпдейтва. На queue-тата работата им е да строят сгради.

Само че тука виждам един проблем. Поправи ме ако греша.
Да кажем стартирам php artisan queue:work но в момента в който затворя конзолата той спира да работи. Така ли е?
 
Да кажем стартирам php artisan queue:work но в момента в който затворя конзолата той спира да работи. Така ли е?

Да, защото конзолата е parent process на стартираната php команда. Виж как в уиндоус да стартираш background process.

П.п. ето ти: https://superuser.com/questions/198525/how-can-i-execute-a-windows-command-line-in-background

START /B program
 
Пак стъпка по стъпка:

Scheduled Tasks
1. Scheduler-а се интересува да има направена команда update:resources
2. Командата се интересува да има създадена таблица resources_per_min

Процес на работа:
1. Schduler-а се изпълнява всяка минута, проверява дали има задачи за изпълнение и ако има ги изпълнява. В случая ти имаш.
2. Командата се изпълнява, взима текущите данни от resources_per_min и ъпдейтва съответно стойностите в resources. Край.
3. Връщаме се на т1.

Добавка: Scheduler-а винаги се изпълнява щом му дойде времето(в твоя случай всяка минута). В твоя случай, той не следи дали има построена дадена мина. Него го интересува само данните да са налични, за да не праска грешки. Дали всички стойности ще са 0, не го интересува, той ще си се изпълнява.

Важно: Тази команда има за задача да ъпдейтва на всички потребители ресурсите. За тази цел в командата трябва да завърташ цикъл с всички потребители.

Queue Jobs обяснени за твоята задача
1. Queue Jobs(в твоя случай UpdateResourcesPerMinJob) се интересува от данните на потребителя и данните на сградата, която строиш.
1.1. Данните на потребителя ти трябват, за да знаеш на кой точно потребител трябва да ъпдейтнеш данните в resources_per_min
1.2. Данните за сградата ти трябват, за да знаеш коя колона да промениш. Ако строиш каменна мина, да промениш стойността на кеманната мина. Съответно и за другите.
Съвет: Изпращай обект Building(за пример), от който ще можеш да взимаш името на сградата, нивото, ресурсите след всяко ниво, които трябва да получаваш(това е най-важно всъщност) и т.н.
2. Да имаш queue worker пуснат.
Информация: Да, винаги трябва да е отворена или както ти казаха, да пуснеш процеса в бекграунд. Но това са подробности, които не ти трябват, ако го правиш само с научна цел.

Процес на работа
1. Имаш контролер, който управлява строенето на всички сгради.
1.1. Контролера не се интересува каква ще е сградата, стига да е сграда.
2. При извикване на съответния метод, който в случая се вика при кликане на бутон за строене на сграда, има за цел да регистрира задачата - UpdateResourcesPerMinJob::dispatch(array params)
3. Ако не зададеш delay, то задачата ще се изпълни веднага, но ни не искаме това.
4. Закачаш на dispatch() един delay(), който трябва да е времето за строене на сградата, за да може чак след като строежа приключи, задачата да се изпълни.
5. Сградата е построена, изпълнява се задачата, ъпдейтва resources_per_min и приключва.

Информация: Задачата трябва да се регистрира само и единствено, когато е натиснат бутон за строене на сграда или респективно, когато се извика съответния action в контролера, И трябва да се изпълнява винаги след като сградата се построи или иначе казано със закъснение(delay)

Надявам се вече да е малко по-ясно какво се случва, че се уморих. :D
 
Руска печка съм знам :D, ама какво да правя. Мисля че разбрах от къде идва объркването ми. В графиката която ми даде в началото двете таблици са с абсолютно еднакви имена на колоните. Да вземем за пример полето gold. Какво се очаква да съдържа в едната и в другата таблица? Името на мината или там се трупа златото?
 
resources - съдържа събраните от потребителя ресурси
[sql]
user_id
total_gold
total_iron
total_stone
[/sql]

Пример:
Потребителя в момента има:
* Злато - 1500
* Желязо - 300
* Камък - 765
________________________________________

resources_per_min - съдържа по колко ресурси да събира на минута(ако искаш ги пази и на час, просто ще трябва да делиш на 60)
[sql]
user_id
gold_per_min
iron_per_min
stone_per_min
[/sql]

Пример:
Потребителя на час трябва да прави:
* Злато - 840 (или по 14 на минута)
* Желязо - 180 (или по 3 на минута)
* Камък - 540 (или по 9 на минута)
________________________________________

Процес на минута: (работа на scheduler-a)
Тик 1:
* Злато = 1500 + 14 = 1514
* Желязо = 300 + 3 = 303
* Камък = 765 + 9 = 774

Тик 2:
* Злато = 1514 + 14 = 1528
* Желязо = 303 + 3 = 306
* Камък = 774 + 9 = 783

... продължава надолу ...
________________________________________

Строеж на желязна мина за потребител Х:
1. Взимаме ресурси за построяването
* Злато = 1528 - 180 = 1348
* Желязо = 306 - 30 = 276
* Камък = 783 - 83 = 700

2. Регистрира се задача, която трябва да се изпълни след 10 минути
3. След 10 минути се изпълнява задачата
4. Желязната мина вече трябва да дава по 300 на час(5 на мин)
5. Ъпдейт на resources_per_min
* Злато - 840 (14 на мин) - не се променя
* Желязо - (стари 180 (3 на мин) ) - 300 (5 на мин) - само тази колона променяме от UpdateResourcesPerMinJob
* Камък - 540 (9 на мин) - не се променя
_________________________________________

след 10 минути (предполагаемото време за построяването на новата сграда) ресурсите са следните:

* Злато = 1348 + (14з./мин * 10 мин) = 1488
* Желязо = 276 + (3ж./мин * 10 мин) = 306
* Камък = 700 + (9к./мин * 10 мин) = 790
(Тези са се обновявали през това време от scheduler-a)

От тука вече имаме построена сграда и нова стойност за добива на желязо
... Тик 13:
* Злато = 1488 + 14 = 1502
* Желязо = 306 + 5 = 311
* Камък = 790 + 9 = 799

Тик 14:
* Злато = 1502 + 14 = 1516
* Желязо = 311 + 5 = 316
* Камък = 799 + 9 = 808

И т.н.


Баси, трябва да напиша статия. Аз колкото неща описах тука и както ги описах трябва да си търся и авторско право, хаха. :D
 
До тука всичко е ок, обаче закъсах с цените на сградите. Имам предвид че искам различните сгради да струват повече от един вид ресурс.

Пример:
Златна мина:
* Ниво 1 - 50 злато
* Ниво 2 - 50 злато и 50 камъни
* Ниво 3 - 100 камъни 50 желязо

Някакви идеи?
 
Към реда на съответната сграда в таблицата с нивата добави полета за цените - price_stone, price_gold. price_steel.

Ако е ясно, че няма да има други ресурси, това е най-удобния вариант.
Ако често сменяш видове ресурси може би ще трябва да извадиш цените в отделна таблица с колони примерно:
element_id [id към таблицата с нивата на сградите]
price_type [ enum 'stone'/'gold'/'steel' ]
price_value int

Но ако ще са само 3 веднъж завинаги, ще ти е по-удобно да си ги държиш като колони в таблицата с нивата.
 
Да ги държа в таблицата с нивата мисля че няма да се получи, защото ново id се създава само при нов юзър, а нивата се ъпдейтват. Дори да добавя още полета няма да може да е различна цената за всяко ниво.

Пример:
Таблица с нивата:
* user_id - 1
* gold_mine - 0
* iron_mine - 0
* stone_mine - 0

Дори да направя още една таблица пак не виждам как ще определям цената за всяка мина и всяко ниво. За да стане май трябва да направя отделна таблица за всяка мина, която да е попълнена според това колко нива ще имам, например 10.

Може и да греша тотално, което няма да е невероятно :D .
 
Не е нужно. В една таблица слагаш данните за всяко ниво на всяка сграда.

[sql]
building_id
level
price_gold
price_stone
price_iron
[/sql]

Като building_id и level могат да са ти индекси.

Така, когато строиш взимаш id на текущата сграда и текущото ниво на сградата + 1 и взимаш данните.

Така или иначе, ако нямаш формула за някакво експоненционално увеличение на ресурсите, ще трябва да си направиш таблица.
 
Нещо не можах да схвана идеята. Как ще изведа цената за всяка мина на всеки юзър ако е съставена от повече от един ресурс?
 
В тази примерна таблица записваш данните на всяка сграда, която имаш, като за съответното ниво записваш колко ресурс да иска. Следователно, ако искаш 2 ресурса за определено ниво, просто пишеш 0 на мястото на конкретния ресурс.
В отделна таблица си записваш за всеки потребител нивото на сградите.

Нужни ресурси на ниво на сграда
[sql]
building_id
level
price_gold
price_iron
price_stone
[/sql]

Нива на сградите за потребителите
[sql]
user_id
building_id
level
[/sql]

Сгради
[sql]
id
building_name
[/sql]

Така много лесно можеш обработваш данните.
 
Ами да. Никога не прави всичко в една таблица. Прочети, ако трябва някъде за дизайн и нормализация на база данни.
 
Добре аз ги направих таблиците, обаче не мога да схвана нещо как ще се попълват. Ще дам пример с таблицата която имах до сега. При регистрация на нов юзър автоматично попълвах id-то и левелите, които после само ъпдейтвах. Един вид нов запис се прави само при нов юзър.


[sql]
Пример:
Таблица с нивата:
* user_id - 1
* gold_mine - 0
* iron_mine - 0
* stone_mine - 0
[/sql]

Сега да вземем за пример едната от новите таблици.

[sql]
user_id
building_id
level
[/sql]

Тука на building_id трябват три записа също и на level ако правилно разбирам?

Би ли обяснил по-подробно как да работя с тези таблици.
 

Горе