Jump to content

Ken Muldrew

  • Posts

  • Joined

  • Last visited

Everything posted by Ken Muldrew

  1. Many thanks, BitPoet. I wasn't even aware of that function. It may be a while before I see if it solves the problem, but for what it's worth, here is how I implemented locking in lazy cron and the script called from AJAX: excerpt from lazy cron: $json = json_encode($mapData); $fp = fopen('site/templates/api.json', 'r+'); if (flock($fp, LOCK_EX)) { // lock the file fwrite($fp, $json); flock($fp, LOCK_UN); // unlock the file //$log->save('user_activities','api.json updated with ' . count($mapData['locations']) . ' records'); } else { // flock() returned false, no lock obtained $log->save('user_activities',"Could not lock api.json. Update failed"); } fclose($fp); excerpt from form.php: // lock api.json while reading/writing to prevent collision with lazycron $handle = fopen('api.json', 'r'); while (!flock($handle, LOCK_SH)) { usleep(1); } $inp = fread($handle, filesize('api.json')); $tempArray = json_decode($inp, true); // convert json to php array array_push($tempArray['locations'], $mapData['locations']); // add new data to end of array $jsonData = json_encode($tempArray); // convert back to json file_put_contents('api.json', $jsonData); // re-write the file flock($handle, LOCK_UN); fclose($handle);
  2. I had an odd bug that I haven't been able to replicate and I'm wondering if it's possible for some code run by an AJAX call to simultaneously try to overwrite a file that is also being updated by a lazycron routine. In order to get the website to load in a reasonable time, I read in a bunch of asset data from a static json file rather than using page->children(). Every couple of hours, lazycron reads through all the assets and updates the file. When users add new assets, though, the code that creates a new asset page also appends the record to the end of the json file so that it will be visible right away. This usually works fine but the other day a user added six assets in a relatively short period and the json file got corrupted. Due to competing demands for my time, and the panic of my boss over the empty screen, I revived the website quickly without saving the corrupt file for later analysis. I have tried to replicate the error on a staging site but with no success. Does anyone think that a collision is at all likely in this scenario? Is there a way to either suspend the execution of a lazycron routine, or to suspend access to a particular file, in code?
  3. This is the line where it crashes: $transport_pages = $pages->find("template=aggregate-entry, aggregate_type.title='Transport'"); Do you mean it should be this instead?: $transport_pages = wire('$pages')->find("template=aggregate-entry, aggregate_type.title='Transport'");
  4. I'm trying to get a short routine to run once per day that will look at some pages and send a reminder email when that customer's subscription (yearly) is about to expire. When I run the code in a template then it works without issue, but inside my lazycron service routine, I get an "Error: Uncaught Error: Call to a member function get() on null" as if the database cannot be found. My autoload module is just the sample HelloWorld module included with ProcessWire, editted to perform this task. The whole of it is included below (I've stripped out the code that generates the email because it never gets past $pages->find): <?php namespace ProcessWire; /** * ProcessWire 'LazyCronLoad' module * */ class LazyCronLoad extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'LazyCronLoad', 'version' => 1, 'summary' => 'Just loads a lazy cron callback.', 'singular' => true, 'autoload' => true, ); } public function init() { // initialize the hook in the AutoLoad module $this->addHook('LazyCron::everyDay', $this, 'myHook'); } public function myHook(HookEvent $e) { // called once per day wire('log')->save('user_activities',' lazy cron service routine'); $transport_pages = $pages->find("template=aggregate-entry, aggregate_type.title='Transport'"); foreach ($transport_pages as $page) { if (($page->purchase_date + 30325800 < time()) && ($page->purchase_date + 30412600 > time())) { // between 351 and 352 days wire('log')->save('user_activities', $page->id . ' email reminder sent'); // send email } } } } The first wire('log') shows up but the second one doesn't (the purchase_date condition is met (as demonstrated by running the code in a template close in time to when the lazycron routine executes)). The error log gives the Uncaught Error shown above. I think this is a beginner's mistake with something obvious being missed and would be grateful for any assistance in fixing it.
  • Create New...