Jump to content

PWCron


Entil`zha
 Share

Recommended Posts

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
Link to comment
Share on other sites

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
Link to comment
Share on other sites

  • 4 weeks later...

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
Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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
Link to comment
Share on other sites

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}

 

Link to comment
Share on other sites

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
Link to comment
Share on other sites

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
Link to comment
Share on other sites

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
 Share

×
×
  • Create New...