Jump to content

Recommended Posts

Posted

Hi,

We made a little help tool for implementing cron to processwire. Basically the module has two options to run module methods under cron:

  • Lazy method: Just add simple config line to configuration field where you specify module, method and time delay
  • Pro method: Just hook to our method and do everything you want

Getting started should be relative easy, just install module and add line to configuration field (MyModule;MyMethdo;+10 minute). Delay accepts strtotime formats.

http://modules.processwire.com/modules/pwcron/

  • Like 7
Posted
38 minutes ago, horst said:

Many thanks for the contribution. Does it work with PW 3, too?

Yes, we just forget to put tap in place. :)

  • Like 1
Posted
11 hours ago, kongondo said:

Excellent, thanks! Does Pro method mean it will run automatically (i.e. not lazy and does not require, for example, a 'web visitor')? 

Actually both methods will run automatically, there's already another module for executing cron via webvisitors (Lazycron or something like that).

So both methods will run automatically depending how task is defined at crontab (etc. /etc/crontab), the lazy option is targeted for users who just need to run some basic tasks and the pro option is targeted for users who want to do more. :)

I'm gonna write a better instructions but it's still on todo :)

  • Like 5
Posted

Brilliant!^-^.  Exactly what the doctor ordered :). I needed something that will run without user intervention (i.e. without the need for web visitors)

  • 4 weeks later...
Posted (edited)

Hi,

I have the following error on ProcessWire 3.0.40 / MySQL 5.6.28 / PHP 5.6.25 :

 

Quote

Fatal error: Exception: SQLSTATE[HY000] [2002] No such file or directory (in /www/sites/skom/wwwroot/wire/core/ProcessWire.php line 308)

#0 /www/sites/skom/wwwroot/wire/core/ProcessWire.php(149): ProcessWire\ProcessWire->load(Object(ProcessWire\Config))
#1 /www/sites/skom/wwwroot/index.php(52): ProcessWire\ProcessWire->__construct(Object(ProcessWire\Config))
#2 /www/sites/skom/wwwroot/site/modules/PWCron/cron.php(15): require_once('/www/sites/skom...')
#3 {main} in /www/sites/skom/wwwroot/index.php on line 64

 

And this error on another live site (ProcessWire 3.0.25 / MySQL 5.5.50 /  PHP 5.6.24 :

Quote

Error: Call to undefined function wire() (line 17 of [...]/public_html/site/modules/PWCron/cron.php)

 

Edited by flydev
second test
Posted

Another try on PW 3.0.40, another error :

Quote

Notice: Undefined offset: 1 in [...]/wire/modules/Process/ProcessModule/ProcessModule.module on line 623

Notice: Undefined offset: 1 in [...]/wire/modules/Process/ProcessModule/ProcessModule.module on line 623

  • ProcessModule: Invalid module name: PWCron

 

Someone has already tried this module ? if so, is it working properly?

Posted

I have tried it, but added namespace to the files and also renamed the PWCron class-, file-, and directory-names to camelcase PwCron. Don't remember of any other changes. We have a cron setup to call cron.php every 5 minutes via CLI. All is working as expected after the changes described above, incl. the $wire API var.

  • Like 1
Posted

Thank you horst, I made the change, now calling the cron.php via CLI still give me this error :

Quote

Error: Exception: SQLSTATE[HY000] [2002] No such file or directory (in /www/sites/skom/wwwroot/wire/core/ProcessWire.php line 308)

#0 /www/sites/skom/wwwroot/wire/core/ProcessWire.php(149): ProcessWire\ProcessWire->load(Object(ProcessWire\Config))

#1 /www/sites/skom/wwwroot/index.php(52): ProcessWire\ProcessWire->__construct(Object(ProcessWire\Config))

#2 /www/sites/skom/wwwroot/site/modules/PwCron/cron.php(15): require_once('/www/sites/skom...')

#3 {main}

 

Posted (edited)

content of our cron.php:

Spoiler

<?php namespace ProcessWire;
/**
 * Cron file to call from /etc/crontab
 *
 * Call this file from system crontab
 *
 * example:
 * 0,15,30,45 * * * * user  php <path_to_pw>/site/modules/PwCron/cron.php
 *
 * @author Joonas Kolkka <joonas.kolkka@comspot.fi>
 * @author Ville Sulin <ville.sulin@comspot.fi>
*/

/** Bootstrap ProcessWire */
require_once(__DIR__ . '/../../../index.php');

if($wire->modules->isInstalled('PwCron')) {
    $cron = $wire->modules->get('PwCron');
    if($cron) {
        $cron->run();
    }
}

 

 and the PwCron.module file:

Spoiler

<?php namespace ProcessWire;

/**
 * PwCron - Cron implementation for ProcessWire
 *
 * @author Joonas Kolkka <joonas.kolkka@comspot.fi>
 * @author Ville Sulin <ville.sulin@comspot.fi>
 */

class PwCron extends Process implements Module, ConfigurableModule {

    private $runstateData;

    public function __construct() {
        foreach(self::getDefaultConfigData() as $key => $value) {
            $this->$key = $value;
        }
        $this->runstateData = new \StdClass();
    }

    static public function getModuleInfo() {
        return array(
            'title'    => 'PwCron',
            'version'  => 300,
            'author'   => 'Ville Sulin & Joonas Kolkka',
            'summary'  => 'Cron implementation for Processwire',
            'href'     => 'https://processwire.com/talk/topic/14572-pwcron/',
            'singular' => true,
            'autoload' => false,
        );
    }

    static private function getDefaultConfigData() {
        return array(
            "runconfig" => "",
            "runstate" => "",
        );
    }

    public function init() {
        /** Read runstate and seperate lines */
        $lines = explode("\n", $this->runstate);
        /** Loop trough lines */
        foreach ($lines as $line) {
            /** Seperate running info */
            $l = explode(";", $line);

            /** Check if line has enough data */
            if(count($l) != 5) continue;
            /** Check if module exists and if not, create it */
            if(!isset($this->runstateData->{$l[0]})) {
                $this->runstateData->{$l[0]} = new \StdClass();
            }
            /** Set method run data to new object */
            $this->runstateData->{$l[0]}->{$l[1]} = new \StdClass();
            $this->runstateData->{$l[0]}->{$l[1]}->last_start = $l[2];
            $this->runstateData->{$l[0]}->{$l[1]}->last_done = $l[3];
            $this->runstateData->{$l[0]}->{$l[1]}->last_status = $l[4];
        }
    }

	/**
	 *	method to hook other modules, hook this!
	**/
	public function ___cronHook() {

	}


	/**
	 *	method that does the magic
	 *
	 *	Method will first read modules configured under runconfig
	 *	and execute them. After that it runs all hooked modules
	 *
	 *	@return boolean true or false
	**/
    public function run() {
		/** Read runconfig and sepereate lines */
		$lines = explode("\n", $this->runconfig);

		/** Loop trough lines */
		foreach ($lines as $line) {
			/** If line is empty, continue */
			if($line == "") continue;
			/** Get job information */
			$l = explode(";", $line);

			/** Check has module been ran */
			if(!isset($this->runstateData->{$l[0]})) {
				$this->runstateData->{$l[0]} = new \StdClass();
			}

			/** Check has method been ran */
			if(!isset($this->runstateData->{$l[0]}->{$l[1]})) {
					$this->runstateData->{$l[0]}->{$l[1]} = new \StdClass();
					$this->runstateData->{$l[0]}->{$l[1]}->last_start =  "";
					$this->runstateData->{$l[0]}->{$l[1]}->last_done =  "";
					$this->runstateData->{$l[0]}->{$l[1]}->last_status =  "";

			}

			/** Check is it time to run module again */
			if (time() > strtotime($l[2], strtotime($this->runstateData->{$l[0]}->{$l[1]}->last_done))) {
				/** Load module */
				$module = $this->modules->get($l[0]);
				/** Update start time */
				$this->runstateData->{$l[0]}->{$l[1]}->last_start = date("Y-m-d H:i:s", time());
				/** Start output buffering */
				ob_start();
				/** Call method */
				$returnInfo = $module->{$l[1]}();
				/** Get buffered output */
				$output = ob_get_contents();
				/** Clean output buffer */
				ob_end_clean();
				/** Update End time */
				$this->runstateData->{$l[0]}->{$l[1]}->last_done = date("Y-m-d H:i:s", time());
			}
			/** Save running state data after each run */
			$this->saveRunningStateData();
		}
		//if(isset($output)) echo $output;
		//echo $returnInfo;

		/** Run hooked modules */
		$this->cronHook();
	}

	public function install() {

	}

	/**
	 * Save runningstate after each run
	 */
	private function saveRunningStateData() {
		$config = $this->wire('modules')->getModuleConfigData('PwCron');
		$statedata = array();
		foreach($this->runstateData as $module => $moduledata) {
			foreach ($moduledata as $method => $methoddata) {
				array_push($statedata, implode(";", array(
					$module,
					$method,
					$methoddata->last_start,
					$methoddata->last_done,
					$methoddata->last_status,
					)));
			}
		}
        $config["runstate"] = implode("\n", $statedata);
		$this->wire('modules')->saveModuleConfigData('PwCron', $config);
	}


	static public function getModuleConfigInputfields(array $data) {

		$fields = new InputfieldWrapper();
		$modules = Wire::getFuel('modules');

		$field = $modules->get('InputfieldTextarea');
		$field->attr('name', 'runconfig');
		$field->attr('size', 10);
		$field->attr('value', $data['runconfig']);
		$field->label = 'Modules to run';
		$field->description = "Module per line. Syntax: ModuleName;Method;Delay.";
		$fields->append($field);

		$field = $modules->get('InputfieldTextarea');
		$field->attr('name', 'runstate');
		$field->attr('size', 10);
		$field->attr('value', $data['runstate']);
		$field->label = 'Info from running crons';
		$fields->append($field);

		return $fields;
	}
}

 

Everything is working fine from 20161107-10:15:06 until now, without errors, in a 5 minute intervall.

EDIT:

Did you refreshed the modules cache after changing the class-, file- and directorynames? :-X

Edited by horst
  • Like 3
Posted

Yes I refreshed the modules cache, but even more, I reinstalled it from scratch (PW, PwCron) but still getting the same error. I will try on a live server into one hour and will come back. Thanks again.

  • Like 1
Posted

Got it working, the cron task call the PHP script.

Now I am getting another exception, but I suspect my code  MariaDB server - I will open a new thread, thanks for your help horst !

 

Quote

Error: Exception: SQLSTATE[HY000]: General error: 2006 MySQL server has gone away

 

 

@Entil`zha could you update the module ? :)

  • Like 2

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...