poposito Posted October 5, 2014 Share Posted October 5, 2014 Hello, I'm having a big problem with a module that I've been developing. The main problem is that the code is been executed twice instead of once. The goal of this code is that it should be executed only once after 3 minutes since the last execution (something similar to this: http://doc.prestashop.com/pages/viewpage.action?pageId=5374186) The problem is that the user is executing this hook four times in a row, so, after calling the code to be executed, a new hook function is started and the values are not updated. Is there a better way to do this ? Note: This function is been used to change several order values. public function hookBackOfficeFooter($params) { $fecha = Configuration::get($this->rename . 'LAST_EXECUTE'); $dif = $this->getTimeDif($fecha); if (((int) ($dif['min']) > 3 ) ) { $fecha = Configuration::get($this->rename . 'LAST_EXECUTE'); $dif = $this->getTimeDif($fecha); /*Ticket is always set to 1 in this test*/ if (Configuration::get($this->rename . 'TICKET') == 1 && ((int) ($dif['min']) > 3 )) { Configuration::updatevalue($this->rename . 'LAST_EXECUTE', date("Y-m-d H:i:s") ); $fecha = Configuration::get($this->rename . 'LAST_EXECUTE'); sleep(30); /*Code to be executed */ } Configuration::updateValue($this->rename . 'LAST_EXECUTE', date("Y-m-d H:i:s") ); $fecha = Configuration::get($this->rename . 'LAST_EXECUTE'); } } Link to comment Share on other sites More sharing options...
misthero Posted October 5, 2014 Share Posted October 5, 2014 the function should always execute after 3 minutes, or at most every 3 minutes? in the second case try something like this public function checkTime($minutes){ $time = time(); $lastupdated = Configuration::get('LASTUPDATE'); if ($lastupdated < ($time-(60*$minutes))) { //3 minutes have passed Configuration::updateValue('LASTUPDATE', $time); return true; } return false; } public function hookBackOfficeFooter() { $minutes = 3; if ($this->checkTime($minutes)) { //EXECUTE YOUR FUNCTION HERE } } Link to comment Share on other sites More sharing options...
poposito Posted October 5, 2014 Author Share Posted October 5, 2014 (edited) Hello, I've tried the code, but the problem remains. The main problem is that the hook is executed twice at the same time, so the if doesn't work properly, the code is executed more than once. I need the code to be executed once after 3 minutes, but only once. public function checkTime($minutes) { $time = time(); $this->writeToFileParam('CheckTime value -> $time=' . $time .''); $lastupdated = Configuration::get($this->rename . 'LAST_EXECUTE'); if ($lastupdated < ($time-(60*$minutes))) { //3 minutes have passed Configuration::updateValue($this->rename .'LAST_EXECUTE', $time); return true; } return false; } public function hookBackOfficeFooter($params) { $minutes = 3; $fecha = Configuration::get($this->rename . 'LAST_EXECUTE'); $this->writeToFileParam('Entering the function with:-> $fecha=' . $fecha .''); $this->writeToFileParam('Before the IF clause:-> $fecha=' . $fecha .''); if ($this->checkTime($minutes)) { $this->writeToFileParam('Executing the code'); sleep(30); $fecha = Configuration::get($this->rename . 'LAST_EXECUTE'); $this->writeToFileParam('After executing the info -> $fecha=' . $fecha .''); } else $this->writeToFileParam('Else hookBackOfficeFooter :-> No code executed'); } The logs are: 05-10-2014 21:06:09 Entering the function with:-> $fecha=1412535487 05-10-2014 21:06:09 Before the IF clause:-> $fecha=1412535487 05-10-2014 21:06:09 CheckTime value -> $time=1412535969 05-10-2014 21:06:09 Executing the code 05-10-2014 21:06:10 Entering the function with:-> $fecha=1412535487 05-10-2014 21:06:10 Before the IF clause:-> $fecha=1412535487 05-10-2014 21:06:10 CheckTime value -> $time=1412535970 05-10-2014 21:06:10 Executing the code 05-10-2014 21:06:10 Entering the function with:-> $fecha=1412535487 05-10-2014 21:06:10 Before the IF clause:-> $fecha=1412535487 05-10-2014 21:06:10 CheckTime value -> $time=1412535970 05-10-2014 21:06:10 Executing the code 05-10-2014 21:06:39 After executing the info -> $fecha=1412535969 05-10-2014 21:06:40 After executing the info -> $fecha=1412535970 Edited October 5, 2014 by poposito (see edit history) Link to comment Share on other sites More sharing options...
misthero Posted October 5, 2014 Share Posted October 5, 2014 first of all is very strange the hook is called twice, there is a problem somwhere, a double call to the hook or a loop in the code, you can try to lock it with a variable, untested, but something like: private $executing = false; public function checkTime($minutes) { if ($this->executing ) return false; $this->executing = true; $time = time(); $this->writeToFileParam('CheckTime value -> $time=' . $time .''); $lastupdated = Configuration::get($this->rename . 'LAST_EXECUTE'); if ($lastupdated < ($time-(60*$minutes))) { //3 minutes have passed Configuration::updateValue($this->rename .'LAST_EXECUTE', $time); $this->executing = false; return true; } return false; } public function hookBackOfficeFooter($params) { $minutes = 3; $fecha = Configuration::get($this->rename . 'LAST_EXECUTE'); $this->writeToFileParam('Entering the function with:-> $fecha=' . $fecha .''); $this->writeToFileParam('Before the IF clause:-> $fecha=' . $fecha .''); if ($this->checkTime($minutes)) { $this->writeToFileParam('Executing the code'); sleep(30); $fecha = Configuration::get($this->rename . 'LAST_EXECUTE'); $this->writeToFileParam('After executing the info -> $fecha=' . $fecha .''); } else $this->writeToFileParam('Else hookBackOfficeFooter :-> No code executed'); } or try playing with the $executing position, anyway I think there is something wrong somwhere else Link to comment Share on other sites More sharing options...
poposito Posted October 5, 2014 Author Share Posted October 5, 2014 Thx Mistero, but it doesn't work. How to execute the hook twice? While you have the list of orders, click several time in different orders (in a short period of time) to check the orderDetail. That's how you can execute the hook several times. I t seems like if the code is executed in parallel, so the updated variables were not updated until the function is finished. I don't know how to execute the hook once after 3 minutes or more since the last time. Link to comment Share on other sites More sharing options...
misthero Posted October 6, 2014 Share Posted October 6, 2014 (edited) but that is still very odd, I have some modules that make similar checks, for example checking for updates once every hour at most, I can put the variable to something like 30 seconds, an it still works even refreshing and reloading the page very fast, I even tried opening 2 tabs in the browser and reload them both at the same time, only one fire the function. no matter how fast you are. what is in the variable : $this->rename? did you checked what values you have in database? and why you have a sleep(30) in there? Edited October 6, 2014 by misthero (see edit history) Link to comment Share on other sites More sharing options...
poposito Posted October 6, 2014 Author Share Posted October 6, 2014 (edited) Hi, $this->rename is the prefix for all the variables, all the tables. Is the name of the company The reason why I have sleep(30) is a way to simulate a task that is too heavy like the real code. I don't know the reason why several time the hook is activated, that's the issue. I have been testing in prestashop 1.4 because our main client have this. Is there any way to block the amount of times a hook is executed in a row? PS: If you want to simulate the situation: Orders -> Show all orders Press in more than one order with the mouse. -> Try to press as fast as you can. Edited October 6, 2014 by poposito (see edit history) Link to comment Share on other sites More sharing options...
misthero Posted October 6, 2014 Share Posted October 6, 2014 you cannot prevent the hook from launching, you can only control your code attached to that hook. I understood what is happening and in my testing I cannot reproduce it (at least is not executed twice with my functions), but I have not your full code, and not working with 1.4. maybe you can add some more condition, for example limiting the pages where the user should be when the function is executed. $controller = Tools::getValue('controller'); $orderId = Tools::getValue('id_order', 'not_set'); if ($controller == 'AdminOrders' && $orderId == 'not_set' ){ //execute only if watching order list page... } I will look more into it tonight, now I'm at work, if you find the cause of the problem let me know, I'm curious. Link to comment Share on other sites More sharing options...
poposito Posted October 6, 2014 Author Share Posted October 6, 2014 Hello, There's a partial solution with a Session Control variable. But, there's another problem. Due to the fact that the function is way too long a MySQL error is launched, so the Session get caught. I'm stil investigating how to do this. Thx in advanced. Link to comment Share on other sites More sharing options...
misthero Posted October 6, 2014 Share Posted October 6, 2014 (edited) yep using sessions could work but if your purpose is executing the funcions once, no matter how many users are logged in that will not work. One more thing, what are you triyng to do exactly, does it needs to be triggered by users? if it is some heavy query woudn't be better using a cron? Edited October 6, 2014 by misthero (see edit history) Link to comment Share on other sites More sharing options...
misthero Posted October 6, 2014 Share Posted October 6, 2014 (edited) I did a little module and in my testing it works, try it yourself is attached it will write a file in the module dir everytime you visit a backoffice page, but at most every 15 second and you can see a text telling it it was launched or not. it use a timer AND a lock both stored in database, the lock depends from the sleeping function it unlocks only when it finishes. The lock is not really necessary, but is a good option if your function lasts more than the timeout and you don't want it to be executed if the previous one is still working. the sleeping function sleep 10 seconds, but you can increase it. You will see the file is never written more often than 15 seconds. I tested it opening 2 browser and 2 browser tabs for each one, every tab on the same page, than I used a plugin for firefox to reaload both tabs every 5 seconds and on chrome I was clicking randomly timetest.zip Edited October 6, 2014 by misthero (see edit history) Link to comment Share on other sites More sharing options...
misthero Posted October 8, 2014 Share Posted October 8, 2014 did you got it working? Link to comment Share on other sites More sharing options...
Appwards Posted April 22, 2021 Share Posted April 22, 2021 It's an old post, but for people searching for the same thing, here's what I use to avoid this. Note that I haven't taken much time to find the cause of this double execution, but I do know that my module is the only module listening to that hook. Also I know my module isn't listed twice for the same hook in the ps_hook_module table. Instead of using a session, I use the context which is available in your yourmodule.php file if (isset($this->context->controller->blockDoubleStockUpdateExecution)) return true; else $this->context->controller->blockDoubleStockUpdateExecution = true; Hope it helps someone. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now