<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.moodle.org/405/en/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mjollnir</id>
	<title>MoodleDocs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/405/en/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mjollnir"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/Special:Contributions/Mjollnir"/>
	<updated>2026-04-16T13:18:53Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Profiling_PHP&amp;diff=77657</id>
		<title>Development:Profiling PHP</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Profiling_PHP&amp;diff=77657"/>
		<updated>2010-11-10T17:47:50Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Suggestion, please look into xhprof (I saw the following talk about it: https://docs.google.com/present/view?id=dcbkgbgf_45fbg3rnmk&amp;amp;)&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=162045 Forum thread about profiling Moodle 2.0]&lt;br /&gt;
&lt;br /&gt;
{{CategoryDeveloper}}&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=69773</id>
		<title>Development:MNET 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=69773"/>
		<updated>2010-03-16T08:50:56Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Method signatures */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page attempts to summarise the changes in MNET between Moodle 1.9 and Moodle 2.0, both from an administrative perspective, and a code perspective.&lt;br /&gt;
&lt;br /&gt;
There are still things to do before 2.0 is released, so this page is a work in progress.&lt;br /&gt;
&lt;br /&gt;
See [http://tracker.moodle.org/secure/IssueNavigator.jspa?reset=true&amp;amp;&amp;amp;pid=10011&amp;amp;fixfor=10122&amp;amp;status=5&amp;amp;status=6&amp;amp;component=10162&amp;amp;sorter/field=updated&amp;amp;sorter/order=DESC this list] for all closed 2.0 MNET bugs.&lt;br /&gt;
&lt;br /&gt;
== Backwards Compatibility Breaks ==&lt;br /&gt;
&lt;br /&gt;
=== Plugins registering MNET services ===&lt;br /&gt;
&lt;br /&gt;
It used to be that the plugins that needed to export mnet services used a mnet_publishes() method on the class (static or not).  This led to a list of hard coded plugins that supported it, and in some cases auth factory involvement, just to get a list of the RPC functions available.&lt;br /&gt;
&lt;br /&gt;
This has now changed to a file containing an array, in db/mnet.php, similar to lib/db/services.php.  This file looks something like this (example from the Mahara portfolio plugin):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$publishes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;apiversion&#039; =&amp;gt; 1,&lt;br /&gt;
        &#039;classname&#039;  =&amp;gt; &#039;portfolio_plugin_mahara&#039;,&lt;br /&gt;
        &#039;filename&#039;   =&amp;gt; &#039;lib.php&#039;,&lt;br /&gt;
        &#039;methods&#039;    =&amp;gt; array(&lt;br /&gt;
            &#039;fetch_file&#039;&lt;br /&gt;
        ),&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
$subscribes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;send_content_intent&#039; =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_intent&#039;,&lt;br /&gt;
        &#039;send_content_ready&#039;  =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_ready&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that there is a unsymmetricality between the methods that are published and the methods that are subscribed to.  &#039;&#039;&#039;This is new&#039;&#039;&#039; .&lt;br /&gt;
&lt;br /&gt;
This also resulted in two new tables. The old tables, mnet_rpc and mnet_service2rpc relate to the methods that are being published. The new tables, mnet_remote_rpc and mnet_remote_service2rpc relate to the methods that are being subscribed to.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
* MDL-16269&lt;br /&gt;
* MDL-16277&lt;br /&gt;
&lt;br /&gt;
=== Method signatures ===&lt;br /&gt;
&lt;br /&gt;
The method signature code used to use a string tokeniser to parse the php files that contained mnet services and store information about them in the database.  This was unreliable and slow.  We&#039;ve switched to using php5&#039;s reflection utilities, which gives us &#039;&#039;&#039;some&#039;&#039;&#039; information about the code, and the Zend_Server Reflection to get the rest.  This uses the native php5 reflection, as well as parsing the phpdoc blocks to find information about the types of function arguments, and the return values.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important: this means that you &#039;&#039;must&#039;&#039; write phpdocs in the correct format, otherwise a php warning will be generated&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Because of this, we can now reliably include both argument types and return value information in the method signature, where previously only arguments had been included (and in the case of no arguments, the return value had previously been erroneously used).&lt;br /&gt;
&lt;br /&gt;
This means that before where the method signature looked like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    array(&lt;br /&gt;
        /* ... */&lt;br /&gt;
    ),&lt;br /&gt;
    /* ... */&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
it now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;parameters&#039; =&amp;gt;  array(&lt;br /&gt;
        array(&lt;br /&gt;
            &#039;name&#039; =&amp;gt; &#039;token&#039;,&lt;br /&gt;
            &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
            &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
        ),&lt;br /&gt;
        array(&lt;br /&gt;
            /* ... */&lt;br /&gt;
        ),&lt;br /&gt;
        /* ... */,&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;return&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which, although it is unarguably more informative and clearer, is a backwards compatibility break.  This information is what is sent as the response to the system/methodSignature xmlrpc method.  The only place this is used &#039;&#039;&#039;within Moodle&#039;&#039;&#039;, however, is in the old testclient.php, which was present in code, but not linked to from anywhere.  This has been changed and is covered under Administrative changes.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this: &lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
&lt;br /&gt;
== Other code changes ==&lt;br /&gt;
&lt;br /&gt;
=== Removal of all MNET globals ===&lt;br /&gt;
&lt;br /&gt;
There were two regularly used MNET globals, $MNET and $MNET_REMOTE_CLIENT.  These have both been removed, and replaced with get_mnet_environment and get_mnet_remote_client functions, which are available in the global scope.  The mnet remote client object is &#039;&#039;&#039;only&#039;&#039;&#039; set at the start of mnet/xmlrpc/server.php, and if it is attempted to be accessed outside of the mnet xmlrpc server environment, an error will occur.  This will be a debugging() level error in the case of trying to get the mnet remote client object, and an exception if trying to set it.&lt;br /&gt;
&lt;br /&gt;
The last MNET global was only used in one place, and it related to the jump url of a given user.  This was used in rewriting urls in a preg_replace_callback in  email_to_user.  This has been replaced with no global and a partially bound function. PHP has no native partial binding, but a workaround has been recently added to HEAD.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21130&lt;br /&gt;
* MDL-21276&lt;br /&gt;
* MDL-21255&lt;br /&gt;
&lt;br /&gt;
=== Conditional MNET environment bootstrapping ===&lt;br /&gt;
&lt;br /&gt;
Previously any time you included mnet/lib.php, the mnet environment was bootstrapped.  This is not ideal as it adds a lot of unnecessary overhead.  Now any time you need any bit of the mnet environment, you must do $mnet = get_mnet_environment.  Note that this replaces the old $MNET global, but it is no longer always bootstrapped for you.&lt;br /&gt;
&lt;br /&gt;
See the following bug about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21276&lt;br /&gt;
&lt;br /&gt;
=== Removal of library code from mnet/xmlrpc/server.php ===&lt;br /&gt;
&lt;br /&gt;
mnet/xmlrpc/server.php used to contain both functional code and library code, and I always found it annoying reading through what should have been a simple script, which was hundreds of lines long, so I moved all the functions into mnet/xmlrpc/serverlib.php in case they needed to be reused.&lt;br /&gt;
&lt;br /&gt;
=== Better debugging ===&lt;br /&gt;
&lt;br /&gt;
There is now an mnet_debug function which will print to the error log.  MNET previously used trigger_error in places, which raises a PHP-level notice/warning/error.  This is not helpful in all cases, because of ini settings, or log targets.  In particular if php errors are going to STDOUT, this will cause problems in the XMLRPC responses.  The mnet_debug function takes any sort of argument (it will recursively call itself for objects and arrays) and a debuglevel.  This is controlled by $CFG-&amp;gt;mnet_rpcdebug, which is a config.php only setting (and has been there since before the MNET overhaul)&lt;br /&gt;
&lt;br /&gt;
== Administrative changes ==&lt;br /&gt;
&lt;br /&gt;
=== New Networking Test Client ===&lt;br /&gt;
&lt;br /&gt;
Previously there was a hidden MNET test client that could only be accessed via url directly by administrators.  This has been cleaned up, rewritten to work with the method signature and placed under the Development Menu in the main Administration Block.  This can be used to perform introspection on remote hosts and find out what methods are available and what their method signatures are.  It is very helpful for debugging MNET.&lt;br /&gt;
&lt;br /&gt;
This was done as part of MDL-21261&lt;br /&gt;
&lt;br /&gt;
=== Removal of &#039;auto create users&#039; configuration option ===&lt;br /&gt;
&lt;br /&gt;
Under the configuration screen for the MNET authentication plugin, there was previously a setting called &#039;auto add remote users&#039;.  As far as I can understand, there was never a case where this should have been off, so it has been removed now.&lt;br /&gt;
&lt;br /&gt;
See the following forum post:  http://moodle.org/mod/forum/discuss.php?d=141491 and the bug: MDL-21327&lt;br /&gt;
&lt;br /&gt;
=== Reworked MNET administration screens ===&lt;br /&gt;
&lt;br /&gt;
Most of admin/mnet has been updated to use Moodle Forms and the new Output API.  This should not result in functional changes, but there may be some smaller aesthetic ones.  Not all screens have been rewritten yet.&lt;br /&gt;
&lt;br /&gt;
The relevant bug is MDL-21256&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68651</id>
		<title>Development:MNET 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68651"/>
		<updated>2010-02-16T23:50:02Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page attempts to summarise the changes in MNET between Moodle 1.9 and Moodle 2.0, both from an administrative perspective, and a code perspective.&lt;br /&gt;
&lt;br /&gt;
There are still things to do before 2.0 is released, so this page is a work in progress.&lt;br /&gt;
&lt;br /&gt;
See [http://tracker.moodle.org/secure/IssueNavigator.jspa?reset=true&amp;amp;&amp;amp;pid=10011&amp;amp;fixfor=10122&amp;amp;status=5&amp;amp;status=6&amp;amp;component=10162&amp;amp;sorter/field=updated&amp;amp;sorter/order=DESC this list] for all closed 2.0 MNET bugs.&lt;br /&gt;
&lt;br /&gt;
== Backwards Compatibility Breaks ==&lt;br /&gt;
&lt;br /&gt;
=== Plugins registering MNET services ===&lt;br /&gt;
&lt;br /&gt;
It used to be that the plugins that needed to export mnet services used a mnet_publishes() method on the class (static or not).  This led to a list of hard coded plugins that supported it, and in some cases auth factory involvement, just to get a list of the RPC functions available.&lt;br /&gt;
&lt;br /&gt;
This has now changed to a file containing an array, in db/mnet.php, similar to lib/db/services.php.  This file looks something like this (example from the Mahara portfolio plugin):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$publishes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;apiversion&#039; =&amp;gt; 1,&lt;br /&gt;
        &#039;classname&#039;  =&amp;gt; &#039;portfolio_plugin_mahara&#039;,&lt;br /&gt;
        &#039;filename&#039;   =&amp;gt; &#039;lib.php&#039;,&lt;br /&gt;
        &#039;methods&#039;    =&amp;gt; array(&lt;br /&gt;
            &#039;fetch_file&#039;&lt;br /&gt;
        ),&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
$subscribes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;send_content_intent&#039; =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_intent&#039;,&lt;br /&gt;
        &#039;send_content_ready&#039;  =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_ready&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that there is a unsymmetricality between the methods that are published and the methods that are subscribed to.  &#039;&#039;&#039;This is new&#039;&#039;&#039; .&lt;br /&gt;
&lt;br /&gt;
This also resulted in two new tables. The old tables, mnet_rpc and mnet_service2rpc relate to the methods that are being published. The new tables, mnet_remote_rpc and mnet_remote_service2rpc relate to the methods that are being subscribed to.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
* MDL-16269&lt;br /&gt;
* MDL-16277&lt;br /&gt;
&lt;br /&gt;
=== Method signatures ===&lt;br /&gt;
&lt;br /&gt;
The method signature code used to use a string tokeniser to parse the php files that contained mnet services and store information about them in the database.  This was unreliable and slow.  We&#039;ve switched to using php5&#039;s reflection utilities, which gives us &#039;&#039;&#039;some&#039;&#039;&#039; information about the code, and the Zend_Server Reflection to get the rest.  This uses the native php5 reflection, as well as parsing the phpdoc blocks to find information about the types of function arguments, and the return values.&lt;br /&gt;
&lt;br /&gt;
Because of this, we can now reliably include both argument types and return value information in the method signature, where previously only arguments had been included (and in the case of no arguments, the return value had previously been erroneously used).&lt;br /&gt;
&lt;br /&gt;
This means that before where the method signature looked like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    array(&lt;br /&gt;
        /* ... */&lt;br /&gt;
    ),&lt;br /&gt;
    /* ... */&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
it now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;parameters&#039; =&amp;gt;  array(&lt;br /&gt;
        array(&lt;br /&gt;
            &#039;name&#039; =&amp;gt; &#039;token&#039;,&lt;br /&gt;
            &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
            &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
        ),&lt;br /&gt;
        array(&lt;br /&gt;
            /* ... */&lt;br /&gt;
        ),&lt;br /&gt;
        /* ... */,&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;return&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which, although it is unarguably more informative and clearer, is a backwards compatibility break.  This information is what is sent as the response to the system/methodSignature xmlrpc method.  The only place this is used &#039;&#039;&#039;within Moodle&#039;&#039;&#039;, however, is in the old testclient.php, which was present in code, but not linked to from anywhere.  This has been changed and is covered under Administrative changes.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this: &lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
&lt;br /&gt;
== Other code changes ==&lt;br /&gt;
&lt;br /&gt;
=== Removal of all MNET globals ===&lt;br /&gt;
&lt;br /&gt;
There were two regularly used MNET globals, $MNET and $MNET_REMOTE_CLIENT.  These have both been removed, and replaced with get_mnet_environment and get_mnet_remote_client functions, which are available in the global scope.  The mnet remote client object is &#039;&#039;&#039;only&#039;&#039;&#039; set at the start of mnet/xmlrpc/server.php, and if it is attempted to be accessed outside of the mnet xmlrpc server environment, an error will occur.  This will be a debugging() level error in the case of trying to get the mnet remote client object, and an exception if trying to set it.&lt;br /&gt;
&lt;br /&gt;
The last MNET global was only used in one place, and it related to the jump url of a given user.  This was used in rewriting urls in a preg_replace_callback in  email_to_user.  This has been replaced with no global and a partially bound function. PHP has no native partial binding, but a workaround has been recently added to HEAD.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21130&lt;br /&gt;
* MDL-21276&lt;br /&gt;
* MDL-21255&lt;br /&gt;
&lt;br /&gt;
=== Conditional MNET environment bootstrapping ===&lt;br /&gt;
&lt;br /&gt;
Previously any time you included mnet/lib.php, the mnet environment was bootstrapped.  This is not ideal as it adds a lot of unnecessary overhead.  Now any time you need any bit of the mnet environment, you must do $mnet = get_mnet_environment.  Note that this replaces the old $MNET global, but it is no longer always bootstrapped for you.&lt;br /&gt;
&lt;br /&gt;
See the following bug about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21276&lt;br /&gt;
&lt;br /&gt;
=== Removal of library code from mnet/xmlrpc/server.php ===&lt;br /&gt;
&lt;br /&gt;
mnet/xmlrpc/server.php used to contain both functional code and library code, and I always found it annoying reading through what should have been a simple script, which was hundreds of lines long, so I moved all the functions into mnet/xmlrpc/serverlib.php in case they needed to be reused.&lt;br /&gt;
&lt;br /&gt;
=== Better debugging ===&lt;br /&gt;
&lt;br /&gt;
There is now an mnet_debug function which will print to the error log.  MNET previously used trigger_error in places, which raises a PHP-level notice/warning/error.  This is not helpful in all cases, because of ini settings, or log targets.  In particular if php errors are going to STDOUT, this will cause problems in the XMLRPC responses.  The mnet_debug function takes any sort of argument (it will recursively call itself for objects and arrays) and a debuglevel.  This is controlled by $CFG-&amp;gt;mnet_rpcdebug, which is a config.php only setting (and has been there since before the MNET overhaul)&lt;br /&gt;
&lt;br /&gt;
== Administrative changes ==&lt;br /&gt;
&lt;br /&gt;
=== New Networking Test Client ===&lt;br /&gt;
&lt;br /&gt;
Previously there was a hidden MNET test client that could only be accessed via url directly by administrators.  This has been cleaned up, rewritten to work with the method signature and placed under the Development Menu in the main Administration Block.  This can be used to perform introspection on remote hosts and find out what methods are available and what their method signatures are.  It is very helpful for debugging MNET.&lt;br /&gt;
&lt;br /&gt;
This was done as part of MDL-21261&lt;br /&gt;
&lt;br /&gt;
=== Removal of &#039;auto create users&#039; configuration option ===&lt;br /&gt;
&lt;br /&gt;
Under the configuration screen for the MNET authentication plugin, there was previously a setting called &#039;auto add remote users&#039;.  As far as I can understand, there was never a case where this should have been off, so it has been removed now.&lt;br /&gt;
&lt;br /&gt;
See the following forum post:  http://moodle.org/mod/forum/discuss.php?d=141491 and the bug: MDL-21327&lt;br /&gt;
&lt;br /&gt;
=== Reworked MNET administration screens ===&lt;br /&gt;
&lt;br /&gt;
Most of admin/mnet has been updated to use Moodle Forms and the new Output API.  This should not result in functional changes, but there may be some smaller aesthetic ones.  Not all screens have been rewritten yet.&lt;br /&gt;
&lt;br /&gt;
The relevant bug is MDL-21256&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68650</id>
		<title>Development:MNET 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68650"/>
		<updated>2010-02-16T23:49:16Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page attempts to summarise the changes in MNET between Moodle 1.9 and Moodle 2.0, both from an administrative perspective, and a code perspective.&lt;br /&gt;
&lt;br /&gt;
There are still things to do before 2.0 is released, so this page is a work in progress.&lt;br /&gt;
&lt;br /&gt;
See [ http://tracker.moodle.org/secure/IssueNavigator.jspa?reset=true&amp;amp;&amp;amp;pid=10011&amp;amp;fixfor=10122&amp;amp;status=5&amp;amp;status=6&amp;amp;component=10162&amp;amp;sorter/field=updated&amp;amp;sorter/order=DESC this list] for all closed 2.0 MNET bugs.&lt;br /&gt;
&lt;br /&gt;
== Backwards Compatibility Breaks ==&lt;br /&gt;
&lt;br /&gt;
=== Plugins registering MNET services ===&lt;br /&gt;
&lt;br /&gt;
It used to be that the plugins that needed to export mnet services used a mnet_publishes() method on the class (static or not).  This led to a list of hard coded plugins that supported it, and in some cases auth factory involvement, just to get a list of the RPC functions available.&lt;br /&gt;
&lt;br /&gt;
This has now changed to a file containing an array, in db/mnet.php, similar to lib/db/services.php.  This file looks something like this (example from the Mahara portfolio plugin):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$publishes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;apiversion&#039; =&amp;gt; 1,&lt;br /&gt;
        &#039;classname&#039;  =&amp;gt; &#039;portfolio_plugin_mahara&#039;,&lt;br /&gt;
        &#039;filename&#039;   =&amp;gt; &#039;lib.php&#039;,&lt;br /&gt;
        &#039;methods&#039;    =&amp;gt; array(&lt;br /&gt;
            &#039;fetch_file&#039;&lt;br /&gt;
        ),&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
$subscribes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;send_content_intent&#039; =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_intent&#039;,&lt;br /&gt;
        &#039;send_content_ready&#039;  =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_ready&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that there is a unsymmetricality between the methods that are published and the methods that are subscribed to.  &#039;&#039;&#039;This is new&#039;&#039;&#039; .&lt;br /&gt;
&lt;br /&gt;
This also resulted in two new tables. The old tables, mnet_rpc and mnet_service2rpc relate to the methods that are being published. The new tables, mnet_remote_rpc and mnet_remote_service2rpc relate to the methods that are being subscribed to.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
* MDL-16269&lt;br /&gt;
* MDL-16277&lt;br /&gt;
&lt;br /&gt;
=== Method signatures ===&lt;br /&gt;
&lt;br /&gt;
The method signature code used to use a string tokeniser to parse the php files that contained mnet services and store information about them in the database.  This was unreliable and slow.  We&#039;ve switched to using php5&#039;s reflection utilities, which gives us &#039;&#039;&#039;some&#039;&#039;&#039; information about the code, and the Zend_Server Reflection to get the rest.  This uses the native php5 reflection, as well as parsing the phpdoc blocks to find information about the types of function arguments, and the return values.&lt;br /&gt;
&lt;br /&gt;
Because of this, we can now reliably include both argument types and return value information in the method signature, where previously only arguments had been included (and in the case of no arguments, the return value had previously been erroneously used).&lt;br /&gt;
&lt;br /&gt;
This means that before where the method signature looked like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    array(&lt;br /&gt;
        /* ... */&lt;br /&gt;
    ),&lt;br /&gt;
    /* ... */&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
it now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;parameters&#039; =&amp;gt;  array(&lt;br /&gt;
        array(&lt;br /&gt;
            &#039;name&#039; =&amp;gt; &#039;token&#039;,&lt;br /&gt;
            &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
            &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
        ),&lt;br /&gt;
        array(&lt;br /&gt;
            /* ... */&lt;br /&gt;
        ),&lt;br /&gt;
        /* ... */,&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;return&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which, although it is unarguably more informative and clearer, is a backwards compatibility break.  This information is what is sent as the response to the system/methodSignature xmlrpc method.  The only place this is used &#039;&#039;&#039;within Moodle&#039;&#039;&#039;, however, is in the old testclient.php, which was present in code, but not linked to from anywhere.  This has been changed and is covered under Administrative changes.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this: &lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
&lt;br /&gt;
== Other code changes ==&lt;br /&gt;
&lt;br /&gt;
=== Removal of all MNET globals ===&lt;br /&gt;
&lt;br /&gt;
There were two regularly used MNET globals, $MNET and $MNET_REMOTE_CLIENT.  These have both been removed, and replaced with get_mnet_environment and get_mnet_remote_client functions, which are available in the global scope.  The mnet remote client object is &#039;&#039;&#039;only&#039;&#039;&#039; set at the start of mnet/xmlrpc/server.php, and if it is attempted to be accessed outside of the mnet xmlrpc server environment, an error will occur.  This will be a debugging() level error in the case of trying to get the mnet remote client object, and an exception if trying to set it.&lt;br /&gt;
&lt;br /&gt;
The last MNET global was only used in one place, and it related to the jump url of a given user.  This was used in rewriting urls in a preg_replace_callback in  email_to_user.  This has been replaced with no global and a partially bound function. PHP has no native partial binding, but a workaround has been recently added to HEAD.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21130&lt;br /&gt;
* MDL-21276&lt;br /&gt;
* MDL-21255&lt;br /&gt;
&lt;br /&gt;
=== Conditional MNET environment bootstrapping ===&lt;br /&gt;
&lt;br /&gt;
Previously any time you included mnet/lib.php, the mnet environment was bootstrapped.  This is not ideal as it adds a lot of unnecessary overhead.  Now any time you need any bit of the mnet environment, you must do $mnet = get_mnet_environment.  Note that this replaces the old $MNET global, but it is no longer always bootstrapped for you.&lt;br /&gt;
&lt;br /&gt;
See the following bug about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21276&lt;br /&gt;
&lt;br /&gt;
=== Removal of library code from mnet/xmlrpc/server.php ===&lt;br /&gt;
&lt;br /&gt;
mnet/xmlrpc/server.php used to contain both functional code and library code, and I always found it annoying reading through what should have been a simple script, which was hundreds of lines long, so I moved all the functions into mnet/xmlrpc/serverlib.php in case they needed to be reused.&lt;br /&gt;
&lt;br /&gt;
=== Better debugging ===&lt;br /&gt;
&lt;br /&gt;
There is now an mnet_debug function which will print to the error log.  MNET previously used trigger_error in places, which raises a PHP-level notice/warning/error.  This is not helpful in all cases, because of ini settings, or log targets.  In particular if php errors are going to STDOUT, this will cause problems in the XMLRPC responses.  The mnet_debug function takes any sort of argument (it will recursively call itself for objects and arrays) and a debuglevel.  This is controlled by $CFG-&amp;gt;mnet_rpcdebug, which is a config.php only setting (and has been there since before the MNET overhaul)&lt;br /&gt;
&lt;br /&gt;
== Administrative changes ==&lt;br /&gt;
&lt;br /&gt;
=== New Networking Test Client ===&lt;br /&gt;
&lt;br /&gt;
Previously there was a hidden MNET test client that could only be accessed via url directly by administrators.  This has been cleaned up, rewritten to work with the method signature and placed under the Development Menu in the main Administration Block.  This can be used to perform introspection on remote hosts and find out what methods are available and what their method signatures are.  It is very helpful for debugging MNET.&lt;br /&gt;
&lt;br /&gt;
This was done as part of MDL-21261&lt;br /&gt;
&lt;br /&gt;
=== Removal of &#039;auto create users&#039; configuration option ===&lt;br /&gt;
&lt;br /&gt;
Under the configuration screen for the MNET authentication plugin, there was previously a setting called &#039;auto add remote users&#039;.  As far as I can understand, there was never a case where this should have been off, so it has been removed now.&lt;br /&gt;
&lt;br /&gt;
See the following forum post:  http://moodle.org/mod/forum/discuss.php?d=141491 and the bug: MDL-21327&lt;br /&gt;
&lt;br /&gt;
=== Reworked MNET administration screens ===&lt;br /&gt;
&lt;br /&gt;
Most of admin/mnet has been updated to use Moodle Forms and the new Output API.  This should not result in functional changes, but there may be some smaller aesthetic ones.  Not all screens have been rewritten yet.&lt;br /&gt;
&lt;br /&gt;
The relevant bug is MDL-21256&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68649</id>
		<title>Development:MNET 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68649"/>
		<updated>2010-02-16T23:45:38Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Other code changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page attempts to summarise the changes in MNET between Moodle 1.9 and Moodle 2.0, both from an administrative perspective, and a code perspective.&lt;br /&gt;
&lt;br /&gt;
There are still things to do before 2.0 is released, so this page is a work in progress.&lt;br /&gt;
&lt;br /&gt;
== Backwards Compatibility Breaks ==&lt;br /&gt;
&lt;br /&gt;
=== Plugins registering MNET services ===&lt;br /&gt;
&lt;br /&gt;
It used to be that the plugins that needed to export mnet services used a mnet_publishes() method on the class (static or not).  This led to a list of hard coded plugins that supported it, and in some cases auth factory involvement, just to get a list of the RPC functions available.&lt;br /&gt;
&lt;br /&gt;
This has now changed to a file containing an array, in db/mnet.php, similar to lib/db/services.php.  This file looks something like this (example from the Mahara portfolio plugin):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$publishes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;apiversion&#039; =&amp;gt; 1,&lt;br /&gt;
        &#039;classname&#039;  =&amp;gt; &#039;portfolio_plugin_mahara&#039;,&lt;br /&gt;
        &#039;filename&#039;   =&amp;gt; &#039;lib.php&#039;,&lt;br /&gt;
        &#039;methods&#039;    =&amp;gt; array(&lt;br /&gt;
            &#039;fetch_file&#039;&lt;br /&gt;
        ),&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
$subscribes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;send_content_intent&#039; =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_intent&#039;,&lt;br /&gt;
        &#039;send_content_ready&#039;  =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_ready&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that there is a unsymmetricality between the methods that are published and the methods that are subscribed to.  &#039;&#039;&#039;This is new&#039;&#039;&#039; .&lt;br /&gt;
&lt;br /&gt;
This also resulted in two new tables. The old tables, mnet_rpc and mnet_service2rpc relate to the methods that are being published. The new tables, mnet_remote_rpc and mnet_remote_service2rpc relate to the methods that are being subscribed to.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
* MDL-16269&lt;br /&gt;
* MDL-16277&lt;br /&gt;
&lt;br /&gt;
=== Method signatures ===&lt;br /&gt;
&lt;br /&gt;
The method signature code used to use a string tokeniser to parse the php files that contained mnet services and store information about them in the database.  This was unreliable and slow.  We&#039;ve switched to using php5&#039;s reflection utilities, which gives us &#039;&#039;&#039;some&#039;&#039;&#039; information about the code, and the Zend_Server Reflection to get the rest.  This uses the native php5 reflection, as well as parsing the phpdoc blocks to find information about the types of function arguments, and the return values.&lt;br /&gt;
&lt;br /&gt;
Because of this, we can now reliably include both argument types and return value information in the method signature, where previously only arguments had been included (and in the case of no arguments, the return value had previously been erroneously used).&lt;br /&gt;
&lt;br /&gt;
This means that before where the method signature looked like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    array(&lt;br /&gt;
        /* ... */&lt;br /&gt;
    ),&lt;br /&gt;
    /* ... */&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
it now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;parameters&#039; =&amp;gt;  array(&lt;br /&gt;
        array(&lt;br /&gt;
            &#039;name&#039; =&amp;gt; &#039;token&#039;,&lt;br /&gt;
            &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
            &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
        ),&lt;br /&gt;
        array(&lt;br /&gt;
            /* ... */&lt;br /&gt;
        ),&lt;br /&gt;
        /* ... */,&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;return&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which, although it is unarguably more informative and clearer, is a backwards compatibility break.  This information is what is sent as the response to the system/methodSignature xmlrpc method.  The only place this is used &#039;&#039;&#039;within Moodle&#039;&#039;&#039;, however, is in the old testclient.php, which was present in code, but not linked to from anywhere.  This has been changed and is covered under Administrative changes.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this: &lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
&lt;br /&gt;
== Other code changes ==&lt;br /&gt;
&lt;br /&gt;
=== Removal of all MNET globals ===&lt;br /&gt;
&lt;br /&gt;
There were two regularly used MNET globals, $MNET and $MNET_REMOTE_CLIENT.  These have both been removed, and replaced with get_mnet_environment and get_mnet_remote_client functions, which are available in the global scope.  The mnet remote client object is &#039;&#039;&#039;only&#039;&#039;&#039; set at the start of mnet/xmlrpc/server.php, and if it is attempted to be accessed outside of the mnet xmlrpc server environment, an error will occur.  This will be a debugging() level error in the case of trying to get the mnet remote client object, and an exception if trying to set it.&lt;br /&gt;
&lt;br /&gt;
The last MNET global was only used in one place, and it related to the jump url of a given user.  This was used in rewriting urls in a preg_replace_callback in  email_to_user.  This has been replaced with no global and a partially bound function. PHP has no native partial binding, but a workaround has been recently added to HEAD.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21130&lt;br /&gt;
* MDL-21276&lt;br /&gt;
* MDL-21255&lt;br /&gt;
&lt;br /&gt;
=== Conditional MNET environment bootstrapping ===&lt;br /&gt;
&lt;br /&gt;
Previously any time you included mnet/lib.php, the mnet environment was bootstrapped.  This is not ideal as it adds a lot of unnecessary overhead.  Now any time you need any bit of the mnet environment, you must do $mnet = get_mnet_environment.  Note that this replaces the old $MNET global, but it is no longer always bootstrapped for you.&lt;br /&gt;
&lt;br /&gt;
See the following bug about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21276&lt;br /&gt;
&lt;br /&gt;
=== Removal of library code from mnet/xmlrpc/server.php ===&lt;br /&gt;
&lt;br /&gt;
mnet/xmlrpc/server.php used to contain both functional code and library code, and I always found it annoying reading through what should have been a simple script, which was hundreds of lines long, so I moved all the functions into mnet/xmlrpc/serverlib.php in case they needed to be reused.&lt;br /&gt;
&lt;br /&gt;
=== Better debugging ===&lt;br /&gt;
&lt;br /&gt;
There is now an mnet_debug function which will print to the error log.  MNET previously used trigger_error in places, which raises a PHP-level notice/warning/error.  This is not helpful in all cases, because of ini settings, or log targets.  In particular if php errors are going to STDOUT, this will cause problems in the XMLRPC responses.  The mnet_debug function takes any sort of argument (it will recursively call itself for objects and arrays) and a debuglevel.  This is controlled by $CFG-&amp;gt;mnet_rpcdebug, which is a config.php only setting (and has been there since before the MNET overhaul)&lt;br /&gt;
&lt;br /&gt;
== Administrative changes ==&lt;br /&gt;
&lt;br /&gt;
=== New Networking Test Client ===&lt;br /&gt;
&lt;br /&gt;
Previously there was a hidden MNET test client that could only be accessed via url directly by administrators.  This has been cleaned up, rewritten to work with the method signature and placed under the Development Menu in the main Administration Block.  This can be used to perform introspection on remote hosts and find out what methods are available and what their method signatures are.  It is very helpful for debugging MNET.&lt;br /&gt;
&lt;br /&gt;
This was done as part of MDL-21261&lt;br /&gt;
&lt;br /&gt;
=== Removal of &#039;auto create users&#039; configuration option ===&lt;br /&gt;
&lt;br /&gt;
Under the configuration screen for the MNET authentication plugin, there was previously a setting called &#039;auto add remote users&#039;.  As far as I can understand, there was never a case where this should have been off, so it has been removed now.&lt;br /&gt;
&lt;br /&gt;
See the following forum post:  http://moodle.org/mod/forum/discuss.php?d=141491 and the bug: MDL-21327&lt;br /&gt;
&lt;br /&gt;
=== Reworked MNET administration screens ===&lt;br /&gt;
&lt;br /&gt;
Most of admin/mnet has been updated to use Moodle Forms and the new Output API.  This should not result in functional changes, but there may be some smaller aesthetic ones.  Not all screens have been rewritten yet.&lt;br /&gt;
&lt;br /&gt;
The relevant bug is MDL-21256&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68648</id>
		<title>Development:MNET 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68648"/>
		<updated>2010-02-16T23:26:46Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Administrative changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page attempts to summarise the changes in MNET between Moodle 1.9 and Moodle 2.0, both from an administrative perspective, and a code perspective.&lt;br /&gt;
&lt;br /&gt;
There are still things to do before 2.0 is released, so this page is a work in progress.&lt;br /&gt;
&lt;br /&gt;
== Backwards Compatibility Breaks ==&lt;br /&gt;
&lt;br /&gt;
=== Plugins registering MNET services ===&lt;br /&gt;
&lt;br /&gt;
It used to be that the plugins that needed to export mnet services used a mnet_publishes() method on the class (static or not).  This led to a list of hard coded plugins that supported it, and in some cases auth factory involvement, just to get a list of the RPC functions available.&lt;br /&gt;
&lt;br /&gt;
This has now changed to a file containing an array, in db/mnet.php, similar to lib/db/services.php.  This file looks something like this (example from the Mahara portfolio plugin):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$publishes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;apiversion&#039; =&amp;gt; 1,&lt;br /&gt;
        &#039;classname&#039;  =&amp;gt; &#039;portfolio_plugin_mahara&#039;,&lt;br /&gt;
        &#039;filename&#039;   =&amp;gt; &#039;lib.php&#039;,&lt;br /&gt;
        &#039;methods&#039;    =&amp;gt; array(&lt;br /&gt;
            &#039;fetch_file&#039;&lt;br /&gt;
        ),&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
$subscribes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;send_content_intent&#039; =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_intent&#039;,&lt;br /&gt;
        &#039;send_content_ready&#039;  =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_ready&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that there is a unsymmetricality between the methods that are published and the methods that are subscribed to.  &#039;&#039;&#039;This is new&#039;&#039;&#039; .&lt;br /&gt;
&lt;br /&gt;
This also resulted in two new tables. The old tables, mnet_rpc and mnet_service2rpc relate to the methods that are being published. The new tables, mnet_remote_rpc and mnet_remote_service2rpc relate to the methods that are being subscribed to.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
* MDL-16269&lt;br /&gt;
* MDL-16277&lt;br /&gt;
&lt;br /&gt;
=== Method signatures ===&lt;br /&gt;
&lt;br /&gt;
The method signature code used to use a string tokeniser to parse the php files that contained mnet services and store information about them in the database.  This was unreliable and slow.  We&#039;ve switched to using php5&#039;s reflection utilities, which gives us &#039;&#039;&#039;some&#039;&#039;&#039; information about the code, and the Zend_Server Reflection to get the rest.  This uses the native php5 reflection, as well as parsing the phpdoc blocks to find information about the types of function arguments, and the return values.&lt;br /&gt;
&lt;br /&gt;
Because of this, we can now reliably include both argument types and return value information in the method signature, where previously only arguments had been included (and in the case of no arguments, the return value had previously been erroneously used).&lt;br /&gt;
&lt;br /&gt;
This means that before where the method signature looked like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    array(&lt;br /&gt;
        /* ... */&lt;br /&gt;
    ),&lt;br /&gt;
    /* ... */&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
it now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;parameters&#039; =&amp;gt;  array(&lt;br /&gt;
        array(&lt;br /&gt;
            &#039;name&#039; =&amp;gt; &#039;token&#039;,&lt;br /&gt;
            &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
            &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
        ),&lt;br /&gt;
        array(&lt;br /&gt;
            /* ... */&lt;br /&gt;
        ),&lt;br /&gt;
        /* ... */,&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;return&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which, although it is unarguably more informative and clearer, is a backwards compatibility break.  This information is what is sent as the response to the system/methodSignature xmlrpc method.  The only place this is used &#039;&#039;&#039;within Moodle&#039;&#039;&#039;, however, is in the old testclient.php, which was present in code, but not linked to from anywhere.  This has been changed and is covered under Administrative changes.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this: &lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
&lt;br /&gt;
== Other code changes ==&lt;br /&gt;
&lt;br /&gt;
== Administrative changes ==&lt;br /&gt;
&lt;br /&gt;
=== New Networking Test Client ===&lt;br /&gt;
&lt;br /&gt;
Previously there was a hidden MNET test client that could only be accessed via url directly by administrators.  This has been cleaned up, rewritten to work with the method signature and placed under the Development Menu in the main Administration Block.  This can be used to perform introspection on remote hosts and find out what methods are available and what their method signatures are.  It is very helpful for debugging MNET.&lt;br /&gt;
&lt;br /&gt;
This was done as part of MDL-21261&lt;br /&gt;
&lt;br /&gt;
=== Removal of &#039;auto create users&#039; configuration option ===&lt;br /&gt;
&lt;br /&gt;
Under the configuration screen for the MNET authentication plugin, there was previously a setting called &#039;auto add remote users&#039;.  As far as I can understand, there was never a case where this should have been off, so it has been removed now.&lt;br /&gt;
&lt;br /&gt;
See the following forum post:  http://moodle.org/mod/forum/discuss.php?d=141491 and the bug: MDL-21327&lt;br /&gt;
&lt;br /&gt;
=== Reworked MNET administration screens ===&lt;br /&gt;
&lt;br /&gt;
Most of admin/mnet has been updated to use Moodle Forms and the new Output API.  This should not result in functional changes, but there may be some smaller aesthetic ones.  Not all screens have been rewritten yet.&lt;br /&gt;
&lt;br /&gt;
The relevant bug is MDL-21256&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68629</id>
		<title>Development:MNET 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68629"/>
		<updated>2010-02-16T04:22:18Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Administrative changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page attempts to summarise the changes in MNET between Moodle 1.9 and Moodle 2.0, both from an administrative perspective, and a code perspective.&lt;br /&gt;
&lt;br /&gt;
There are still things to do before 2.0 is released, so this page is a work in progress.&lt;br /&gt;
&lt;br /&gt;
== Backwards Compatibility Breaks ==&lt;br /&gt;
&lt;br /&gt;
=== Plugins registering MNET services ===&lt;br /&gt;
&lt;br /&gt;
It used to be that the plugins that needed to export mnet services used a mnet_publishes() method on the class (static or not).  This led to a list of hard coded plugins that supported it, and in some cases auth factory involvement, just to get a list of the RPC functions available.&lt;br /&gt;
&lt;br /&gt;
This has now changed to a file containing an array, in db/mnet.php, similar to lib/db/services.php.  This file looks something like this (example from the Mahara portfolio plugin):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$publishes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;apiversion&#039; =&amp;gt; 1,&lt;br /&gt;
        &#039;classname&#039;  =&amp;gt; &#039;portfolio_plugin_mahara&#039;,&lt;br /&gt;
        &#039;filename&#039;   =&amp;gt; &#039;lib.php&#039;,&lt;br /&gt;
        &#039;methods&#039;    =&amp;gt; array(&lt;br /&gt;
            &#039;fetch_file&#039;&lt;br /&gt;
        ),&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
$subscribes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;send_content_intent&#039; =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_intent&#039;,&lt;br /&gt;
        &#039;send_content_ready&#039;  =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_ready&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that there is a unsymmetricality between the methods that are published and the methods that are subscribed to.  &#039;&#039;&#039;This is new&#039;&#039;&#039; .&lt;br /&gt;
&lt;br /&gt;
This also resulted in two new tables. The old tables, mnet_rpc and mnet_service2rpc relate to the methods that are being published. The new tables, mnet_remote_rpc and mnet_remote_service2rpc relate to the methods that are being subscribed to.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
* MDL-16269&lt;br /&gt;
* MDL-16277&lt;br /&gt;
&lt;br /&gt;
=== Method signatures ===&lt;br /&gt;
&lt;br /&gt;
The method signature code used to use a string tokeniser to parse the php files that contained mnet services and store information about them in the database.  This was unreliable and slow.  We&#039;ve switched to using php5&#039;s reflection utilities, which gives us &#039;&#039;&#039;some&#039;&#039;&#039; information about the code, and the Zend_Server Reflection to get the rest.  This uses the native php5 reflection, as well as parsing the phpdoc blocks to find information about the types of function arguments, and the return values.&lt;br /&gt;
&lt;br /&gt;
Because of this, we can now reliably include both argument types and return value information in the method signature, where previously only arguments had been included (and in the case of no arguments, the return value had previously been erroneously used).&lt;br /&gt;
&lt;br /&gt;
This means that before where the method signature looked like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    array(&lt;br /&gt;
        /* ... */&lt;br /&gt;
    ),&lt;br /&gt;
    /* ... */&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
it now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;parameters&#039; =&amp;gt;  array(&lt;br /&gt;
        array(&lt;br /&gt;
            &#039;name&#039; =&amp;gt; &#039;token&#039;,&lt;br /&gt;
            &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
            &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
        ),&lt;br /&gt;
        array(&lt;br /&gt;
            /* ... */&lt;br /&gt;
        ),&lt;br /&gt;
        /* ... */,&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;return&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which, although it is unarguably more informative and clearer, is a backwards compatibility break.  This information is what is sent as the response to the system/methodSignature xmlrpc method.  The only place this is used &#039;&#039;&#039;within Moodle&#039;&#039;&#039;, however, is in the old testclient.php, which was present in code, but not linked to from anywhere.  This has been changed and is covered under Administrative changes.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this: &lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
&lt;br /&gt;
== Other code changes ==&lt;br /&gt;
&lt;br /&gt;
== Administrative changes ==&lt;br /&gt;
&lt;br /&gt;
=== New Networking Test Client ===&lt;br /&gt;
&lt;br /&gt;
=== Removal of &#039;auto create users&#039; configuration option ===&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Developmnet:MNET_2.0&amp;diff=68628</id>
		<title>Developmnet:MNET 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Developmnet:MNET_2.0&amp;diff=68628"/>
		<updated>2010-02-16T04:21:03Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: Developmnet:MNET 2.0 moved to Development:MNET 2.0&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Development:MNET 2.0]]&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68627</id>
		<title>Development:MNET 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68627"/>
		<updated>2010-02-16T04:21:03Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: Developmnet:MNET 2.0 moved to Development:MNET 2.0&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page attempts to summarise the changes in MNET between Moodle 1.9 and Moodle 2.0, both from an administrative perspective, and a code perspective.&lt;br /&gt;
&lt;br /&gt;
There are still things to do before 2.0 is released, so this page is a work in progress.&lt;br /&gt;
&lt;br /&gt;
== Backwards Compatibility Breaks ==&lt;br /&gt;
&lt;br /&gt;
=== Plugins registering MNET services ===&lt;br /&gt;
&lt;br /&gt;
It used to be that the plugins that needed to export mnet services used a mnet_publishes() method on the class (static or not).  This led to a list of hard coded plugins that supported it, and in some cases auth factory involvement, just to get a list of the RPC functions available.&lt;br /&gt;
&lt;br /&gt;
This has now changed to a file containing an array, in db/mnet.php, similar to lib/db/services.php.  This file looks something like this (example from the Mahara portfolio plugin):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$publishes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;apiversion&#039; =&amp;gt; 1,&lt;br /&gt;
        &#039;classname&#039;  =&amp;gt; &#039;portfolio_plugin_mahara&#039;,&lt;br /&gt;
        &#039;filename&#039;   =&amp;gt; &#039;lib.php&#039;,&lt;br /&gt;
        &#039;methods&#039;    =&amp;gt; array(&lt;br /&gt;
            &#039;fetch_file&#039;&lt;br /&gt;
        ),&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
$subscribes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;send_content_intent&#039; =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_intent&#039;,&lt;br /&gt;
        &#039;send_content_ready&#039;  =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_ready&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that there is a unsymmetricality between the methods that are published and the methods that are subscribed to.  &#039;&#039;&#039;This is new&#039;&#039;&#039; .&lt;br /&gt;
&lt;br /&gt;
This also resulted in two new tables. The old tables, mnet_rpc and mnet_service2rpc relate to the methods that are being published. The new tables, mnet_remote_rpc and mnet_remote_service2rpc relate to the methods that are being subscribed to.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
* MDL-16269&lt;br /&gt;
* MDL-16277&lt;br /&gt;
&lt;br /&gt;
=== Method signatures ===&lt;br /&gt;
&lt;br /&gt;
The method signature code used to use a string tokeniser to parse the php files that contained mnet services and store information about them in the database.  This was unreliable and slow.  We&#039;ve switched to using php5&#039;s reflection utilities, which gives us &#039;&#039;&#039;some&#039;&#039;&#039; information about the code, and the Zend_Server Reflection to get the rest.  This uses the native php5 reflection, as well as parsing the phpdoc blocks to find information about the types of function arguments, and the return values.&lt;br /&gt;
&lt;br /&gt;
Because of this, we can now reliably include both argument types and return value information in the method signature, where previously only arguments had been included (and in the case of no arguments, the return value had previously been erroneously used).&lt;br /&gt;
&lt;br /&gt;
This means that before where the method signature looked like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    array(&lt;br /&gt;
        /* ... */&lt;br /&gt;
    ),&lt;br /&gt;
    /* ... */&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
it now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;parameters&#039; =&amp;gt;  array(&lt;br /&gt;
        array(&lt;br /&gt;
            &#039;name&#039; =&amp;gt; &#039;token&#039;,&lt;br /&gt;
            &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
            &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
        ),&lt;br /&gt;
        array(&lt;br /&gt;
            /* ... */&lt;br /&gt;
        ),&lt;br /&gt;
        /* ... */,&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;return&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which, although it is unarguably more informative and clearer, is a backwards compatibility break.  This information is what is sent as the response to the system/methodSignature xmlrpc method.  The only place this is used &#039;&#039;&#039;within Moodle&#039;&#039;&#039;, however, is in the old testclient.php, which was present in code, but not linked to from anywhere.  This has been changed and is covered under Administrative changes.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this: &lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
&lt;br /&gt;
== Other code changes ==&lt;br /&gt;
&lt;br /&gt;
== Administrative changes ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68626</id>
		<title>Development:MNET 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68626"/>
		<updated>2010-02-16T03:53:23Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Method signatures */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page attempts to summarise the changes in MNET between Moodle 1.9 and Moodle 2.0, both from an administrative perspective, and a code perspective.&lt;br /&gt;
&lt;br /&gt;
There are still things to do before 2.0 is released, so this page is a work in progress.&lt;br /&gt;
&lt;br /&gt;
== Backwards Compatibility Breaks ==&lt;br /&gt;
&lt;br /&gt;
=== Plugins registering MNET services ===&lt;br /&gt;
&lt;br /&gt;
It used to be that the plugins that needed to export mnet services used a mnet_publishes() method on the class (static or not).  This led to a list of hard coded plugins that supported it, and in some cases auth factory involvement, just to get a list of the RPC functions available.&lt;br /&gt;
&lt;br /&gt;
This has now changed to a file containing an array, in db/mnet.php, similar to lib/db/services.php.  This file looks something like this (example from the Mahara portfolio plugin):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$publishes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;apiversion&#039; =&amp;gt; 1,&lt;br /&gt;
        &#039;classname&#039;  =&amp;gt; &#039;portfolio_plugin_mahara&#039;,&lt;br /&gt;
        &#039;filename&#039;   =&amp;gt; &#039;lib.php&#039;,&lt;br /&gt;
        &#039;methods&#039;    =&amp;gt; array(&lt;br /&gt;
            &#039;fetch_file&#039;&lt;br /&gt;
        ),&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
$subscribes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;send_content_intent&#039; =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_intent&#039;,&lt;br /&gt;
        &#039;send_content_ready&#039;  =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_ready&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that there is a unsymmetricality between the methods that are published and the methods that are subscribed to.  &#039;&#039;&#039;This is new&#039;&#039;&#039; .&lt;br /&gt;
&lt;br /&gt;
This also resulted in two new tables. The old tables, mnet_rpc and mnet_service2rpc relate to the methods that are being published. The new tables, mnet_remote_rpc and mnet_remote_service2rpc relate to the methods that are being subscribed to.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
* MDL-16269&lt;br /&gt;
* MDL-16277&lt;br /&gt;
&lt;br /&gt;
=== Method signatures ===&lt;br /&gt;
&lt;br /&gt;
The method signature code used to use a string tokeniser to parse the php files that contained mnet services and store information about them in the database.  This was unreliable and slow.  We&#039;ve switched to using php5&#039;s reflection utilities, which gives us &#039;&#039;&#039;some&#039;&#039;&#039; information about the code, and the Zend_Server Reflection to get the rest.  This uses the native php5 reflection, as well as parsing the phpdoc blocks to find information about the types of function arguments, and the return values.&lt;br /&gt;
&lt;br /&gt;
Because of this, we can now reliably include both argument types and return value information in the method signature, where previously only arguments had been included (and in the case of no arguments, the return value had previously been erroneously used).&lt;br /&gt;
&lt;br /&gt;
This means that before where the method signature looked like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    array(&lt;br /&gt;
        /* ... */&lt;br /&gt;
    ),&lt;br /&gt;
    /* ... */&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
it now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;parameters&#039; =&amp;gt;  array(&lt;br /&gt;
        array(&lt;br /&gt;
            &#039;name&#039; =&amp;gt; &#039;token&#039;,&lt;br /&gt;
            &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
            &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
        ),&lt;br /&gt;
        array(&lt;br /&gt;
            /* ... */&lt;br /&gt;
        ),&lt;br /&gt;
        /* ... */,&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;return&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which, although it is unarguably more informative and clearer, is a backwards compatibility break.  This information is what is sent as the response to the system/methodSignature xmlrpc method.  The only place this is used &#039;&#039;&#039;within Moodle&#039;&#039;&#039;, however, is in the old testclient.php, which was present in code, but not linked to from anywhere.  This has been changed and is covered under Administrative changes.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this: &lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
&lt;br /&gt;
== Other code changes ==&lt;br /&gt;
&lt;br /&gt;
== Administrative changes ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68624</id>
		<title>Development:MNET 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68624"/>
		<updated>2010-02-16T03:47:36Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Plugins registering MNET services */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page attempts to summarise the changes in MNET between Moodle 1.9 and Moodle 2.0, both from an administrative perspective, and a code perspective.&lt;br /&gt;
&lt;br /&gt;
There are still things to do before 2.0 is released, so this page is a work in progress.&lt;br /&gt;
&lt;br /&gt;
== Backwards Compatibility Breaks ==&lt;br /&gt;
&lt;br /&gt;
=== Plugins registering MNET services ===&lt;br /&gt;
&lt;br /&gt;
It used to be that the plugins that needed to export mnet services used a mnet_publishes() method on the class (static or not).  This led to a list of hard coded plugins that supported it, and in some cases auth factory involvement, just to get a list of the RPC functions available.&lt;br /&gt;
&lt;br /&gt;
This has now changed to a file containing an array, in db/mnet.php, similar to lib/db/services.php.  This file looks something like this (example from the Mahara portfolio plugin):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$publishes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;apiversion&#039; =&amp;gt; 1,&lt;br /&gt;
        &#039;classname&#039;  =&amp;gt; &#039;portfolio_plugin_mahara&#039;,&lt;br /&gt;
        &#039;filename&#039;   =&amp;gt; &#039;lib.php&#039;,&lt;br /&gt;
        &#039;methods&#039;    =&amp;gt; array(&lt;br /&gt;
            &#039;fetch_file&#039;&lt;br /&gt;
        ),&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
$subscribes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;send_content_intent&#039; =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_intent&#039;,&lt;br /&gt;
        &#039;send_content_ready&#039;  =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_ready&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that there is a unsymmetricality between the methods that are published and the methods that are subscribed to.  &#039;&#039;&#039;This is new&#039;&#039;&#039; .&lt;br /&gt;
&lt;br /&gt;
This also resulted in two new tables. The old tables, mnet_rpc and mnet_service2rpc relate to the methods that are being published. The new tables, mnet_remote_rpc and mnet_remote_service2rpc relate to the methods that are being subscribed to.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
* MDL-16269&lt;br /&gt;
* MDL-16277&lt;br /&gt;
&lt;br /&gt;
=== Method signatures ===&lt;br /&gt;
&lt;br /&gt;
The method signature code used to use a string tokeniser to parse the php files that contained mnet services and store information about them in the database.  This was unreliable and slow.  We&#039;ve switched to using php5&#039;s reflection utilities, which gives us &#039;&#039;&#039;some&#039;&#039;&#039; information about the code, and the Zend_Server Reflection to get the rest.  This uses the native php5 reflection, as well as parsing the phpdoc blocks to find information about the types of function arguments, and the return values.&lt;br /&gt;
&lt;br /&gt;
Because of this, we can now reliably include both argument types and return value information in the method signature, where previously only arguments had been included (and in the case of no arguments, the return value had previously been erroneously used).&lt;br /&gt;
&lt;br /&gt;
This means that before where the method signature looked like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    array(&lt;br /&gt;
        /* ... */&lt;br /&gt;
    ),&lt;br /&gt;
    /* ... */&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
it now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;parameters&#039; =&amp;gt;  array(&lt;br /&gt;
        array(&lt;br /&gt;
            &#039;name&#039; =&amp;gt; &#039;token&#039;,&lt;br /&gt;
            &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
            &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
        ),&lt;br /&gt;
        array(&lt;br /&gt;
            /* ... */&lt;br /&gt;
        ),&lt;br /&gt;
        /* ... */,&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;return&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which, although it is unarguably more informative and clearer, is a backwards compatibility break.  This information is what is sent as the response to the system/methodSignature xmlrpc method.  The only place this is used &#039;&#039;&#039;within Moodle&#039;&#039;&#039;, however, is in the old testclient.php, which was present in code, but not linked to from anywhere.  This has been changed and is covered under Administrative changes.&lt;br /&gt;
&lt;br /&gt;
== Other code changes ==&lt;br /&gt;
&lt;br /&gt;
== Administrative changes ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68623</id>
		<title>Development:MNET 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68623"/>
		<updated>2010-02-16T03:47:06Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page attempts to summarise the changes in MNET between Moodle 1.9 and Moodle 2.0, both from an administrative perspective, and a code perspective.&lt;br /&gt;
&lt;br /&gt;
There are still things to do before 2.0 is released, so this page is a work in progress.&lt;br /&gt;
&lt;br /&gt;
== Backwards Compatibility Breaks ==&lt;br /&gt;
&lt;br /&gt;
=== Plugins registering MNET services ===&lt;br /&gt;
&lt;br /&gt;
It used to be that the plugins that needed to export mnet services used a mnet_publishes() method on the class (static or not).  This led to a list of hard coded plugins that supported it, and in some cases auth factory involvement, just to get a list of the RPC functions available.&lt;br /&gt;
&lt;br /&gt;
This has now changed to a file containing an array, in db/mnet.php, similar to lib/db/services.php.  This file looks something like this (example from the Mahara portfolio plugin):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$publishes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;apiversion&#039; =&amp;gt; 1,&lt;br /&gt;
        &#039;classname&#039;  =&amp;gt; &#039;portfolio_plugin_mahara&#039;,&lt;br /&gt;
        &#039;filename&#039;   =&amp;gt; &#039;lib.php&#039;,&lt;br /&gt;
        &#039;methods&#039;    =&amp;gt; array(&lt;br /&gt;
            &#039;fetch_file&#039;&lt;br /&gt;
        ),&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
$subscribes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;send_content_intent&#039; =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_intent&#039;,&lt;br /&gt;
        &#039;send_content_ready&#039;  =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_ready&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that there is a unsymmetricality between the methods that are published and the methods that are subscribed to.  &#039;&#039;&#039;This is new&#039;&#039;&#039; .&lt;br /&gt;
&lt;br /&gt;
This also resulted in two new tables. The old tables, mnet_rpc and mnet_service2rpc relate to the methods that are being published. The new tables, mnet_remote_rpc and mnet_remote_service2rpc relate to the methods that are being subscribed to.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
* MDL-16269&lt;br /&gt;
* MDL-16277&lt;br /&gt;
&lt;br /&gt;
=== Method signatures ===&lt;br /&gt;
&lt;br /&gt;
The method signature code used to use a string tokeniser to parse the php files that contained mnet services and store information about them in the database.  This was unreliable and slow.  We&#039;ve switched to using php5&#039;s reflection utilities, which gives us &#039;&#039;&#039;some&#039;&#039;&#039; information about the code, and the Zend_Server Reflection to get the rest.  This uses the native php5 reflection, as well as parsing the phpdoc blocks to find information about the types of function arguments, and the return values.&lt;br /&gt;
&lt;br /&gt;
Because of this, we can now reliably include both argument types and return value information in the method signature, where previously only arguments had been included (and in the case of no arguments, the return value had previously been erroneously used).&lt;br /&gt;
&lt;br /&gt;
This means that before where the method signature looked like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    array(&lt;br /&gt;
        /* ... */&lt;br /&gt;
    ),&lt;br /&gt;
    /* ... */&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
it now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;parameters&#039; =&amp;gt;  array(&lt;br /&gt;
        array(&lt;br /&gt;
            &#039;name&#039; =&amp;gt; &#039;token&#039;,&lt;br /&gt;
            &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
            &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
        ),&lt;br /&gt;
        array(&lt;br /&gt;
            /* ... */&lt;br /&gt;
        ),&lt;br /&gt;
        /* ... */,&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;return&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;string&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;something here&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which, although it is unarguably more informative and clearer, is a backwards compatibility break.  This information is what is sent as the response to the system/methodSignature xmlrpc method.  The only place this is used &#039;&#039;&#039;within Moodle&#039;&#039;&#039;, however, is in the old testclient.php, which was present in code, but not linked to from anywhere.  This has been changed and is covered under Administrative changes.&lt;br /&gt;
&lt;br /&gt;
== Other code changes ==&lt;br /&gt;
&lt;br /&gt;
== Administrative changes ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68621</id>
		<title>Development:MNET 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68621"/>
		<updated>2010-02-16T03:37:05Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page attempts to summarise the changes in MNET between Moodle 1.9 and Moodle 2.0, both from an administrative perspective, and a code perspective.&lt;br /&gt;
&lt;br /&gt;
There are still things to do before 2.0 is released, so this page is a work in progress.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Backwards Compatibility Breaks ==&lt;br /&gt;
&lt;br /&gt;
=== Plugins registering MNET services ===&lt;br /&gt;
&lt;br /&gt;
It used to be that the plugins that needed to export mnet services used a mnet_publishes() method on the class (static or not).  This led to a list of hard coded plugins that supported it, and in some cases auth factory involvement, just to get a list of the RPC functions available.&lt;br /&gt;
&lt;br /&gt;
This has now changed to a file containing an array, in db/mnet.php, similar to lib/db/services.php.  This file looks something like this (example from the Mahara portfolio plugin):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$publishes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;apiversion&#039; =&amp;gt; 1,&lt;br /&gt;
        &#039;classname&#039;  =&amp;gt; &#039;portfolio_plugin_mahara&#039;,&lt;br /&gt;
        &#039;filename&#039;   =&amp;gt; &#039;lib.php&#039;,&lt;br /&gt;
        &#039;methods&#039;    =&amp;gt; array(&lt;br /&gt;
            &#039;fetch_file&#039;&lt;br /&gt;
        ),&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
$subscribes = array(&lt;br /&gt;
    &#039;pf&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;send_content_intent&#039; =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_intent&#039;,&lt;br /&gt;
        &#039;send_content_ready&#039;  =&amp;gt; &#039;portfolio/mahara/lib.php/send_content_ready&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that there is a unsymmetricality between the methods that are published and the methods that are subscribed to.  &#039;&#039;&#039;This is new&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
See the following bugs about this:&lt;br /&gt;
&lt;br /&gt;
* MDL-21261&lt;br /&gt;
* MDL-16269&lt;br /&gt;
* MDL-16277&lt;br /&gt;
&lt;br /&gt;
=== Method signatures ===&lt;br /&gt;
&lt;br /&gt;
== Other code changes ==&lt;br /&gt;
&lt;br /&gt;
== Administrative changes ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68620</id>
		<title>Development:MNET 2.0</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNET_2.0&amp;diff=68620"/>
		<updated>2010-02-16T03:24:24Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: New page: == Introduction ==  This page attempts to summarise the changes in MNET between Moodle 1.9 and Moodle 2.0, both from an administrative perspective, and a code perspective.  There are still...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page attempts to summarise the changes in MNET between Moodle 1.9 and Moodle 2.0, both from an administrative perspective, and a code perspective.&lt;br /&gt;
&lt;br /&gt;
There are still things to do before 2.0 is released, so this page is a work in progress.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Backwards Compatibility Breaks ==&lt;br /&gt;
&lt;br /&gt;
== Other code changes ==&lt;br /&gt;
&lt;br /&gt;
== Administrative changes ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67741</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67741"/>
		<updated>2010-01-27T00:49:23Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* 708, &amp;quot;nosuchclass&amp;quot; = */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
=== 7014, &amp;quot;nosuchmethod&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that a class method has been requested, a new object has been constructed, but then the method cannot be called on the object.&lt;br /&gt;
&lt;br /&gt;
Note that 7014 is also purportedly triggered with a &amp;quot;nosuchfunction&amp;quot; message in mnet_server_invoke_method, but it is in a non-executable piece of code.&lt;br /&gt;
&lt;br /&gt;
=== 7015, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that the class doesn&#039;t export a list of published mnet methods, in either the case of the requested method being static, or not.&lt;br /&gt;
&lt;br /&gt;
=== 7000, &amp;quot;unknownerror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
For some reason the xmlrpc request cannot be processed. Generic failure message.&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== 7018, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request was for a system method (eg &amp;quot;listMethods&amp;quot;, etc), but it wasn&#039;t in the list of allowed systemcalls.  The complete list of system calls are:&lt;br /&gt;
&lt;br /&gt;
* listMethods&lt;br /&gt;
* methodSignature&lt;br /&gt;
* methodHelp&lt;br /&gt;
* listServices&lt;br /&gt;
* listFiles&lt;br /&gt;
* retrieveFile&lt;br /&gt;
* keyswap&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is the generic error code for the inability to find a function.&lt;br /&gt;
&lt;br /&gt;
=== 7019, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in mnet_system() if a system method has been called, but it&#039;s not listMethods, methodSignature, methodHelp, or listServices.  It looks as though listFiles or retrieveFile are not implemented, even though they are registered to mnet_system in the mnet_server_dispatch() function.&lt;br /&gt;
&lt;br /&gt;
This is also triggered if mnet_permit_rpc_call returns a non-zero error code that hasn&#039;t already been trapped by one of the RPC_ constants defined in mnet/lib.php (which have their own error codes)&lt;br /&gt;
&lt;br /&gt;
=== 705, &amp;quot;nosuchfile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the file requested cannot be found (eg auth/mnet/lib.php instead of auth/mnet/auth.php)&lt;br /&gt;
&lt;br /&gt;
=== 706, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request is for a function (rather than a static method or class method), and it cannot be called (eg function_exists fails)&lt;br /&gt;
&lt;br /&gt;
=== 707, &amp;quot;forbidden-function&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This happens when the function is found, but not allowed (either not published to this host, or disabled)&lt;br /&gt;
&lt;br /&gt;
=== 708, &amp;quot;nosuchclass&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This happens when the class couldn&#039;t be found - probably would only happen if someone hacked code, as the mnet function installer checks this before putting rpc methods in the database.&lt;br /&gt;
&lt;br /&gt;
=== 709, &amp;quot;classerror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This happens when the class is found, but cannot be constructed - an error was thrown.&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
=== 702, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an authentication method, but the authentication plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 7013, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a class or static method has been requested, but the class could not be founded (eg class_exists fails).  The error message should be renamed in this case.&lt;br /&gt;
&lt;br /&gt;
=== 1, &amp;quot;authfail_nosessionexists&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there&#039;s no record in the mnet_session table for the given token and useragent.&lt;br /&gt;
&lt;br /&gt;
=== 2, &amp;quot;authfail_sessiontimedout&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there is a session, but confirmation has already timed out&lt;br /&gt;
&lt;br /&gt;
=== 3, &amp;quot;authfail_usermismatch&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Moodle can&#039;t find the user that the mnet session has been set up for. This is a weird error, but could possibly happen if the user was deleted between the mnet session being created, and confirmed.&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
=== 703, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an enrolment method, but the enrolment plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 5011, &amp;quot;couldnotcreateuser&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the user doesn&#039;t exist and an error happens trying to create their record&lt;br /&gt;
&lt;br /&gt;
=== 5012, &amp;quot;coursenotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the course doesn&#039;t exist&lt;br /&gt;
&lt;br /&gt;
=== 5013, &amp;quot;courseunavailable&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the course isn&#039;t in the whitelist of available courses&lt;br /&gt;
&lt;br /&gt;
=== 5014, &amp;quot;usernotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be unenrolled from a course, but the user isn&#039;t found&lt;br /&gt;
&lt;br /&gt;
=== 5015, &amp;quot;couldnotunenrol&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if role_unassign fails&lt;br /&gt;
&lt;br /&gt;
=== 5016, &amp;quot;couldnotenrol&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if enrol_into_course fails&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a portfolio plugin. This should be changed to check that the portfolio plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 8009, &amp;quot;mnet_notoken&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a portfolio file from Moodle and Moodle can&#039;t find a token in the transfer queue.&lt;br /&gt;
&lt;br /&gt;
=== 8010, &amp;quot;mnet_noid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, the queue record is found, but the transfer information cannot be rewoken (which can happen if permissions have changed or settings have changed in the meantime, or the transfer is expired)&lt;br /&gt;
&lt;br /&gt;
=== 8011, &amp;quot;mnet_wronghost&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is trigered if the xmlrpc request comes from a different host than the queue record has been saved against&lt;br /&gt;
&lt;br /&gt;
=== 8012, &amp;quot;mnet_nofile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, and Moodle can&#039;t find it&lt;br /&gt;
&lt;br /&gt;
=== 8013, &amp;quot;mnet_nofilecontents&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, Moodle portfolio records know which file to send, but the Files API throws an exception, or the file is empty.&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a repository plugin. This should be changed to check that the repository plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 9012, &amp;quot;usernotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the local user is not registered in the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
=== 9013, &amp;quot;usercannotaccess&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the local user cannot access to this file on the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
=== 9014, &amp;quot;failtoretrievelist&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when no file list could be retrieved from the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Dangerous mode&amp;quot; errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when $CFG-&amp;gt;mnet_dispatcher_mode has been set to &amp;quot;dangerous&amp;quot;, and the request is for something other than a file that ends in &#039;.php&#039;, or the request comes from a client that isn&#039;t a trusted host&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67740</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67740"/>
		<updated>2010-01-27T00:44:27Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Dispatch errors */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
=== 7014, &amp;quot;nosuchmethod&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that a class method has been requested, a new object has been constructed, but then the method cannot be called on the object.&lt;br /&gt;
&lt;br /&gt;
Note that 7014 is also purportedly triggered with a &amp;quot;nosuchfunction&amp;quot; message in mnet_server_invoke_method, but it is in a non-executable piece of code.&lt;br /&gt;
&lt;br /&gt;
=== 7015, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that the class doesn&#039;t export a list of published mnet methods, in either the case of the requested method being static, or not.&lt;br /&gt;
&lt;br /&gt;
=== 7000, &amp;quot;unknownerror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
For some reason the xmlrpc request cannot be processed. Generic failure message.&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== 7018, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request was for a system method (eg &amp;quot;listMethods&amp;quot;, etc), but it wasn&#039;t in the list of allowed systemcalls.  The complete list of system calls are:&lt;br /&gt;
&lt;br /&gt;
* listMethods&lt;br /&gt;
* methodSignature&lt;br /&gt;
* methodHelp&lt;br /&gt;
* listServices&lt;br /&gt;
* listFiles&lt;br /&gt;
* retrieveFile&lt;br /&gt;
* keyswap&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is the generic error code for the inability to find a function.&lt;br /&gt;
&lt;br /&gt;
=== 7019, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in mnet_system() if a system method has been called, but it&#039;s not listMethods, methodSignature, methodHelp, or listServices.  It looks as though listFiles or retrieveFile are not implemented, even though they are registered to mnet_system in the mnet_server_dispatch() function.&lt;br /&gt;
&lt;br /&gt;
This is also triggered if mnet_permit_rpc_call returns a non-zero error code that hasn&#039;t already been trapped by one of the RPC_ constants defined in mnet/lib.php (which have their own error codes)&lt;br /&gt;
&lt;br /&gt;
=== 705, &amp;quot;nosuchfile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the file requested cannot be found (eg auth/mnet/lib.php instead of auth/mnet/auth.php)&lt;br /&gt;
&lt;br /&gt;
=== 706, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request is for a function (rather than a static method or class method), and it cannot be called (eg function_exists fails)&lt;br /&gt;
&lt;br /&gt;
=== 707, &amp;quot;forbidden-function&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This happens when the function is found, but not allowed (either not published to this host, or disabled)&lt;br /&gt;
&lt;br /&gt;
=== 708, &amp;quot;nosuchclass&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
This happens when the class couldn&#039;t be found - probably would only happen if someone hacked code, as the mnet function installer checks this before putting rpc methods in the database.&lt;br /&gt;
&lt;br /&gt;
=== 709, &amp;quot;classerror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This happens when the class is found, but cannot be constructed - an error was thrown.&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
=== 702, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an authentication method, but the authentication plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 7013, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a class or static method has been requested, but the class could not be founded (eg class_exists fails).  The error message should be renamed in this case.&lt;br /&gt;
&lt;br /&gt;
=== 1, &amp;quot;authfail_nosessionexists&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there&#039;s no record in the mnet_session table for the given token and useragent.&lt;br /&gt;
&lt;br /&gt;
=== 2, &amp;quot;authfail_sessiontimedout&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there is a session, but confirmation has already timed out&lt;br /&gt;
&lt;br /&gt;
=== 3, &amp;quot;authfail_usermismatch&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Moodle can&#039;t find the user that the mnet session has been set up for. This is a weird error, but could possibly happen if the user was deleted between the mnet session being created, and confirmed.&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
=== 703, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an enrolment method, but the enrolment plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 5011, &amp;quot;couldnotcreateuser&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the user doesn&#039;t exist and an error happens trying to create their record&lt;br /&gt;
&lt;br /&gt;
=== 5012, &amp;quot;coursenotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the course doesn&#039;t exist&lt;br /&gt;
&lt;br /&gt;
=== 5013, &amp;quot;courseunavailable&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the course isn&#039;t in the whitelist of available courses&lt;br /&gt;
&lt;br /&gt;
=== 5014, &amp;quot;usernotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be unenrolled from a course, but the user isn&#039;t found&lt;br /&gt;
&lt;br /&gt;
=== 5015, &amp;quot;couldnotunenrol&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if role_unassign fails&lt;br /&gt;
&lt;br /&gt;
=== 5016, &amp;quot;couldnotenrol&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if enrol_into_course fails&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a portfolio plugin. This should be changed to check that the portfolio plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 8009, &amp;quot;mnet_notoken&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a portfolio file from Moodle and Moodle can&#039;t find a token in the transfer queue.&lt;br /&gt;
&lt;br /&gt;
=== 8010, &amp;quot;mnet_noid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, the queue record is found, but the transfer information cannot be rewoken (which can happen if permissions have changed or settings have changed in the meantime, or the transfer is expired)&lt;br /&gt;
&lt;br /&gt;
=== 8011, &amp;quot;mnet_wronghost&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is trigered if the xmlrpc request comes from a different host than the queue record has been saved against&lt;br /&gt;
&lt;br /&gt;
=== 8012, &amp;quot;mnet_nofile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, and Moodle can&#039;t find it&lt;br /&gt;
&lt;br /&gt;
=== 8013, &amp;quot;mnet_nofilecontents&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, Moodle portfolio records know which file to send, but the Files API throws an exception, or the file is empty.&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a repository plugin. This should be changed to check that the repository plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 9012, &amp;quot;usernotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the local user is not registered in the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
=== 9013, &amp;quot;usercannotaccess&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the local user cannot access to this file on the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
=== 9014, &amp;quot;failtoretrievelist&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when no file list could be retrieved from the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Dangerous mode&amp;quot; errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when $CFG-&amp;gt;mnet_dispatcher_mode has been set to &amp;quot;dangerous&amp;quot;, and the request is for something other than a file that ends in &#039;.php&#039;, or the request comes from a client that isn&#039;t a trusted host&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67739</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67739"/>
		<updated>2010-01-27T00:32:21Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Dispatch errors */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
=== 7014, &amp;quot;nosuchmethod&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that a class method has been requested, a new object has been constructed, but then the method cannot be called on the object.&lt;br /&gt;
&lt;br /&gt;
Note that 7014 is also purportedly triggered with a &amp;quot;nosuchfunction&amp;quot; message in mnet_server_invoke_method, but it is in a non-executable piece of code.&lt;br /&gt;
&lt;br /&gt;
=== 7015, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that the class doesn&#039;t export a list of published mnet methods, in either the case of the requested method being static, or not.&lt;br /&gt;
&lt;br /&gt;
=== 7000, &amp;quot;unknownerror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
For some reason the xmlrpc request cannot be processed. Generic failure message.&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== 7018, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request was for a system method (eg &amp;quot;listMethods&amp;quot;, etc), but it wasn&#039;t in the list of allowed systemcalls.  The complete list of system calls are:&lt;br /&gt;
&lt;br /&gt;
* listMethods&lt;br /&gt;
* methodSignature&lt;br /&gt;
* methodHelp&lt;br /&gt;
* listServices&lt;br /&gt;
* listFiles&lt;br /&gt;
* retrieveFile&lt;br /&gt;
* keyswap&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is the generic error code for the inability to find a function.&lt;br /&gt;
&lt;br /&gt;
=== 7019, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in mnet_system() if a system method has been called, but it&#039;s not listMethods, methodSignature, methodHelp, or listServices.  It looks as though listFiles or retrieveFile are not implemented, even though they are registered to mnet_system in the mnet_server_dispatch() function.&lt;br /&gt;
&lt;br /&gt;
This is also triggered if mnet_permit_rpc_call returns a non-zero error code that hasn&#039;t already been trapped by one of the RPC_ constants defined in mnet/lib.php (which have their own error codes)&lt;br /&gt;
&lt;br /&gt;
=== 705, &amp;quot;nosuchfile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the file requested cannot be found (eg auth/mnet/lib.php instead of auth/mnet/auth.php)&lt;br /&gt;
&lt;br /&gt;
=== 706, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request is for a function (rather than a static method or class method), and it cannot be called (eg function_exists fails)&lt;br /&gt;
&lt;br /&gt;
=== 707, &amp;quot;forbidden-function&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This happens when the function is found, but not allowed (either not published to this host, or disabled)&lt;br /&gt;
&lt;br /&gt;
=== 708, &amp;quot;nosuchclass&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
This happens when the class couldn&#039;t be found - probably would only happen if someone hacked code, as the mnet function installer checks this before putting rpc methods in the database.&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
=== 702, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an authentication method, but the authentication plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 7013, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a class or static method has been requested, but the class could not be founded (eg class_exists fails).  The error message should be renamed in this case.&lt;br /&gt;
&lt;br /&gt;
=== 1, &amp;quot;authfail_nosessionexists&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there&#039;s no record in the mnet_session table for the given token and useragent.&lt;br /&gt;
&lt;br /&gt;
=== 2, &amp;quot;authfail_sessiontimedout&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there is a session, but confirmation has already timed out&lt;br /&gt;
&lt;br /&gt;
=== 3, &amp;quot;authfail_usermismatch&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Moodle can&#039;t find the user that the mnet session has been set up for. This is a weird error, but could possibly happen if the user was deleted between the mnet session being created, and confirmed.&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
=== 703, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an enrolment method, but the enrolment plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 5011, &amp;quot;couldnotcreateuser&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the user doesn&#039;t exist and an error happens trying to create their record&lt;br /&gt;
&lt;br /&gt;
=== 5012, &amp;quot;coursenotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the course doesn&#039;t exist&lt;br /&gt;
&lt;br /&gt;
=== 5013, &amp;quot;courseunavailable&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the course isn&#039;t in the whitelist of available courses&lt;br /&gt;
&lt;br /&gt;
=== 5014, &amp;quot;usernotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be unenrolled from a course, but the user isn&#039;t found&lt;br /&gt;
&lt;br /&gt;
=== 5015, &amp;quot;couldnotunenrol&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if role_unassign fails&lt;br /&gt;
&lt;br /&gt;
=== 5016, &amp;quot;couldnotenrol&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if enrol_into_course fails&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a portfolio plugin. This should be changed to check that the portfolio plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 8009, &amp;quot;mnet_notoken&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a portfolio file from Moodle and Moodle can&#039;t find a token in the transfer queue.&lt;br /&gt;
&lt;br /&gt;
=== 8010, &amp;quot;mnet_noid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, the queue record is found, but the transfer information cannot be rewoken (which can happen if permissions have changed or settings have changed in the meantime, or the transfer is expired)&lt;br /&gt;
&lt;br /&gt;
=== 8011, &amp;quot;mnet_wronghost&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is trigered if the xmlrpc request comes from a different host than the queue record has been saved against&lt;br /&gt;
&lt;br /&gt;
=== 8012, &amp;quot;mnet_nofile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, and Moodle can&#039;t find it&lt;br /&gt;
&lt;br /&gt;
=== 8013, &amp;quot;mnet_nofilecontents&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, Moodle portfolio records know which file to send, but the Files API throws an exception, or the file is empty.&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a repository plugin. This should be changed to check that the repository plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 9012, &amp;quot;usernotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the local user is not registered in the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
=== 9013, &amp;quot;usercannotaccess&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the local user cannot access to this file on the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
=== 9014, &amp;quot;failtoretrievelist&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when no file list could be retrieved from the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Dangerous mode&amp;quot; errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when $CFG-&amp;gt;mnet_dispatcher_mode has been set to &amp;quot;dangerous&amp;quot;, and the request is for something other than a file that ends in &#039;.php&#039;, or the request comes from a client that isn&#039;t a trusted host&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67735</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67735"/>
		<updated>2010-01-26T22:50:55Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* 707, &amp;quot;forbidden-function&amp;quot; */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
=== 7014, &amp;quot;nosuchmethod&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that a class method has been requested, a new object has been constructed, but then the method cannot be called on the object.&lt;br /&gt;
&lt;br /&gt;
Note that 7014 is also purportedly triggered with a &amp;quot;nosuchfunction&amp;quot; message in mnet_server_invoke_method, but it is in a non-executable piece of code.&lt;br /&gt;
&lt;br /&gt;
=== 7015, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that the class doesn&#039;t export a list of published mnet methods, in either the case of the requested method being static, or not.&lt;br /&gt;
&lt;br /&gt;
=== 7000, &amp;quot;unknownerror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
For some reason the xmlrpc request cannot be processed. Generic failure message.&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== 7018, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request was for a system method (eg &amp;quot;listMethods&amp;quot;, etc), but it wasn&#039;t in the list of allowed systemcalls.  The complete list of system calls are:&lt;br /&gt;
&lt;br /&gt;
* listMethods&lt;br /&gt;
* methodSignature&lt;br /&gt;
* methodHelp&lt;br /&gt;
* listServices&lt;br /&gt;
* listFiles&lt;br /&gt;
* retrieveFile&lt;br /&gt;
* keyswap&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is the generic error code for the inability to find a function.&lt;br /&gt;
&lt;br /&gt;
=== 7019, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in mnet_system() if a system method has been called, but it&#039;s not listMethods, methodSignature, methodHelp, or listServices.  It looks as though listFiles or retrieveFile are not implemented, even though they are registered to mnet_system in the mnet_server_dispatch() function.&lt;br /&gt;
&lt;br /&gt;
This is also triggered if mnet_permit_rpc_call returns a non-zero error code that hasn&#039;t already been trapped by one of the RPC_ constants defined in mnet/lib.php (which have their own error codes)&lt;br /&gt;
&lt;br /&gt;
=== 705, &amp;quot;nosuchfile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the file requested cannot be found (eg auth/mnet/lib.php instead of auth/mnet/auth.php)&lt;br /&gt;
&lt;br /&gt;
=== 706, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request is for a function (rather than a static method or class method), and it cannot be called (eg function_exists fails)&lt;br /&gt;
&lt;br /&gt;
=== 707, &amp;quot;forbidden-function&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This happens when the function is found, but not allowed (either not published to this host, or disabled)&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
=== 702, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an authentication method, but the authentication plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 7013, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a class or static method has been requested, but the class could not be founded (eg class_exists fails).  The error message should be renamed in this case.&lt;br /&gt;
&lt;br /&gt;
=== 1, &amp;quot;authfail_nosessionexists&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there&#039;s no record in the mnet_session table for the given token and useragent.&lt;br /&gt;
&lt;br /&gt;
=== 2, &amp;quot;authfail_sessiontimedout&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there is a session, but confirmation has already timed out&lt;br /&gt;
&lt;br /&gt;
=== 3, &amp;quot;authfail_usermismatch&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Moodle can&#039;t find the user that the mnet session has been set up for. This is a weird error, but could possibly happen if the user was deleted between the mnet session being created, and confirmed.&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
=== 703, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an enrolment method, but the enrolment plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 5011, &amp;quot;couldnotcreateuser&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the user doesn&#039;t exist and an error happens trying to create their record&lt;br /&gt;
&lt;br /&gt;
=== 5012, &amp;quot;coursenotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the course doesn&#039;t exist&lt;br /&gt;
&lt;br /&gt;
=== 5013, &amp;quot;courseunavailable&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the course isn&#039;t in the whitelist of available courses&lt;br /&gt;
&lt;br /&gt;
=== 5014, &amp;quot;usernotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be unenrolled from a course, but the user isn&#039;t found&lt;br /&gt;
&lt;br /&gt;
=== 5015, &amp;quot;couldnotunenrol&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if role_unassign fails&lt;br /&gt;
&lt;br /&gt;
=== 5016, &amp;quot;couldnotenrol&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if enrol_into_course fails&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a portfolio plugin. This should be changed to check that the portfolio plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 8009, &amp;quot;mnet_notoken&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a portfolio file from Moodle and Moodle can&#039;t find a token in the transfer queue.&lt;br /&gt;
&lt;br /&gt;
=== 8010, &amp;quot;mnet_noid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, the queue record is found, but the transfer information cannot be rewoken (which can happen if permissions have changed or settings have changed in the meantime, or the transfer is expired)&lt;br /&gt;
&lt;br /&gt;
=== 8011, &amp;quot;mnet_wronghost&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is trigered if the xmlrpc request comes from a different host than the queue record has been saved against&lt;br /&gt;
&lt;br /&gt;
=== 8012, &amp;quot;mnet_nofile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, and Moodle can&#039;t find it&lt;br /&gt;
&lt;br /&gt;
=== 8013, &amp;quot;mnet_nofilecontents&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, Moodle portfolio records know which file to send, but the Files API throws an exception, or the file is empty.&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a repository plugin. This should be changed to check that the repository plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 9012, &amp;quot;usernotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the local user is not registered in the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
=== 9013, &amp;quot;usercannotaccess&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the local user cannot access to this file on the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
=== 9014, &amp;quot;failtoretrievelist&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when no file list could be retrieved from the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Dangerous mode&amp;quot; errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when $CFG-&amp;gt;mnet_dispatcher_mode has been set to &amp;quot;dangerous&amp;quot;, and the request is for something other than a file that ends in &#039;.php&#039;, or the request comes from a client that isn&#039;t a trusted host&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67734</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67734"/>
		<updated>2010-01-26T21:59:50Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* System/Verification errors */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
=== 7014, &amp;quot;nosuchmethod&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that a class method has been requested, a new object has been constructed, but then the method cannot be called on the object.&lt;br /&gt;
&lt;br /&gt;
Note that 7014 is also purportedly triggered with a &amp;quot;nosuchfunction&amp;quot; message in mnet_server_invoke_method, but it is in a non-executable piece of code.&lt;br /&gt;
&lt;br /&gt;
=== 7015, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that the class doesn&#039;t export a list of published mnet methods, in either the case of the requested method being static, or not.&lt;br /&gt;
&lt;br /&gt;
=== 7000, &amp;quot;unknownerror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
For some reason the xmlrpc request cannot be processed. Generic failure message.&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== 7018, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request was for a system method (eg &amp;quot;listMethods&amp;quot;, etc), but it wasn&#039;t in the list of allowed systemcalls.  The complete list of system calls are:&lt;br /&gt;
&lt;br /&gt;
* listMethods&lt;br /&gt;
* methodSignature&lt;br /&gt;
* methodHelp&lt;br /&gt;
* listServices&lt;br /&gt;
* listFiles&lt;br /&gt;
* retrieveFile&lt;br /&gt;
* keyswap&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is the generic error code for the inability to find a function.&lt;br /&gt;
&lt;br /&gt;
=== 7019, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in mnet_system() if a system method has been called, but it&#039;s not listMethods, methodSignature, methodHelp, or listServices.  It looks as though listFiles or retrieveFile are not implemented, even though they are registered to mnet_system in the mnet_server_dispatch() function.&lt;br /&gt;
&lt;br /&gt;
This is also triggered if mnet_permit_rpc_call returns a non-zero error code that hasn&#039;t already been trapped by one of the RPC_ constants defined in mnet/lib.php (which have their own error codes)&lt;br /&gt;
&lt;br /&gt;
=== 705, &amp;quot;nosuchfile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the file requested cannot be found (eg auth/mnet/lib.php instead of auth/mnet/auth.php)&lt;br /&gt;
&lt;br /&gt;
=== 706, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request is for a function (rather than a static method or class method), and it cannot be called (eg function_exists fails)&lt;br /&gt;
&lt;br /&gt;
=== 707, &amp;quot;forbidden-function&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
There isn&#039;t any code that throws this error case&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
=== 702, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an authentication method, but the authentication plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 7013, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a class or static method has been requested, but the class could not be founded (eg class_exists fails).  The error message should be renamed in this case.&lt;br /&gt;
&lt;br /&gt;
=== 1, &amp;quot;authfail_nosessionexists&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there&#039;s no record in the mnet_session table for the given token and useragent.&lt;br /&gt;
&lt;br /&gt;
=== 2, &amp;quot;authfail_sessiontimedout&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there is a session, but confirmation has already timed out&lt;br /&gt;
&lt;br /&gt;
=== 3, &amp;quot;authfail_usermismatch&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Moodle can&#039;t find the user that the mnet session has been set up for. This is a weird error, but could possibly happen if the user was deleted between the mnet session being created, and confirmed.&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
=== 703, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an enrolment method, but the enrolment plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 5011, &amp;quot;couldnotcreateuser&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the user doesn&#039;t exist and an error happens trying to create their record&lt;br /&gt;
&lt;br /&gt;
=== 5012, &amp;quot;coursenotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the course doesn&#039;t exist&lt;br /&gt;
&lt;br /&gt;
=== 5013, &amp;quot;courseunavailable&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the course isn&#039;t in the whitelist of available courses&lt;br /&gt;
&lt;br /&gt;
=== 5014, &amp;quot;usernotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be unenrolled from a course, but the user isn&#039;t found&lt;br /&gt;
&lt;br /&gt;
=== 5015, &amp;quot;couldnotunenrol&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if role_unassign fails&lt;br /&gt;
&lt;br /&gt;
=== 5016, &amp;quot;couldnotenrol&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if enrol_into_course fails&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a portfolio plugin. This should be changed to check that the portfolio plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 8009, &amp;quot;mnet_notoken&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a portfolio file from Moodle and Moodle can&#039;t find a token in the transfer queue.&lt;br /&gt;
&lt;br /&gt;
=== 8010, &amp;quot;mnet_noid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, the queue record is found, but the transfer information cannot be rewoken (which can happen if permissions have changed or settings have changed in the meantime, or the transfer is expired)&lt;br /&gt;
&lt;br /&gt;
=== 8011, &amp;quot;mnet_wronghost&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is trigered if the xmlrpc request comes from a different host than the queue record has been saved against&lt;br /&gt;
&lt;br /&gt;
=== 8012, &amp;quot;mnet_nofile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, and Moodle can&#039;t find it&lt;br /&gt;
&lt;br /&gt;
=== 8013, &amp;quot;mnet_nofilecontents&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, Moodle portfolio records know which file to send, but the Files API throws an exception, or the file is empty.&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a repository plugin. This should be changed to check that the repository plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 9012, &amp;quot;usernotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the local user is not registered in the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
=== 9013, &amp;quot;usercannotaccess&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the local user cannot access to this file on the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
=== 9014, &amp;quot;failtoretrievelist&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when no file list could be retrieved from the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Dangerous mode&amp;quot; errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when $CFG-&amp;gt;mnet_dispatcher_mode has been set to &amp;quot;dangerous&amp;quot;, and the request is for something other than a file that ends in &#039;.php&#039;, or the request comes from a client that isn&#039;t a trusted host&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67172</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67172"/>
		<updated>2010-01-13T01:01:45Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Enrolment errors */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
=== 7014, &amp;quot;nosuchmethod&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that a class method has been requested, a new object has been constructed, but then the method cannot be called on the object.&lt;br /&gt;
&lt;br /&gt;
Note that 7014 is also purportedly triggered with a &amp;quot;nosuchfunction&amp;quot; message in mnet_server_invoke_method, but it is in a non-executable piece of code.&lt;br /&gt;
&lt;br /&gt;
=== 7015, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that the class doesn&#039;t export a list of published mnet methods, in either the case of the requested method being static, or not.&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== 7018, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request was for a system method (eg &amp;quot;listMethods&amp;quot;, etc), but it wasn&#039;t in the list of allowed systemcalls.  The complete list of system calls are:&lt;br /&gt;
&lt;br /&gt;
* listMethods&lt;br /&gt;
* methodSignature&lt;br /&gt;
* methodHelp&lt;br /&gt;
* listServices&lt;br /&gt;
* listFiles&lt;br /&gt;
* retrieveFile&lt;br /&gt;
* keyswap&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is the generic error code for the inability to find a function.&lt;br /&gt;
&lt;br /&gt;
=== 7019, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in mnet_system() if a system method has been called, but it&#039;s not listMethods, methodSignature, methodHelp, or listServices.  It looks as though listFiles or retrieveFile are not implemented, even though they are registered to mnet_system in the mnet_server_dispatch() function.&lt;br /&gt;
&lt;br /&gt;
This is also triggered if mnet_permit_rpc_call returns a non-zero error code that hasn&#039;t already been trapped by one of the RPC_ constants defined in mnet/lib.php (which have their own error codes)&lt;br /&gt;
&lt;br /&gt;
=== 705, &amp;quot;nosuchfile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the file requested cannot be found (eg auth/mnet/lib.php instead of auth/mnet/auth.php)&lt;br /&gt;
&lt;br /&gt;
=== 706, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request is for a function (rather than a static method or class method), and it cannot be called (eg function_exists fails)&lt;br /&gt;
&lt;br /&gt;
=== 707, &amp;quot;forbidden-function&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
There isn&#039;t any code that throws this error case&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
=== 702, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an authentication method, but the authentication plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 7013, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a class or static method has been requested, but the class could not be founded (eg class_exists fails).  The error message should be renamed in this case.&lt;br /&gt;
&lt;br /&gt;
=== 1, &amp;quot;authfail_nosessionexists&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there&#039;s no record in the mnet_session table for the given token and useragent.&lt;br /&gt;
&lt;br /&gt;
=== 2, &amp;quot;authfail_sessiontimedout&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there is a session, but confirmation has already timed out&lt;br /&gt;
&lt;br /&gt;
=== 3, &amp;quot;authfail_usermismatch&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Moodle can&#039;t find the user that the mnet session has been set up for. This is a weird error, but could possibly happen if the user was deleted between the mnet session being created, and confirmed.&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
=== 703, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an enrolment method, but the enrolment plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 5011, &amp;quot;couldnotcreateuser&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the user doesn&#039;t exist and an error happens trying to create their record&lt;br /&gt;
&lt;br /&gt;
=== 5012, &amp;quot;coursenotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the course doesn&#039;t exist&lt;br /&gt;
&lt;br /&gt;
=== 5013, &amp;quot;courseunavailable&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the course isn&#039;t in the whitelist of available courses&lt;br /&gt;
&lt;br /&gt;
=== 5014, &amp;quot;usernotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be unenrolled from a course, but the user isn&#039;t found&lt;br /&gt;
&lt;br /&gt;
=== 5015, &amp;quot;couldnotunenrol&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if role_unassign fails&lt;br /&gt;
&lt;br /&gt;
=== 5016, &amp;quot;couldnotenrol&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if enrol_into_course fails&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a portfolio plugin. This should be changed to check that the portfolio plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 8009, &amp;quot;mnet_notoken&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a portfolio file from Moodle and Moodle can&#039;t find a token in the transfer queue.&lt;br /&gt;
&lt;br /&gt;
=== 8010, &amp;quot;mnet_noid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, the queue record is found, but the transfer information cannot be rewoken (which can happen if permissions have changed or settings have changed in the meantime, or the transfer is expired)&lt;br /&gt;
&lt;br /&gt;
=== 8011, &amp;quot;mnet_wronghost&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is trigered if the xmlrpc request comes from a different host than the queue record has been saved against&lt;br /&gt;
&lt;br /&gt;
=== 8012, &amp;quot;mnet_nofile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, and Moodle can&#039;t find it&lt;br /&gt;
&lt;br /&gt;
=== 8013, &amp;quot;mnet_nofilecontents&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, Moodle portfolio records know which file to send, but the Files API throws an exception, or the file is empty.&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a repository plugin. This should be changed to check that the repository plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 9012, &amp;quot;usernotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the local user is not registered in the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
=== 9013, &amp;quot;usercannotaccess&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the local user cannot access to this file on the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
=== 9014, &amp;quot;failtoretrievelist&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when no file list could be retrieved from the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Dangerous mode&amp;quot; errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when $CFG-&amp;gt;mnet_dispatcher_mode has been set to &amp;quot;dangerous&amp;quot;, and the request is for something other than a file that ends in &#039;.php&#039;, or the request comes from a client that isn&#039;t a trusted host&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67171</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67171"/>
		<updated>2010-01-13T00:57:38Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Enrolment errors */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
=== 7014, &amp;quot;nosuchmethod&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that a class method has been requested, a new object has been constructed, but then the method cannot be called on the object.&lt;br /&gt;
&lt;br /&gt;
Note that 7014 is also purportedly triggered with a &amp;quot;nosuchfunction&amp;quot; message in mnet_server_invoke_method, but it is in a non-executable piece of code.&lt;br /&gt;
&lt;br /&gt;
=== 7015, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that the class doesn&#039;t export a list of published mnet methods, in either the case of the requested method being static, or not.&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== 7018, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request was for a system method (eg &amp;quot;listMethods&amp;quot;, etc), but it wasn&#039;t in the list of allowed systemcalls.  The complete list of system calls are:&lt;br /&gt;
&lt;br /&gt;
* listMethods&lt;br /&gt;
* methodSignature&lt;br /&gt;
* methodHelp&lt;br /&gt;
* listServices&lt;br /&gt;
* listFiles&lt;br /&gt;
* retrieveFile&lt;br /&gt;
* keyswap&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is the generic error code for the inability to find a function.&lt;br /&gt;
&lt;br /&gt;
=== 7019, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in mnet_system() if a system method has been called, but it&#039;s not listMethods, methodSignature, methodHelp, or listServices.  It looks as though listFiles or retrieveFile are not implemented, even though they are registered to mnet_system in the mnet_server_dispatch() function.&lt;br /&gt;
&lt;br /&gt;
This is also triggered if mnet_permit_rpc_call returns a non-zero error code that hasn&#039;t already been trapped by one of the RPC_ constants defined in mnet/lib.php (which have their own error codes)&lt;br /&gt;
&lt;br /&gt;
=== 705, &amp;quot;nosuchfile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the file requested cannot be found (eg auth/mnet/lib.php instead of auth/mnet/auth.php)&lt;br /&gt;
&lt;br /&gt;
=== 706, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request is for a function (rather than a static method or class method), and it cannot be called (eg function_exists fails)&lt;br /&gt;
&lt;br /&gt;
=== 707, &amp;quot;forbidden-function&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
There isn&#039;t any code that throws this error case&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
=== 702, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an authentication method, but the authentication plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 7013, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a class or static method has been requested, but the class could not be founded (eg class_exists fails).  The error message should be renamed in this case.&lt;br /&gt;
&lt;br /&gt;
=== 1, &amp;quot;authfail_nosessionexists&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there&#039;s no record in the mnet_session table for the given token and useragent.&lt;br /&gt;
&lt;br /&gt;
=== 2, &amp;quot;authfail_sessiontimedout&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there is a session, but confirmation has already timed out&lt;br /&gt;
&lt;br /&gt;
=== 3, &amp;quot;authfail_usermismatch&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Moodle can&#039;t find the user that the mnet session has been set up for. This is a weird error, but could possibly happen if the user was deleted between the mnet session being created, and confirmed.&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
=== 703, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an enrolment method, but the enrolment plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 5011, &amp;quot;couldnotcreateuser&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the user doesn&#039;t exist and an error happens trying to create their record&lt;br /&gt;
&lt;br /&gt;
=== 5012, &amp;quot;coursenotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the course doesn&#039;t exist&lt;br /&gt;
&lt;br /&gt;
=== 5013, &amp;quot;courseunavailable&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be enrolled in a course, but the course isn&#039;t in the whitelist of available courses&lt;br /&gt;
&lt;br /&gt;
=== 5014, &amp;quot;usernotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a user is requested to be unenrolled from a course, but the user isn&#039;t found&lt;br /&gt;
&lt;br /&gt;
=== 5015, &amp;quot;couldnotunenrol&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
This is triggered if role_unassign fails&lt;br /&gt;
&lt;br /&gt;
=== 5016, &amp;quot;couldnotenrol&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if enrol_into_course fails&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a portfolio plugin. This should be changed to check that the portfolio plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 8009, &amp;quot;mnet_notoken&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a portfolio file from Moodle and Moodle can&#039;t find a token in the transfer queue.&lt;br /&gt;
&lt;br /&gt;
=== 8010, &amp;quot;mnet_noid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, the queue record is found, but the transfer information cannot be rewoken (which can happen if permissions have changed or settings have changed in the meantime, or the transfer is expired)&lt;br /&gt;
&lt;br /&gt;
=== 8011, &amp;quot;mnet_wronghost&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is trigered if the xmlrpc request comes from a different host than the queue record has been saved against&lt;br /&gt;
&lt;br /&gt;
=== 8012, &amp;quot;mnet_nofile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, and Moodle can&#039;t find it&lt;br /&gt;
&lt;br /&gt;
=== 8013, &amp;quot;mnet_nofilecontents&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, Moodle portfolio records know which file to send, but the Files API throws an exception, or the file is empty.&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a repository plugin. This should be changed to check that the repository plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 9012, &amp;quot;usernotfound&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the local user is not registered in the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
=== 9013, &amp;quot;usercannotaccess&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the local user cannot access to this file on the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
=== 9014, &amp;quot;failtoretrievelist&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when no file list could be retrieved from the remote Moodle site.&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Dangerous mode&amp;quot; errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when $CFG-&amp;gt;mnet_dispatcher_mode has been set to &amp;quot;dangerous&amp;quot;, and the request is for something other than a file that ends in &#039;.php&#039;, or the request comes from a client that isn&#039;t a trusted host&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67124</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67124"/>
		<updated>2010-01-11T04:13:08Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
=== 7014, &amp;quot;nosuchmethod&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that a class method has been requested, a new object has been constructed, but then the method cannot be called on the object.&lt;br /&gt;
&lt;br /&gt;
Note that 7014 is also purportedly triggered with a &amp;quot;nosuchfunction&amp;quot; message in mnet_server_invoke_method, but it is in a non-executable piece of code.&lt;br /&gt;
&lt;br /&gt;
=== 7015, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that the class doesn&#039;t export a list of published mnet methods, in either the case of the requested method being static, or not.&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== 7018, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request was for a system method (eg &amp;quot;listMethods&amp;quot;, etc), but it wasn&#039;t in the list of allowed systemcalls.  The complete list of system calls are:&lt;br /&gt;
&lt;br /&gt;
* listMethods&lt;br /&gt;
* methodSignature&lt;br /&gt;
* methodHelp&lt;br /&gt;
* listServices&lt;br /&gt;
* listFiles&lt;br /&gt;
* retrieveFile&lt;br /&gt;
* keyswap&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is the generic error code for the inability to find a function.&lt;br /&gt;
&lt;br /&gt;
=== 7019, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in mnet_system() if a system method has been called, but it&#039;s not listMethods, methodSignature, methodHelp, or listServices.  It looks as though listFiles or retrieveFile are not implemented, even though they are registered to mnet_system in the mnet_server_dispatch() function.&lt;br /&gt;
&lt;br /&gt;
This is also triggered if mnet_permit_rpc_call returns a non-zero error code that hasn&#039;t already been trapped by one of the RPC_ constants defined in mnet/lib.php (which have their own error codes)&lt;br /&gt;
&lt;br /&gt;
=== 705, &amp;quot;nosuchfile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the file requested cannot be found (eg auth/mnet/lib.php instead of auth/mnet/auth.php)&lt;br /&gt;
&lt;br /&gt;
=== 706, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request is for a function (rather than a static method or class method), and it cannot be called (eg function_exists fails)&lt;br /&gt;
&lt;br /&gt;
=== 707, &amp;quot;forbidden-function&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
There isn&#039;t any code that throws this error case&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
=== 702, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an authentication method, but the authentication plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 7013, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a class or static method has been requested, but the class could not be founded (eg class_exists fails).  The error message should be renamed in this case.&lt;br /&gt;
&lt;br /&gt;
=== 1, &amp;quot;authfail_nosessionexists&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there&#039;s no record in the mnet_session table for the given token and useragent.&lt;br /&gt;
&lt;br /&gt;
=== 2, &amp;quot;authfail_sessiontimedout&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there is a session, but confirmation has already timed out&lt;br /&gt;
&lt;br /&gt;
=== 3, &amp;quot;authfail_usermismatch&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Moodle can&#039;t find the user that the mnet session has been set up for. This is a weird error, but could possibly happen if the user was deleted between the mnet session being created, and confirmed.&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
=== 703, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an enrolment method, but the enrolment plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a portfolio plugin. This should be changed to check that the portfolio plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 8009, &amp;quot;mnet_notoken&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a portfolio file from Moodle and Moodle can&#039;t find a token in the transfer queue.&lt;br /&gt;
&lt;br /&gt;
=== 8010, &amp;quot;mnet_noid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, the queue record is found, but the transfer information cannot be rewoken (which can happen if permissions have changed or settings have changed in the meantime, or the transfer is expired)&lt;br /&gt;
&lt;br /&gt;
=== 8011, &amp;quot;mnet_wronghost&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is trigered if the xmlrpc request comes from a different host than the queue record has been saved against&lt;br /&gt;
&lt;br /&gt;
=== 8012, &amp;quot;mnet_nofile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, and Moodle can&#039;t find it&lt;br /&gt;
&lt;br /&gt;
=== 8013, &amp;quot;mnet_nofilecontents&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, Moodle portfolio records know which file to send, but the Files API throws an exception, or the file is empty.&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a repository plugin. This should be changed to check that the repository plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== others ===&lt;br /&gt;
&lt;br /&gt;
TODO Jerome or someone else&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Dangerous mode&amp;quot; errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when $CFG-&amp;gt;mnet_dispatcher_mode has been set to &amp;quot;dangerous&amp;quot;, and the request is for something other than a file that ends in &#039;.php&#039;, or the request comes from a client that isn&#039;t a trusted host&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67123</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67123"/>
		<updated>2010-01-11T04:09:55Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Repository errors */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
=== 7014, &amp;quot;nosuchmethod&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that a class method has been requested, a new object has been constructed, but then the method cannot be called on the object.&lt;br /&gt;
&lt;br /&gt;
Note that 7014 is also purportedly triggered with a &amp;quot;nosuchfunction&amp;quot; message in mnet_server_invoke_method, but it is in a non-executable piece of code.&lt;br /&gt;
&lt;br /&gt;
=== 7015, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that the class doesn&#039;t export a list of published mnet methods, in either the case of the requested method being static, or not.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== 7018, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request was for a system method (eg &amp;quot;listMethods&amp;quot;, etc), but it wasn&#039;t in the list of allowed systemcalls.  The complete list of system calls are:&lt;br /&gt;
&lt;br /&gt;
* listMethods&lt;br /&gt;
* methodSignature&lt;br /&gt;
* methodHelp&lt;br /&gt;
* listServices&lt;br /&gt;
* listFiles&lt;br /&gt;
* retrieveFile&lt;br /&gt;
* keyswap&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is the generic error code for the inability to find a function.&lt;br /&gt;
&lt;br /&gt;
=== 7019, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in mnet_system() if a system method has been called, but it&#039;s not listMethods, methodSignature, methodHelp, or listServices.  It looks as though listFiles or retrieveFile are not implemented, even though they are registered to mnet_system in the mnet_server_dispatch() function.&lt;br /&gt;
&lt;br /&gt;
This is also triggered if mnet_permit_rpc_call returns a non-zero error code that hasn&#039;t already been trapped by one of the RPC_ constants defined in mnet/lib.php (which have their own error codes)&lt;br /&gt;
&lt;br /&gt;
=== 705, &amp;quot;nosuchfile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the file requested cannot be found (eg auth/mnet/lib.php instead of auth/mnet/auth.php)&lt;br /&gt;
&lt;br /&gt;
=== 706, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request is for a function (rather than a static method or class method), and it cannot be called (eg function_exists fails)&lt;br /&gt;
&lt;br /&gt;
=== 707, &amp;quot;forbidden-function&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
There isn&#039;t any code that throws this error case&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
=== 702, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an authentication method, but the authentication plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 7013, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a class or static method has been requested, but the class could not be founded (eg class_exists fails).  The error message should be renamed in this case.&lt;br /&gt;
&lt;br /&gt;
=== 1, &amp;quot;authfail_nosessionexists&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there&#039;s no record in the mnet_session table for the given token and useragent.&lt;br /&gt;
&lt;br /&gt;
=== 2, &amp;quot;authfail_sessiontimedout&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there is a session, but confirmation has already timed out&lt;br /&gt;
&lt;br /&gt;
=== 3, &amp;quot;authfail_usermismatch&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Moodle can&#039;t find the user that the mnet session has been set up for. This is a weird error, but could possibly happen if the user was deleted between the mnet session being created, and confirmed.&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
=== 703, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an enrolment method, but the enrolment plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a portfolio plugin. This should be changed to check that the portfolio plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 8009, &amp;quot;mnet_notoken&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a portfolio file from Moodle and Moodle can&#039;t find a token in the transfer queue.&lt;br /&gt;
&lt;br /&gt;
=== 8010, &amp;quot;mnet_noid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, the queue record is found, but the transfer information cannot be rewoken (which can happen if permissions have changed or settings have changed in the meantime, or the transfer is expired)&lt;br /&gt;
&lt;br /&gt;
=== 8011, &amp;quot;mnet_wronghost&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is trigered if the xmlrpc request comes from a different host than the queue record has been saved against&lt;br /&gt;
&lt;br /&gt;
=== 8012, &amp;quot;mnet_nofile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, and Moodle can&#039;t find it&lt;br /&gt;
&lt;br /&gt;
=== 8013, &amp;quot;mnet_nofilecontents&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, Moodle portfolio records know which file to send, but the Files API throws an exception, or the file is empty.&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a repository plugin. This should be changed to check that the repository plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
TODO Jerome or someone else&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Dangerous mode&amp;quot; errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when $CFG-&amp;gt;mnet_dispatcher_mode has been set to &amp;quot;dangerous&amp;quot;, and the request is for something other than a file that ends in &#039;.php&#039;, or the request comes from a client that isn&#039;t a trusted host&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67122</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67122"/>
		<updated>2010-01-11T04:09:05Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Portfolio errors */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
=== 7014, &amp;quot;nosuchmethod&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that a class method has been requested, a new object has been constructed, but then the method cannot be called on the object.&lt;br /&gt;
&lt;br /&gt;
Note that 7014 is also purportedly triggered with a &amp;quot;nosuchfunction&amp;quot; message in mnet_server_invoke_method, but it is in a non-executable piece of code.&lt;br /&gt;
&lt;br /&gt;
=== 7015, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that the class doesn&#039;t export a list of published mnet methods, in either the case of the requested method being static, or not.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== 7018, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request was for a system method (eg &amp;quot;listMethods&amp;quot;, etc), but it wasn&#039;t in the list of allowed systemcalls.  The complete list of system calls are:&lt;br /&gt;
&lt;br /&gt;
* listMethods&lt;br /&gt;
* methodSignature&lt;br /&gt;
* methodHelp&lt;br /&gt;
* listServices&lt;br /&gt;
* listFiles&lt;br /&gt;
* retrieveFile&lt;br /&gt;
* keyswap&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is the generic error code for the inability to find a function.&lt;br /&gt;
&lt;br /&gt;
=== 7019, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in mnet_system() if a system method has been called, but it&#039;s not listMethods, methodSignature, methodHelp, or listServices.  It looks as though listFiles or retrieveFile are not implemented, even though they are registered to mnet_system in the mnet_server_dispatch() function.&lt;br /&gt;
&lt;br /&gt;
This is also triggered if mnet_permit_rpc_call returns a non-zero error code that hasn&#039;t already been trapped by one of the RPC_ constants defined in mnet/lib.php (which have their own error codes)&lt;br /&gt;
&lt;br /&gt;
=== 705, &amp;quot;nosuchfile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the file requested cannot be found (eg auth/mnet/lib.php instead of auth/mnet/auth.php)&lt;br /&gt;
&lt;br /&gt;
=== 706, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request is for a function (rather than a static method or class method), and it cannot be called (eg function_exists fails)&lt;br /&gt;
&lt;br /&gt;
=== 707, &amp;quot;forbidden-function&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
There isn&#039;t any code that throws this error case&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
=== 702, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an authentication method, but the authentication plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 7013, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a class or static method has been requested, but the class could not be founded (eg class_exists fails).  The error message should be renamed in this case.&lt;br /&gt;
&lt;br /&gt;
=== 1, &amp;quot;authfail_nosessionexists&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there&#039;s no record in the mnet_session table for the given token and useragent.&lt;br /&gt;
&lt;br /&gt;
=== 2, &amp;quot;authfail_sessiontimedout&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there is a session, but confirmation has already timed out&lt;br /&gt;
&lt;br /&gt;
=== 3, &amp;quot;authfail_usermismatch&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Moodle can&#039;t find the user that the mnet session has been set up for. This is a weird error, but could possibly happen if the user was deleted between the mnet session being created, and confirmed.&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
=== 703, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an enrolment method, but the enrolment plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a portfolio plugin. This should be changed to check that the portfolio plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
=== 8009, &amp;quot;mnet_notoken&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a portfolio file from Moodle and Moodle can&#039;t find a token in the transfer queue.&lt;br /&gt;
&lt;br /&gt;
=== 8010, &amp;quot;mnet_noid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, the queue record is found, but the transfer information cannot be rewoken (which can happen if permissions have changed or settings have changed in the meantime, or the transfer is expired)&lt;br /&gt;
&lt;br /&gt;
=== 8011, &amp;quot;mnet_wronghost&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is trigered if the xmlrpc request comes from a different host than the queue record has been saved against&lt;br /&gt;
&lt;br /&gt;
=== 8012, &amp;quot;mnet_nofile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, and Moodle can&#039;t find it&lt;br /&gt;
&lt;br /&gt;
=== 8013, &amp;quot;mnet_nofilecontents&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Mahara requests a file, Moodle portfolio records know which file to send, but the Files API throws an exception, or the file is empty.&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a repository plugin. This should be changed to check that the repository plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Dangerous mode&amp;quot; errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when $CFG-&amp;gt;mnet_dispatcher_mode has been set to &amp;quot;dangerous&amp;quot;, and the request is for something other than a file that ends in &#039;.php&#039;, or the request comes from a client that isn&#039;t a trusted host&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67121</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67121"/>
		<updated>2010-01-11T03:57:30Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Authentication errors */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
=== 7014, &amp;quot;nosuchmethod&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that a class method has been requested, a new object has been constructed, but then the method cannot be called on the object.&lt;br /&gt;
&lt;br /&gt;
Note that 7014 is also purportedly triggered with a &amp;quot;nosuchfunction&amp;quot; message in mnet_server_invoke_method, but it is in a non-executable piece of code.&lt;br /&gt;
&lt;br /&gt;
=== 7015, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that the class doesn&#039;t export a list of published mnet methods, in either the case of the requested method being static, or not.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== 7018, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request was for a system method (eg &amp;quot;listMethods&amp;quot;, etc), but it wasn&#039;t in the list of allowed systemcalls.  The complete list of system calls are:&lt;br /&gt;
&lt;br /&gt;
* listMethods&lt;br /&gt;
* methodSignature&lt;br /&gt;
* methodHelp&lt;br /&gt;
* listServices&lt;br /&gt;
* listFiles&lt;br /&gt;
* retrieveFile&lt;br /&gt;
* keyswap&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is the generic error code for the inability to find a function.&lt;br /&gt;
&lt;br /&gt;
=== 7019, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in mnet_system() if a system method has been called, but it&#039;s not listMethods, methodSignature, methodHelp, or listServices.  It looks as though listFiles or retrieveFile are not implemented, even though they are registered to mnet_system in the mnet_server_dispatch() function.&lt;br /&gt;
&lt;br /&gt;
This is also triggered if mnet_permit_rpc_call returns a non-zero error code that hasn&#039;t already been trapped by one of the RPC_ constants defined in mnet/lib.php (which have their own error codes)&lt;br /&gt;
&lt;br /&gt;
=== 705, &amp;quot;nosuchfile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the file requested cannot be found (eg auth/mnet/lib.php instead of auth/mnet/auth.php)&lt;br /&gt;
&lt;br /&gt;
=== 706, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request is for a function (rather than a static method or class method), and it cannot be called (eg function_exists fails)&lt;br /&gt;
&lt;br /&gt;
=== 707, &amp;quot;forbidden-function&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
There isn&#039;t any code that throws this error case&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
=== 702, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an authentication method, but the authentication plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 7013, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a class or static method has been requested, but the class could not be founded (eg class_exists fails).  The error message should be renamed in this case.&lt;br /&gt;
&lt;br /&gt;
=== 1, &amp;quot;authfail_nosessionexists&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there&#039;s no record in the mnet_session table for the given token and useragent.&lt;br /&gt;
&lt;br /&gt;
=== 2, &amp;quot;authfail_sessiontimedout&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when there is a session, but confirmation has already timed out&lt;br /&gt;
&lt;br /&gt;
=== 3, &amp;quot;authfail_usermismatch&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when Moodle can&#039;t find the user that the mnet session has been set up for. This is a weird error, but could possibly happen if the user was deleted between the mnet session being created, and confirmed.&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
=== 703, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an enrolment method, but the enrolment plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a portfolio plugin. This should be changed to check that the portfolio plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a repository plugin. This should be changed to check that the repository plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Dangerous mode&amp;quot; errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when $CFG-&amp;gt;mnet_dispatcher_mode has been set to &amp;quot;dangerous&amp;quot;, and the request is for something other than a file that ends in &#039;.php&#039;, or the request comes from a client that isn&#039;t a trusted host&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67120</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67120"/>
		<updated>2010-01-11T03:41:32Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
=== 7014, &amp;quot;nosuchmethod&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that a class method has been requested, a new object has been constructed, but then the method cannot be called on the object.&lt;br /&gt;
&lt;br /&gt;
Note that 7014 is also purportedly triggered with a &amp;quot;nosuchfunction&amp;quot; message in mnet_server_invoke_method, but it is in a non-executable piece of code.&lt;br /&gt;
&lt;br /&gt;
=== 7015, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in the case that the class doesn&#039;t export a list of published mnet methods, in either the case of the requested method being static, or not.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== 7018, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request was for a system method (eg &amp;quot;listMethods&amp;quot;, etc), but it wasn&#039;t in the list of allowed systemcalls.  The complete list of system calls are:&lt;br /&gt;
&lt;br /&gt;
* listMethods&lt;br /&gt;
* methodSignature&lt;br /&gt;
* methodHelp&lt;br /&gt;
* listServices&lt;br /&gt;
* listFiles&lt;br /&gt;
* retrieveFile&lt;br /&gt;
* keyswap&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is the generic error code for the inability to find a function.&lt;br /&gt;
&lt;br /&gt;
=== 7019, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in mnet_system() if a system method has been called, but it&#039;s not listMethods, methodSignature, methodHelp, or listServices.  It looks as though listFiles or retrieveFile are not implemented, even though they are registered to mnet_system in the mnet_server_dispatch() function.&lt;br /&gt;
&lt;br /&gt;
This is also triggered if mnet_permit_rpc_call returns a non-zero error code that hasn&#039;t already been trapped by one of the RPC_ constants defined in mnet/lib.php (which have their own error codes)&lt;br /&gt;
&lt;br /&gt;
=== 705, &amp;quot;nosuchfile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the file requested cannot be found (eg auth/mnet/lib.php instead of auth/mnet/auth.php)&lt;br /&gt;
&lt;br /&gt;
=== 706, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request is for a function (rather than a static method or class method), and it cannot be called (eg function_exists fails)&lt;br /&gt;
&lt;br /&gt;
=== 707, &amp;quot;forbidden-function&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
There isn&#039;t any code that throws this error case&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
=== 702, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an authentication method, but the authentication plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 7013, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a class or static method has been requested, but the class could not be founded (eg class_exists fails).  The error message should be renamed in this case.&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
=== 703, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an enrolment method, but the enrolment plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a portfolio plugin. This should be changed to check that the portfolio plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a repository plugin. This should be changed to check that the repository plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Dangerous mode&amp;quot; errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when $CFG-&amp;gt;mnet_dispatcher_mode has been set to &amp;quot;dangerous&amp;quot;, and the request is for something other than a file that ends in &#039;.php&#039;, or the request comes from a client that isn&#039;t a trusted host&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67119</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67119"/>
		<updated>2010-01-11T03:25:54Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== 7018, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request was for a system method (eg &amp;quot;listMethods&amp;quot;, etc), but it wasn&#039;t in the list of allowed systemcalls.  The complete list of system calls are:&lt;br /&gt;
&lt;br /&gt;
* listMethods&lt;br /&gt;
* methodSignature&lt;br /&gt;
* methodHelp&lt;br /&gt;
* listServices&lt;br /&gt;
* listFiles&lt;br /&gt;
* retrieveFile&lt;br /&gt;
* keyswap&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is the generic error code for the inability to find a function.&lt;br /&gt;
&lt;br /&gt;
=== 7019, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in mnet_system() if a system method has been called, but it&#039;s not listMethods, methodSignature, methodHelp, or listServices.  It looks as though listFiles or retrieveFile are not implemented, even though they are registered to mnet_system in the mnet_server_dispatch() function.&lt;br /&gt;
&lt;br /&gt;
This is also triggered if mnet_permit_rpc_call returns a non-zero error code that hasn&#039;t already been trapped by one of the RPC_ constants defined in mnet/lib.php (which have their own error codes)&lt;br /&gt;
&lt;br /&gt;
=== 705, &amp;quot;nosuchfile&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the file requested cannot be found (eg auth/mnet/lib.php instead of auth/mnet/auth.php)&lt;br /&gt;
&lt;br /&gt;
=== 706, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request is for a function (rather than a static method or class method), and it cannot be called (eg function_exists fails)&lt;br /&gt;
&lt;br /&gt;
=== 707, &amp;quot;forbidden-function&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
There isn&#039;t any code that throws this error case&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
=== 702, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an authentication method, but the authentication plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
=== 7013, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when a class or static method has been requested, but the class could not be founded (eg class_exists fails).  The error message should be renamed in this case.&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
=== 703, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an enrolment method, but the enrolment plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a portfolio plugin. This should be changed to check that the portfolio plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a repository plugin. This should be changed to check that the repository plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Dangerous mode&amp;quot; errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when $CFG-&amp;gt;mnet_dispatcher_mode has been set to &amp;quot;dangerous&amp;quot;, and the request is for something other than a file that ends in &#039;.php&#039;, or the request comes from a client that isn&#039;t a trusted host&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67118</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67118"/>
		<updated>2010-01-11T03:13:02Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== 7018, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request was for a system method (eg &amp;quot;listMethods&amp;quot;, etc), but it wasn&#039;t in the list of allowed systemcalls.  The complete list of system calls are:&lt;br /&gt;
&lt;br /&gt;
* listMethods&lt;br /&gt;
* methodSignature&lt;br /&gt;
* methodHelp&lt;br /&gt;
* listServices&lt;br /&gt;
* listFiles&lt;br /&gt;
* retrieveFile&lt;br /&gt;
* keyswap&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is the generic error code for the inability to find a function.&lt;br /&gt;
&lt;br /&gt;
=== 7019, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered in mnet_system() if a system method has been called, but it&#039;s not listMethods, methodSignature, methodHelp, or listServices.  It looks as though listFiles or retrieveFile are not implemented, even though they are registered to mnet_system in the mnet_server_dispatch() function.&lt;br /&gt;
&lt;br /&gt;
This is also triggered if mnet_permit_rpc_call returns a non-zero error code that hasn&#039;t already been trapped by one of the RPC_ constants defined in mnet/lib.php (which have their own error codes)&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
=== 702, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an authentication method, but the authentication plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
=== 703, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an enrolment method, but the enrolment plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a portfolio plugin. This should be changed to check that the portfolio plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when an invalid filename is sent for a repository plugin. This should be changed to check that the repository plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Dangerous mode&amp;quot; errors ==&lt;br /&gt;
&lt;br /&gt;
=== 7012, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when $CFG-&amp;gt;mnet_dispatcher_mode has been set to &amp;quot;dangerous&amp;quot;, and the request is for something other than a file that ends in &#039;.php&#039;, or the request comes from a client that isn&#039;t a trusted host&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67116</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67116"/>
		<updated>2010-01-11T02:59:37Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Authentication errors */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== 7018, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request was for a system method (eg &amp;quot;listMethods&amp;quot;, etc), but it wasn&#039;t in the list of allowed systemcalls.  The complete list of system calls are:&lt;br /&gt;
&lt;br /&gt;
* listMethods&lt;br /&gt;
* methodSignature&lt;br /&gt;
* methodHelp&lt;br /&gt;
* listServices&lt;br /&gt;
* listFiles&lt;br /&gt;
* retrieveFile&lt;br /&gt;
* keyswap&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
=== 702, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the request was for an authentication method, but the authentication plugin requested wasn&#039;t enabled.&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67115</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67115"/>
		<updated>2010-01-11T02:57:23Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Dispatch errors */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== 7018, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the xmlrpc request was for a system method (eg &amp;quot;listMethods&amp;quot;, etc), but it wasn&#039;t in the list of allowed systemcalls.  The complete list of system calls are:&lt;br /&gt;
&lt;br /&gt;
* listMethods&lt;br /&gt;
* methodSignature&lt;br /&gt;
* methodHelp&lt;br /&gt;
* listServices&lt;br /&gt;
* listFiles&lt;br /&gt;
* retrieveFile&lt;br /&gt;
* keyswap&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67114</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67114"/>
		<updated>2010-01-11T02:53:35Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* System errors */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System/Verification errors ==&lt;br /&gt;
&lt;br /&gt;
=== 712, &amp;quot;phperror&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is called from the main mnet xmlrpc server (mnet/xmlrpc/server.php) when $_SERVER is unset.&lt;br /&gt;
&lt;br /&gt;
=== 7025 ===&lt;br /&gt;
&lt;br /&gt;
This is triggered when the peer used an older public key.  This sends the xmlrpc server fault, with 7025 as the code, and the current public key as the text of the error message.&lt;br /&gt;
&lt;br /&gt;
=== 7021, &amp;quot;forbidden-transport&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a non-encrypted request is sent, and plaintext is disallowed (plaintext can be enabled for trusted hosts within a designated subnet)&lt;br /&gt;
&lt;br /&gt;
=== 711, &amp;quot;verifysignature-error&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request wasn&#039;t signed&lt;br /&gt;
&lt;br /&gt;
=== 710, &amp;quot;verifysignature-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if a request was signed, but not able to be verified&lt;br /&gt;
&lt;br /&gt;
=== 7020, &amp;quot;wrong-wwwroot&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the host record is unable to be found, based on the wwwroot inside the xmlrpc request.  This can sometimes happen if you use www.mysite.com and mysite.com&lt;br /&gt;
&lt;br /&gt;
=== 7023, &amp;quot;encryption-invalid&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if Moodle can&#039;t decrypt the message either with the current key, or with any of the keys in the history.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Dispatch errors ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 713, &amp;quot;nosuchfunction&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if the function given in the xmlrpc request doesn&#039;t match the regular expression of allowed function calls (which must be of the form auth/mnet/auth.php/function_name)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 704, &amp;quot;nosuchservice&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is triggered if &amp;quot;Networking&amp;quot; is disabled in Admin -&amp;gt;  Advanced Features, or $CFG-&amp;gt;mnet_dispatcher_mode is &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67111</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67111"/>
		<updated>2010-01-11T02:26:05Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System errors ==&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67110</id>
		<title>Development:MNet Errors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:MNet_Errors&amp;diff=67110"/>
		<updated>2010-01-11T02:25:24Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: New page: == Introduction ==  This wiki page attempts to document all the MNET error codes, what they mean, where they&amp;#039;re called from, and what cases can trigger them.  As MNET is  theoretically plu...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This wiki page attempts to document all the MNET error codes, what they mean, where they&#039;re called from, and what cases can trigger them.  As MNET is&lt;br /&gt;
 theoretically pluggable, this does not cover all exhaustive cases, just ones that are included in the core Moodle distribution.&lt;br /&gt;
&lt;br /&gt;
== System errors ==&lt;br /&gt;
&lt;br /&gt;
== Authentication errors ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Enrolment errors ==&lt;br /&gt;
&lt;br /&gt;
== Portfolio errors ==&lt;br /&gt;
&lt;br /&gt;
== Repository errors ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:State_of_MNET&amp;diff=66922</id>
		<title>Development:State of MNET</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:State_of_MNET&amp;diff=66922"/>
		<updated>2010-01-06T03:29:21Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: New page: == Introduction ==  The purpose of this wiki page is to capture the current state of the Moodle Networking feature as it stands coming up to the 2.0 release, the open bugs and problems, an...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The purpose of this wiki page is to capture the current state of the Moodle Networking feature as it stands coming up to the 2.0 release, the open bugs and problems, and come up with a plan to improve things for the 2.0 release, as well as fix some outstanding problems in 1.9&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Design flaws ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Coding style problems ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Security problems ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66918</id>
		<title>Development:Scheduled Tasks Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66918"/>
		<updated>2010-01-05T22:36:52Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* TODO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This proposal is meant both to provide a replacement for the moodle cron job, and provide a means to schedule once off tasks to be run outside of the user&#039;s request lifecycle.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Subtask&#039;&#039;&#039; an individual piece of cron processing that should be run (equivalent to forum_cron now, or maybe even smaller)&lt;br /&gt;
* &#039;&#039;&#039;Moodle cron instance&#039;&#039;&#039; a cron.php process&lt;br /&gt;
&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The moodle cronjob currently delegates all scheduling to each subtask that is run - for example, the forum cron is responsible for checking when it last run, and making decisions about whether or not it should be run again.   This sort of decision process should be centralised, and individual cron subtasks should be called by the central controller.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is not any central locking of subtasks.  At the moment, some subtasks that expect that they might take a long time to run implement their own locking (for example statistics), but it&#039;s not centralised.  Each moodle cron instance runs to completion, no matter how long it takes, and it processes tasks in the order that they&#039;re programmed, regardless of if there are any other moodle cron instances running, that might be processing sub tasks in parallel&lt;br /&gt;
&lt;br /&gt;
The existing events API seems like it should provide a way to schedule tasks to be run outside of a user&#039;s request cycle, but in reality this just adds to the existing cron problem.  We need to have a way in Moodle to schedule once off tasks to be run &amp;quot;at the next available time&amp;quot; which are picked up by cron.  This can be used to process the event queue, but also for some code to just register a new once off cron event &amp;quot;on the fly&amp;quot; and be picked up on the next run.&lt;br /&gt;
&lt;br /&gt;
Finally, we need to be able to run non-related tasks in parallel so that the entire moodle queue isn&#039;t held up by single long running jobs.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Centralised locking for &#039;&#039;&#039;all&#039;&#039;&#039; tasks&lt;br /&gt;
* A way consistent for &#039;&#039;&#039;all plugin types&#039;&#039;&#039; to register with Moodle (at installation/upgrade) when they want their jobs run&lt;br /&gt;
* More sophisticated scheduling rather than just intervals in seconds (eg every sunday at 11pm or similar) based on unix cron&lt;br /&gt;
* An administration screen in Moodle to allow site administrators to adjust the scheduling of individual tasks&lt;br /&gt;
* An easy way for core and module code to schedule a once off task to be run as soon as possible&lt;br /&gt;
&lt;br /&gt;
== Approach ==&lt;br /&gt;
&lt;br /&gt;
=== Plugin cron registration ===&lt;br /&gt;
&lt;br /&gt;
Each plugin will be able to provide a db/tasks.php (alongside access.php and events.php etc) that lists all the cronjobs that it wants to have run.  This will look something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$tasks = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;function&#039;    =&amp;gt; &#039;yourmodule_cron_somedescription&#039;,&lt;br /&gt;
        &#039;minute&#039;      =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;hour&#039;        =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;day&#039;         =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;month&#039;       =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;dayofweek&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;langstringkey&#039;, // this must correspond to get_string(&#039;langstringkey&#039;, &#039;yourmodule&#039;);&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields are the same as normal unix cron, with the exception that you cannot use 3 letter words for the month and day of week fields like you can for unix cron.  The following is straight from the unix manpage about cron:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
              field          allowed values&lt;br /&gt;
              -----          --------------&lt;br /&gt;
              minute         0-59&lt;br /&gt;
              hour           0-23&lt;br /&gt;
              day of month   1-31&lt;br /&gt;
              month          1-12 (or names, see below)&lt;br /&gt;
              day of week    0-7 (0 or 7 is Sun, or use names)&lt;br /&gt;
&lt;br /&gt;
       A field may be an asterisk (*), which always stands for ``first-last&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Ranges  of  numbers  are  allowed.  Ranges are two numbers separated with a hyphen.&lt;br /&gt;
       The specified range is inclusive.  For example, 8-11 for an ``hours&#039;&#039; entry specifies&lt;br /&gt;
       execution at hours 8, 9, 10 and 11.&lt;br /&gt;
&lt;br /&gt;
       Lists are allowed.  A list is a set of numbers (or ranges) separated by commas.&lt;br /&gt;
       Examples: ``1,2,5,9&#039;&#039;, ``0-4,8-12&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Step values can be used in conjunction with ranges.  Following a range with ``/&amp;lt;number&amp;gt;&#039;&#039;&lt;br /&gt;
       specifies  skips  of  the  number&#039;s  value  through  the  range.   For  example,&lt;br /&gt;
       ``0-23/2&#039;&#039; can be used in the hours field to specify command execution every other hour&lt;br /&gt;
       (the alternative in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22&#039;&#039;).  Steps&lt;br /&gt;
       are also permitted after an asterisk, so if you want to say ``every two hours&#039;&#039;, just use ``*/2&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The unix crontab manpage goes on to say that one can use 3 letter words in the month and dayofweek fields (eg Sun or Feb).  I don&#039;t think this is necessary for our implementation.&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|lastruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|-&lt;br /&gt;
|minute&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|hour&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|day&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|month&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|dayofweek&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|customised&lt;br /&gt;
|integer(1)&lt;br /&gt;
|0 or 1 - whether this time differs from what is in code&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This table is for all the normal scheduled regular tasks.  The time fields are intially populated when a plugin is installed or upgraded, but can be overridden by an administrator, which sets the &amp;quot;customised&amp;quot; flag to 1.  If the administrator later decides to revert their customisation, the original code-values are repopulated into this table.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_onceoff_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|customdata&lt;br /&gt;
|text&lt;br /&gt;
|any data or serialised information&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This table is for the once off tasks, which are run and then deleted.  There isn&#039;t a unique constraint on &#039;callfunction&#039; in this table, because the same once off task may be scheduled twice before the first one is processed.  In this case, the named lock will be obtained using a combination of callfunction and the id.&lt;br /&gt;
&lt;br /&gt;
The original database specification had extra custom fields in the main scheduled_tasks table, that the cronjobs could insert information into, called custom1 and custom2 and so on.  I&#039;ve removed these from this specification until such time as we have a solid use-case for them.  It is certain that we need it for the once off tasks, however, but in this case I think it&#039;s better to just have a text field that can either contain a single value, or a serialised blob of information.&lt;br /&gt;
&lt;br /&gt;
The original spec also had a priority field, but this has been removed after the conversation in Jizerka, which led to the proposal to just let some jobs block all others, rather than prioritising individual tasks.  &#039;&#039;&#039;This decision may be later reverted&#039;&#039;&#039; especially for once off tasks, where some may be really urgent.&lt;br /&gt;
&lt;br /&gt;
=== Locking ===&lt;br /&gt;
&lt;br /&gt;
Penny and Tim originally thought that the best approach was to try and do something that would cause an exception to be thrown - for example, try to insert into a row that had a unique constraint on it, and catch the exception.  However, this will cause far too much noise in the logs.  Matt Oquist came up with a different approach in MDL-21110.  We could potentially change this slightly to allow alternative implementations, by means of an abstract class and factory method (this was suggested by Sam Marshall), but probaby isn&#039;t needed for the initial implementation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Black magic ===&lt;br /&gt;
&lt;br /&gt;
Cron.php will need to be rewritten to look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
while ($nexttask = cron_get_next_task()) {&lt;br /&gt;
    cron_call_function($nexttask);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some black magic to hand out the next task, which does:&lt;br /&gt;
&lt;br /&gt;
* Checks how long the existing process is allowed to run for&lt;br /&gt;
* Figures out if there&#039;s already a &amp;quot;blocking&amp;quot; task running&lt;br /&gt;
* Figures out the next task that&#039;s scheduled&lt;br /&gt;
* Tries to get a lock on it&lt;br /&gt;
* Returns that task&lt;br /&gt;
&lt;br /&gt;
== Unresolved issues/ideas ==&lt;br /&gt;
&lt;br /&gt;
* It might be nice at some point to find a way to allow different subtasks to run on different servers by designation.  This could be eventually added in to the administration screens as an extra setting (IP address)&lt;br /&gt;
* We obviously need some way to avoid different tasks trampling on eachother.  We ran through a number of ideas already, from differentiating between read/write operations, to having dependencies or conflicts between tasks, to having each task say which database tables it uses.   Finally we decided it would be best to just have some tasks that are able to simply block all others from being run.  Anything to do with authentication and enrolment must block other tasks from running, as otherwise there could be the problem of for example, forum posts being emailed out just before someone is unenrolled from a course.&lt;br /&gt;
* When the first cron in a long time is running, we should lock the entire cron and let it run to completeness, because the order is really important then.  This means that there also needs to be some global lastcronruntime flag somewhere (like in the config table)&lt;br /&gt;
&lt;br /&gt;
== Psuedo code proposal ==&lt;br /&gt;
Moved [[Development_talk:Scheduled_Tasks_Proposal|to the talk page]]&lt;br /&gt;
&lt;br /&gt;
== Audit of current cron ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Main section&lt;br /&gt;
! Subtask&lt;br /&gt;
! Frequency&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| session_gc&lt;br /&gt;
|&lt;br /&gt;
| every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|plugins (none)&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|message submissions&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update chat times&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update_events&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old chat_users and add quits&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old messages&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/data&lt;br /&gt;
|&lt;br /&gt;
|every minute&lt;br /&gt;
|no _cron function (includes file unnecessarily)&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|mail posts&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|digest processing&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|delete old read tracking&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/scorm&lt;br /&gt;
|reparse all scorms&lt;br /&gt;
|every five minutes&lt;br /&gt;
|does hourly checking&lt;br /&gt;
|-&lt;br /&gt;
|mod/wiki&lt;br /&gt;
|delete expired locks&lt;br /&gt;
|every hour&lt;br /&gt;
|-&lt;br /&gt;
|blocks/rss_client&lt;br /&gt;
|update feeds&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|quiz/report/statistics&lt;br /&gt;
|delete old statistics&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admin/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|language_cache&lt;br /&gt;
&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|remove expired enrolments&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|lock pending grades (*2)&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|clean old grade history&lt;br /&gt;
|every run&lt;br /&gt;
|has a TODO to not process as often&lt;br /&gt;
|-&lt;br /&gt;
|event queue&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|portfolio cron&lt;br /&gt;
|clean expired exports&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|longtimenosee&lt;br /&gt;
&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteunconfirmedusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteincompleteusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteoldlogs&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deletefiltercache&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|notifyloginfailures&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|metacourse syncing&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|createpasswordemails&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|tag cron&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|clean contexts&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|gc_cache_flags&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|build_context_path&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|scheduled backups&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|make rss feeds&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|keepalives&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|delete old sessions&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/ldap&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/cas&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/db&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|clears old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|notifies administrators of old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|process orders &amp;amp; email teachers&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/flatfile&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/imsenterprise&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/manual&lt;br /&gt;
|notify people of pending unenrolments&lt;br /&gt;
|daily&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|statistics&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|huge&lt;br /&gt;
|-&lt;br /&gt;
|grade/import&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/export&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|fetch blog entries&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|file gc&lt;br /&gt;
|&lt;br /&gt;
|(optional) daily, else every run?&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|local cron&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
* Audit all existing cronjobs (done)&lt;br /&gt;
* Implement the locking code, either Matt&#039;s or something similar and write robust tests for it (this will be hard to test perhaps - can we test race conditions using simpletest?)&lt;br /&gt;
* Write the black magic that hands out the next task to be run for a given cron process&lt;br /&gt;
* Rewrite cron.php to use the black magic&lt;br /&gt;
* Migrate all the existing cronjobs to the new system&lt;br /&gt;
* Write screens to allow administrators to reschedule tasks&lt;br /&gt;
* Write code to transfer between unix-cron-syntax and user-friendly syntax (and vice versa)&lt;br /&gt;
* Write code to capture requests to schedule once off tasks&lt;br /&gt;
* Update portfolio code to use once off tasks rather than events API&lt;br /&gt;
* Evaluate integration of event API to once off tasks&lt;br /&gt;
* Test thoroughly&lt;br /&gt;
&lt;br /&gt;
== TODO ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66917</id>
		<title>Development:Scheduled Tasks Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66917"/>
		<updated>2010-01-05T22:33:36Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Tasks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This proposal is meant both to provide a replacement for the moodle cron job, and provide a means to schedule once off tasks to be run outside of the user&#039;s request lifecycle.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Subtask&#039;&#039;&#039; an individual piece of cron processing that should be run (equivalent to forum_cron now, or maybe even smaller)&lt;br /&gt;
* &#039;&#039;&#039;Moodle cron instance&#039;&#039;&#039; a cron.php process&lt;br /&gt;
&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The moodle cronjob currently delegates all scheduling to each subtask that is run - for example, the forum cron is responsible for checking when it last run, and making decisions about whether or not it should be run again.   This sort of decision process should be centralised, and individual cron subtasks should be called by the central controller.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is not any central locking of subtasks.  At the moment, some subtasks that expect that they might take a long time to run implement their own locking (for example statistics), but it&#039;s not centralised.  Each moodle cron instance runs to completion, no matter how long it takes, and it processes tasks in the order that they&#039;re programmed, regardless of if there are any other moodle cron instances running, that might be processing sub tasks in parallel&lt;br /&gt;
&lt;br /&gt;
The existing events API seems like it should provide a way to schedule tasks to be run outside of a user&#039;s request cycle, but in reality this just adds to the existing cron problem.  We need to have a way in Moodle to schedule once off tasks to be run &amp;quot;at the next available time&amp;quot; which are picked up by cron.  This can be used to process the event queue, but also for some code to just register a new once off cron event &amp;quot;on the fly&amp;quot; and be picked up on the next run.&lt;br /&gt;
&lt;br /&gt;
Finally, we need to be able to run non-related tasks in parallel so that the entire moodle queue isn&#039;t held up by single long running jobs.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Centralised locking for &#039;&#039;&#039;all&#039;&#039;&#039; tasks&lt;br /&gt;
* A way consistent for &#039;&#039;&#039;all plugin types&#039;&#039;&#039; to register with Moodle (at installation/upgrade) when they want their jobs run&lt;br /&gt;
* More sophisticated scheduling rather than just intervals in seconds (eg every sunday at 11pm or similar) based on unix cron&lt;br /&gt;
* An administration screen in Moodle to allow site administrators to adjust the scheduling of individual tasks&lt;br /&gt;
* An easy way for core and module code to schedule a once off task to be run as soon as possible&lt;br /&gt;
&lt;br /&gt;
== Approach ==&lt;br /&gt;
&lt;br /&gt;
=== Plugin cron registration ===&lt;br /&gt;
&lt;br /&gt;
Each plugin will be able to provide a db/tasks.php (alongside access.php and events.php etc) that lists all the cronjobs that it wants to have run.  This will look something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$tasks = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;function&#039;    =&amp;gt; &#039;yourmodule_cron_somedescription&#039;,&lt;br /&gt;
        &#039;minute&#039;      =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;hour&#039;        =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;day&#039;         =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;month&#039;       =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;dayofweek&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;langstringkey&#039;, // this must correspond to get_string(&#039;langstringkey&#039;, &#039;yourmodule&#039;);&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields are the same as normal unix cron, with the exception that you cannot use 3 letter words for the month and day of week fields like you can for unix cron.  The following is straight from the unix manpage about cron:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
              field          allowed values&lt;br /&gt;
              -----          --------------&lt;br /&gt;
              minute         0-59&lt;br /&gt;
              hour           0-23&lt;br /&gt;
              day of month   1-31&lt;br /&gt;
              month          1-12 (or names, see below)&lt;br /&gt;
              day of week    0-7 (0 or 7 is Sun, or use names)&lt;br /&gt;
&lt;br /&gt;
       A field may be an asterisk (*), which always stands for ``first-last&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Ranges  of  numbers  are  allowed.  Ranges are two numbers separated with a hyphen.&lt;br /&gt;
       The specified range is inclusive.  For example, 8-11 for an ``hours&#039;&#039; entry specifies&lt;br /&gt;
       execution at hours 8, 9, 10 and 11.&lt;br /&gt;
&lt;br /&gt;
       Lists are allowed.  A list is a set of numbers (or ranges) separated by commas.&lt;br /&gt;
       Examples: ``1,2,5,9&#039;&#039;, ``0-4,8-12&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Step values can be used in conjunction with ranges.  Following a range with ``/&amp;lt;number&amp;gt;&#039;&#039;&lt;br /&gt;
       specifies  skips  of  the  number&#039;s  value  through  the  range.   For  example,&lt;br /&gt;
       ``0-23/2&#039;&#039; can be used in the hours field to specify command execution every other hour&lt;br /&gt;
       (the alternative in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22&#039;&#039;).  Steps&lt;br /&gt;
       are also permitted after an asterisk, so if you want to say ``every two hours&#039;&#039;, just use ``*/2&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The unix crontab manpage goes on to say that one can use 3 letter words in the month and dayofweek fields (eg Sun or Feb).  I don&#039;t think this is necessary for our implementation.&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|lastruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|-&lt;br /&gt;
|minute&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|hour&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|day&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|month&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|dayofweek&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|customised&lt;br /&gt;
|integer(1)&lt;br /&gt;
|0 or 1 - whether this time differs from what is in code&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This table is for all the normal scheduled regular tasks.  The time fields are intially populated when a plugin is installed or upgraded, but can be overridden by an administrator, which sets the &amp;quot;customised&amp;quot; flag to 1.  If the administrator later decides to revert their customisation, the original code-values are repopulated into this table.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_onceoff_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|customdata&lt;br /&gt;
|text&lt;br /&gt;
|any data or serialised information&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This table is for the once off tasks, which are run and then deleted.  There isn&#039;t a unique constraint on &#039;callfunction&#039; in this table, because the same once off task may be scheduled twice before the first one is processed.  In this case, the named lock will be obtained using a combination of callfunction and the id.&lt;br /&gt;
&lt;br /&gt;
The original database specification had extra custom fields in the main scheduled_tasks table, that the cronjobs could insert information into, called custom1 and custom2 and so on.  I&#039;ve removed these from this specification until such time as we have a solid use-case for them.  It is certain that we need it for the once off tasks, however, but in this case I think it&#039;s better to just have a text field that can either contain a single value, or a serialised blob of information.&lt;br /&gt;
&lt;br /&gt;
The original spec also had a priority field, but this has been removed after the conversation in Jizerka, which led to the proposal to just let some jobs block all others, rather than prioritising individual tasks.  &#039;&#039;&#039;This decision may be later reverted&#039;&#039;&#039; especially for once off tasks, where some may be really urgent.&lt;br /&gt;
&lt;br /&gt;
=== Locking ===&lt;br /&gt;
&lt;br /&gt;
Penny and Tim originally thought that the best approach was to try and do something that would cause an exception to be thrown - for example, try to insert into a row that had a unique constraint on it, and catch the exception.  However, this will cause far too much noise in the logs.  Matt Oquist came up with a different approach in MDL-21110.  We could potentially change this slightly to allow alternative implementations, by means of an abstract class and factory method (this was suggested by Sam Marshall), but probaby isn&#039;t needed for the initial implementation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Black magic ===&lt;br /&gt;
&lt;br /&gt;
Cron.php will need to be rewritten to look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
while ($nexttask = cron_get_next_task()) {&lt;br /&gt;
    cron_call_function($nexttask);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some black magic to hand out the next task, which does:&lt;br /&gt;
&lt;br /&gt;
* Checks how long the existing process is allowed to run for&lt;br /&gt;
* Figures out if there&#039;s already a &amp;quot;blocking&amp;quot; task running&lt;br /&gt;
* Figures out the next task that&#039;s scheduled&lt;br /&gt;
* Tries to get a lock on it&lt;br /&gt;
* Returns that task&lt;br /&gt;
&lt;br /&gt;
== Unresolved issues/ideas ==&lt;br /&gt;
&lt;br /&gt;
* It might be nice at some point to find a way to allow different subtasks to run on different servers by designation.  This could be eventually added in to the administration screens as an extra setting (IP address)&lt;br /&gt;
* We obviously need some way to avoid different tasks trampling on eachother.  We ran through a number of ideas already, from differentiating between read/write operations, to having dependencies or conflicts between tasks, to having each task say which database tables it uses.   Finally we decided it would be best to just have some tasks that are able to simply block all others from being run.  Anything to do with authentication and enrolment must block other tasks from running, as otherwise there could be the problem of for example, forum posts being emailed out just before someone is unenrolled from a course.&lt;br /&gt;
* When the first cron in a long time is running, we should lock the entire cron and let it run to completeness, because the order is really important then.  This means that there also needs to be some global lastcronruntime flag somewhere (like in the config table)&lt;br /&gt;
&lt;br /&gt;
== Psuedo code proposal ==&lt;br /&gt;
Moved [[Development_talk:Scheduled_Tasks_Proposal|to the talk page]]&lt;br /&gt;
&lt;br /&gt;
== Audit of current cron ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Main section&lt;br /&gt;
! Subtask&lt;br /&gt;
! Frequency&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| session_gc&lt;br /&gt;
|&lt;br /&gt;
| every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|plugins (none)&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|message submissions&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update chat times&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update_events&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old chat_users and add quits&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old messages&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/data&lt;br /&gt;
|&lt;br /&gt;
|every minute&lt;br /&gt;
|no _cron function (includes file unnecessarily)&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|mail posts&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|digest processing&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|delete old read tracking&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/scorm&lt;br /&gt;
|reparse all scorms&lt;br /&gt;
|every five minutes&lt;br /&gt;
|does hourly checking&lt;br /&gt;
|-&lt;br /&gt;
|mod/wiki&lt;br /&gt;
|delete expired locks&lt;br /&gt;
|every hour&lt;br /&gt;
|-&lt;br /&gt;
|blocks/rss_client&lt;br /&gt;
|update feeds&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|quiz/report/statistics&lt;br /&gt;
|delete old statistics&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admin/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|language_cache&lt;br /&gt;
&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|remove expired enrolments&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|lock pending grades (*2)&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|clean old grade history&lt;br /&gt;
|every run&lt;br /&gt;
|has a TODO to not process as often&lt;br /&gt;
|-&lt;br /&gt;
|event queue&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|portfolio cron&lt;br /&gt;
|clean expired exports&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|longtimenosee&lt;br /&gt;
&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteunconfirmedusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteincompleteusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteoldlogs&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deletefiltercache&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|notifyloginfailures&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|metacourse syncing&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|createpasswordemails&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|tag cron&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|clean contexts&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|gc_cache_flags&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|build_context_path&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|scheduled backups&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|make rss feeds&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|keepalives&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|delete old sessions&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/ldap&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/cas&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/db&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|clears old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|notifies administrators of old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|process orders &amp;amp; email teachers&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/flatfile&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/imsenterprise&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/manual&lt;br /&gt;
|notify people of pending unenrolments&lt;br /&gt;
|daily&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|statistics&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|huge&lt;br /&gt;
|-&lt;br /&gt;
|grade/import&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/export&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|fetch blog entries&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|file gc&lt;br /&gt;
|&lt;br /&gt;
|(optional) daily, else every run?&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|local cron&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
* Audit all existing cronjobs (done)&lt;br /&gt;
* Implement the locking code, either Matt&#039;s or something similar and write robust tests for it (this will be hard to test perhaps - can we test race conditions using simpletest?)&lt;br /&gt;
* Write the black magic that hands out the next task to be run for a given cron process&lt;br /&gt;
* Rewrite cron.php to use the black magic&lt;br /&gt;
* Migrate all the existing cronjobs to the new system&lt;br /&gt;
* Write screens to allow administrators to reschedule tasks&lt;br /&gt;
* Write code to transfer between unix-cron-syntax and user-friendly syntax (and vice versa)&lt;br /&gt;
* Write code to capture requests to schedule once off tasks&lt;br /&gt;
* Update portfolio code to use once off tasks rather than events API&lt;br /&gt;
* Evaluate integration of event API to once off tasks&lt;br /&gt;
* Test thoroughly&lt;br /&gt;
&lt;br /&gt;
== TODO ==&lt;br /&gt;
&lt;br /&gt;
* This doesn&#039;t include a way to schedule new immediate tasks yet (something like scheduled_tasks_asap table)&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66916</id>
		<title>Development:Scheduled Tasks Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66916"/>
		<updated>2010-01-05T22:29:46Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Database */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This proposal is meant both to provide a replacement for the moodle cron job, and provide a means to schedule once off tasks to be run outside of the user&#039;s request lifecycle.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Subtask&#039;&#039;&#039; an individual piece of cron processing that should be run (equivalent to forum_cron now, or maybe even smaller)&lt;br /&gt;
* &#039;&#039;&#039;Moodle cron instance&#039;&#039;&#039; a cron.php process&lt;br /&gt;
&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The moodle cronjob currently delegates all scheduling to each subtask that is run - for example, the forum cron is responsible for checking when it last run, and making decisions about whether or not it should be run again.   This sort of decision process should be centralised, and individual cron subtasks should be called by the central controller.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is not any central locking of subtasks.  At the moment, some subtasks that expect that they might take a long time to run implement their own locking (for example statistics), but it&#039;s not centralised.  Each moodle cron instance runs to completion, no matter how long it takes, and it processes tasks in the order that they&#039;re programmed, regardless of if there are any other moodle cron instances running, that might be processing sub tasks in parallel&lt;br /&gt;
&lt;br /&gt;
The existing events API seems like it should provide a way to schedule tasks to be run outside of a user&#039;s request cycle, but in reality this just adds to the existing cron problem.  We need to have a way in Moodle to schedule once off tasks to be run &amp;quot;at the next available time&amp;quot; which are picked up by cron.  This can be used to process the event queue, but also for some code to just register a new once off cron event &amp;quot;on the fly&amp;quot; and be picked up on the next run.&lt;br /&gt;
&lt;br /&gt;
Finally, we need to be able to run non-related tasks in parallel so that the entire moodle queue isn&#039;t held up by single long running jobs.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Centralised locking for &#039;&#039;&#039;all&#039;&#039;&#039; tasks&lt;br /&gt;
* A way consistent for &#039;&#039;&#039;all plugin types&#039;&#039;&#039; to register with Moodle (at installation/upgrade) when they want their jobs run&lt;br /&gt;
* More sophisticated scheduling rather than just intervals in seconds (eg every sunday at 11pm or similar) based on unix cron&lt;br /&gt;
* An administration screen in Moodle to allow site administrators to adjust the scheduling of individual tasks&lt;br /&gt;
* An easy way for core and module code to schedule a once off task to be run as soon as possible&lt;br /&gt;
&lt;br /&gt;
== Approach ==&lt;br /&gt;
&lt;br /&gt;
=== Plugin cron registration ===&lt;br /&gt;
&lt;br /&gt;
Each plugin will be able to provide a db/tasks.php (alongside access.php and events.php etc) that lists all the cronjobs that it wants to have run.  This will look something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$tasks = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;function&#039;    =&amp;gt; &#039;yourmodule_cron_somedescription&#039;,&lt;br /&gt;
        &#039;minute&#039;      =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;hour&#039;        =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;day&#039;         =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;month&#039;       =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;dayofweek&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;langstringkey&#039;, // this must correspond to get_string(&#039;langstringkey&#039;, &#039;yourmodule&#039;);&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields are the same as normal unix cron, with the exception that you cannot use 3 letter words for the month and day of week fields like you can for unix cron.  The following is straight from the unix manpage about cron:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
              field          allowed values&lt;br /&gt;
              -----          --------------&lt;br /&gt;
              minute         0-59&lt;br /&gt;
              hour           0-23&lt;br /&gt;
              day of month   1-31&lt;br /&gt;
              month          1-12 (or names, see below)&lt;br /&gt;
              day of week    0-7 (0 or 7 is Sun, or use names)&lt;br /&gt;
&lt;br /&gt;
       A field may be an asterisk (*), which always stands for ``first-last&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Ranges  of  numbers  are  allowed.  Ranges are two numbers separated with a hyphen.&lt;br /&gt;
       The specified range is inclusive.  For example, 8-11 for an ``hours&#039;&#039; entry specifies&lt;br /&gt;
       execution at hours 8, 9, 10 and 11.&lt;br /&gt;
&lt;br /&gt;
       Lists are allowed.  A list is a set of numbers (or ranges) separated by commas.&lt;br /&gt;
       Examples: ``1,2,5,9&#039;&#039;, ``0-4,8-12&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Step values can be used in conjunction with ranges.  Following a range with ``/&amp;lt;number&amp;gt;&#039;&#039;&lt;br /&gt;
       specifies  skips  of  the  number&#039;s  value  through  the  range.   For  example,&lt;br /&gt;
       ``0-23/2&#039;&#039; can be used in the hours field to specify command execution every other hour&lt;br /&gt;
       (the alternative in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22&#039;&#039;).  Steps&lt;br /&gt;
       are also permitted after an asterisk, so if you want to say ``every two hours&#039;&#039;, just use ``*/2&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The unix crontab manpage goes on to say that one can use 3 letter words in the month and dayofweek fields (eg Sun or Feb).  I don&#039;t think this is necessary for our implementation.&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|lastruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|-&lt;br /&gt;
|minute&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|hour&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|day&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|month&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|dayofweek&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|customised&lt;br /&gt;
|integer(1)&lt;br /&gt;
|0 or 1 - whether this time differs from what is in code&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This table is for all the normal scheduled regular tasks.  The time fields are intially populated when a plugin is installed or upgraded, but can be overridden by an administrator, which sets the &amp;quot;customised&amp;quot; flag to 1.  If the administrator later decides to revert their customisation, the original code-values are repopulated into this table.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_onceoff_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|customdata&lt;br /&gt;
|text&lt;br /&gt;
|any data or serialised information&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This table is for the once off tasks, which are run and then deleted.  There isn&#039;t a unique constraint on &#039;callfunction&#039; in this table, because the same once off task may be scheduled twice before the first one is processed.  In this case, the named lock will be obtained using a combination of callfunction and the id.&lt;br /&gt;
&lt;br /&gt;
The original database specification had extra custom fields in the main scheduled_tasks table, that the cronjobs could insert information into, called custom1 and custom2 and so on.  I&#039;ve removed these from this specification until such time as we have a solid use-case for them.  It is certain that we need it for the once off tasks, however, but in this case I think it&#039;s better to just have a text field that can either contain a single value, or a serialised blob of information.&lt;br /&gt;
&lt;br /&gt;
The original spec also had a priority field, but this has been removed after the conversation in Jizerka, which led to the proposal to just let some jobs block all others, rather than prioritising individual tasks.  &#039;&#039;&#039;This decision may be later reverted&#039;&#039;&#039; especially for once off tasks, where some may be really urgent.&lt;br /&gt;
&lt;br /&gt;
=== Locking ===&lt;br /&gt;
&lt;br /&gt;
Penny and Tim originally thought that the best approach was to try and do something that would cause an exception to be thrown - for example, try to insert into a row that had a unique constraint on it, and catch the exception.  However, this will cause far too much noise in the logs.  Matt Oquist came up with a different approach in MDL-21110.  We could potentially change this slightly to allow alternative implementations, by means of an abstract class and factory method (this was suggested by Sam Marshall), but probaby isn&#039;t needed for the initial implementation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Black magic ===&lt;br /&gt;
&lt;br /&gt;
Cron.php will need to be rewritten to look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
while ($nexttask = cron_get_next_task()) {&lt;br /&gt;
    cron_call_function($nexttask);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some black magic to hand out the next task, which does:&lt;br /&gt;
&lt;br /&gt;
* Checks how long the existing process is allowed to run for&lt;br /&gt;
* Figures out if there&#039;s already a &amp;quot;blocking&amp;quot; task running&lt;br /&gt;
* Figures out the next task that&#039;s scheduled&lt;br /&gt;
* Tries to get a lock on it&lt;br /&gt;
* Returns that task&lt;br /&gt;
&lt;br /&gt;
== Unresolved issues/ideas ==&lt;br /&gt;
&lt;br /&gt;
* It might be nice at some point to find a way to allow different subtasks to run on different servers by designation.  This could be eventually added in to the administration screens as an extra setting (IP address)&lt;br /&gt;
* We obviously need some way to avoid different tasks trampling on eachother.  We ran through a number of ideas already, from differentiating between read/write operations, to having dependencies or conflicts between tasks, to having each task say which database tables it uses.   Finally we decided it would be best to just have some tasks that are able to simply block all others from being run.  Anything to do with authentication and enrolment must block other tasks from running, as otherwise there could be the problem of for example, forum posts being emailed out just before someone is unenrolled from a course.&lt;br /&gt;
* When the first cron in a long time is running, we should lock the entire cron and let it run to completeness, because the order is really important then.  This means that there also needs to be some global lastcronruntime flag somewhere (like in the config table)&lt;br /&gt;
&lt;br /&gt;
== Psuedo code proposal ==&lt;br /&gt;
Moved [[Development_talk:Scheduled_Tasks_Proposal|to the talk page]]&lt;br /&gt;
&lt;br /&gt;
== Audit of current cron ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Main section&lt;br /&gt;
! Subtask&lt;br /&gt;
! Frequency&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| session_gc&lt;br /&gt;
|&lt;br /&gt;
| every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|plugins (none)&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|message submissions&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update chat times&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update_events&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old chat_users and add quits&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old messages&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/data&lt;br /&gt;
|&lt;br /&gt;
|every minute&lt;br /&gt;
|no _cron function (includes file unnecessarily)&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|mail posts&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|digest processing&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|delete old read tracking&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/scorm&lt;br /&gt;
|reparse all scorms&lt;br /&gt;
|every five minutes&lt;br /&gt;
|does hourly checking&lt;br /&gt;
|-&lt;br /&gt;
|mod/wiki&lt;br /&gt;
|delete expired locks&lt;br /&gt;
|every hour&lt;br /&gt;
|-&lt;br /&gt;
|blocks/rss_client&lt;br /&gt;
|update feeds&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|quiz/report/statistics&lt;br /&gt;
|delete old statistics&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admin/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|language_cache&lt;br /&gt;
&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|remove expired enrolments&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|lock pending grades (*2)&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|clean old grade history&lt;br /&gt;
|every run&lt;br /&gt;
|has a TODO to not process as often&lt;br /&gt;
|-&lt;br /&gt;
|event queue&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|portfolio cron&lt;br /&gt;
|clean expired exports&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|longtimenosee&lt;br /&gt;
&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteunconfirmedusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteincompleteusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteoldlogs&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deletefiltercache&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|notifyloginfailures&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|metacourse syncing&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|createpasswordemails&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|tag cron&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|clean contexts&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|gc_cache_flags&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|build_context_path&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|scheduled backups&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|make rss feeds&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|keepalives&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|delete old sessions&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/ldap&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/cas&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/db&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|clears old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|notifies administrators of old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|process orders &amp;amp; email teachers&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/flatfile&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/imsenterprise&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/manual&lt;br /&gt;
|notify people of pending unenrolments&lt;br /&gt;
|daily&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|statistics&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|huge&lt;br /&gt;
|-&lt;br /&gt;
|grade/import&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/export&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|fetch blog entries&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|file gc&lt;br /&gt;
|&lt;br /&gt;
|(optional) daily, else every run?&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|local cron&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
* Audit all existing cronjobs (done)&lt;br /&gt;
* Implement the locking code, either Matt&#039;s or something similar and write robust tests for it (this will be hard to test perhaps - can we test race conditions using simpletest?)&lt;br /&gt;
* Write the black magic that hands out the next task to be run for a given cron process&lt;br /&gt;
* Rewrite cron.php to use the black magic&lt;br /&gt;
* Migrate all the existing cronjobs to the new system&lt;br /&gt;
* Write screens to allow administrators to reschedule tasks&lt;br /&gt;
* Write code to transfer between unix-cron-syntax and user-friendly syntax (and vice versa)&lt;br /&gt;
* Test thoroughly&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== TODO ==&lt;br /&gt;
&lt;br /&gt;
* This doesn&#039;t include a way to schedule new immediate tasks yet (something like scheduled_tasks_asap table)&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66914</id>
		<title>Development:Scheduled Tasks Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66914"/>
		<updated>2010-01-05T21:33:30Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This proposal is meant both to provide a replacement for the moodle cron job, and provide a means to schedule once off tasks to be run outside of the user&#039;s request lifecycle.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Subtask&#039;&#039;&#039; an individual piece of cron processing that should be run (equivalent to forum_cron now, or maybe even smaller)&lt;br /&gt;
* &#039;&#039;&#039;Moodle cron instance&#039;&#039;&#039; a cron.php process&lt;br /&gt;
&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The moodle cronjob currently delegates all scheduling to each subtask that is run - for example, the forum cron is responsible for checking when it last run, and making decisions about whether or not it should be run again.   This sort of decision process should be centralised, and individual cron subtasks should be called by the central controller.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is not any central locking of subtasks.  At the moment, some subtasks that expect that they might take a long time to run implement their own locking (for example statistics), but it&#039;s not centralised.  Each moodle cron instance runs to completion, no matter how long it takes, and it processes tasks in the order that they&#039;re programmed, regardless of if there are any other moodle cron instances running, that might be processing sub tasks in parallel&lt;br /&gt;
&lt;br /&gt;
The existing events API seems like it should provide a way to schedule tasks to be run outside of a user&#039;s request cycle, but in reality this just adds to the existing cron problem.  We need to have a way in Moodle to schedule once off tasks to be run &amp;quot;at the next available time&amp;quot; which are picked up by cron.  This can be used to process the event queue, but also for some code to just register a new once off cron event &amp;quot;on the fly&amp;quot; and be picked up on the next run.&lt;br /&gt;
&lt;br /&gt;
Finally, we need to be able to run non-related tasks in parallel so that the entire moodle queue isn&#039;t held up by single long running jobs.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Centralised locking for &#039;&#039;&#039;all&#039;&#039;&#039; tasks&lt;br /&gt;
* A way consistent for &#039;&#039;&#039;all plugin types&#039;&#039;&#039; to register with Moodle (at installation/upgrade) when they want their jobs run&lt;br /&gt;
* More sophisticated scheduling rather than just intervals in seconds (eg every sunday at 11pm or similar) based on unix cron&lt;br /&gt;
* An administration screen in Moodle to allow site administrators to adjust the scheduling of individual tasks&lt;br /&gt;
* An easy way for core and module code to schedule a once off task to be run as soon as possible&lt;br /&gt;
&lt;br /&gt;
== Approach ==&lt;br /&gt;
&lt;br /&gt;
=== Plugin cron registration ===&lt;br /&gt;
&lt;br /&gt;
Each plugin will be able to provide a db/tasks.php (alongside access.php and events.php etc) that lists all the cronjobs that it wants to have run.  This will look something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$tasks = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;function&#039;    =&amp;gt; &#039;yourmodule_cron_somedescription&#039;,&lt;br /&gt;
        &#039;minute&#039;      =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;hour&#039;        =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;day&#039;         =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;month&#039;       =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;dayofweek&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;langstringkey&#039;, // this must correspond to get_string(&#039;langstringkey&#039;, &#039;yourmodule&#039;);&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields are the same as normal unix cron, with the exception that you cannot use 3 letter words for the month and day of week fields like you can for unix cron.  The following is straight from the unix manpage about cron:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
              field          allowed values&lt;br /&gt;
              -----          --------------&lt;br /&gt;
              minute         0-59&lt;br /&gt;
              hour           0-23&lt;br /&gt;
              day of month   1-31&lt;br /&gt;
              month          1-12 (or names, see below)&lt;br /&gt;
              day of week    0-7 (0 or 7 is Sun, or use names)&lt;br /&gt;
&lt;br /&gt;
       A field may be an asterisk (*), which always stands for ``first-last&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Ranges  of  numbers  are  allowed.  Ranges are two numbers separated with a hyphen.&lt;br /&gt;
       The specified range is inclusive.  For example, 8-11 for an ``hours&#039;&#039; entry specifies&lt;br /&gt;
       execution at hours 8, 9, 10 and 11.&lt;br /&gt;
&lt;br /&gt;
       Lists are allowed.  A list is a set of numbers (or ranges) separated by commas.&lt;br /&gt;
       Examples: ``1,2,5,9&#039;&#039;, ``0-4,8-12&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Step values can be used in conjunction with ranges.  Following a range with ``/&amp;lt;number&amp;gt;&#039;&#039;&lt;br /&gt;
       specifies  skips  of  the  number&#039;s  value  through  the  range.   For  example,&lt;br /&gt;
       ``0-23/2&#039;&#039; can be used in the hours field to specify command execution every other hour&lt;br /&gt;
       (the alternative in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22&#039;&#039;).  Steps&lt;br /&gt;
       are also permitted after an asterisk, so if you want to say ``every two hours&#039;&#039;, just use ``*/2&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The unix crontab manpage goes on to say that one can use 3 letter words in the month and dayofweek fields (eg Sun or Feb).  I don&#039;t think this is necessary for our implementation.&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|lastruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|-&lt;br /&gt;
|defaultminute&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaulthour&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaultday&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaultmonth&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaultdayofweek&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminminute&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminhour&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminday&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminmonth&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admindayofweek&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The difference between &amp;quot;admin&amp;quot; and &amp;quot;default&amp;quot; fields is that the default ones are what the code says when it registers the cronjobs, and the admin ones are the values that have been overridden by site administrators.  It may be cleaner to do this in a separate table and use a left join.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The original database specification had extra custom fields that the cronjobs could insert information into, called custom1 and custom2 and so on.  I&#039;ve removed these from this specification until such time as we have a solid use-case for them.&lt;br /&gt;
&lt;br /&gt;
The original spec also had a priority field, but this has been removed after the conversation in Jizerka, which led to the proposal to just let some core jobs block all others, rather than prioritising individual tasks.&lt;br /&gt;
&lt;br /&gt;
=== Locking ===&lt;br /&gt;
&lt;br /&gt;
Penny and Tim originally thought that the best approach was to try and do something that would cause an exception to be thrown - for example, try to insert into a row that had a unique constraint on it, and catch the exception.  However, this will cause far too much noise in the logs.  Matt Oquist came up with a different approach in MDL-21110.  We could potentially change this slightly to allow alternative implementations, by means of an abstract class and factory method (this was suggested by Sam Marshall), but probaby isn&#039;t needed for the initial implementation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Black magic ===&lt;br /&gt;
&lt;br /&gt;
Cron.php will need to be rewritten to look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
while ($nexttask = cron_get_next_task()) {&lt;br /&gt;
    cron_call_function($nexttask);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some black magic to hand out the next task, which does:&lt;br /&gt;
&lt;br /&gt;
* Checks how long the existing process is allowed to run for&lt;br /&gt;
* Figures out if there&#039;s already a &amp;quot;blocking&amp;quot; task running&lt;br /&gt;
* Figures out the next task that&#039;s scheduled&lt;br /&gt;
* Tries to get a lock on it&lt;br /&gt;
* Returns that task&lt;br /&gt;
&lt;br /&gt;
== Unresolved issues/ideas ==&lt;br /&gt;
&lt;br /&gt;
* It might be nice at some point to find a way to allow different subtasks to run on different servers by designation.  This could be eventually added in to the administration screens as an extra setting (IP address)&lt;br /&gt;
* We obviously need some way to avoid different tasks trampling on eachother.  We ran through a number of ideas already, from differentiating between read/write operations, to having dependencies or conflicts between tasks, to having each task say which database tables it uses.   Finally we decided it would be best to just have some tasks that are able to simply block all others from being run.  Anything to do with authentication and enrolment must block other tasks from running, as otherwise there could be the problem of for example, forum posts being emailed out just before someone is unenrolled from a course.&lt;br /&gt;
* When the first cron in a long time is running, we should lock the entire cron and let it run to completeness, because the order is really important then.  This means that there also needs to be some global lastcronruntime flag somewhere (like in the config table)&lt;br /&gt;
&lt;br /&gt;
== Psuedo code proposal ==&lt;br /&gt;
Moved [[Development_talk:Scheduled_Tasks_Proposal|to the talk page]]&lt;br /&gt;
&lt;br /&gt;
== Audit of current cron ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Main section&lt;br /&gt;
! Subtask&lt;br /&gt;
! Frequency&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| session_gc&lt;br /&gt;
|&lt;br /&gt;
| every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|plugins (none)&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|message submissions&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update chat times&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update_events&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old chat_users and add quits&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old messages&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/data&lt;br /&gt;
|&lt;br /&gt;
|every minute&lt;br /&gt;
|no _cron function (includes file unnecessarily)&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|mail posts&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|digest processing&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|delete old read tracking&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/scorm&lt;br /&gt;
|reparse all scorms&lt;br /&gt;
|every five minutes&lt;br /&gt;
|does hourly checking&lt;br /&gt;
|-&lt;br /&gt;
|mod/wiki&lt;br /&gt;
|delete expired locks&lt;br /&gt;
|every hour&lt;br /&gt;
|-&lt;br /&gt;
|blocks/rss_client&lt;br /&gt;
|update feeds&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|quiz/report/statistics&lt;br /&gt;
|delete old statistics&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admin/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|language_cache&lt;br /&gt;
&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|remove expired enrolments&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|lock pending grades (*2)&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|clean old grade history&lt;br /&gt;
|every run&lt;br /&gt;
|has a TODO to not process as often&lt;br /&gt;
|-&lt;br /&gt;
|event queue&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|portfolio cron&lt;br /&gt;
|clean expired exports&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|longtimenosee&lt;br /&gt;
&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteunconfirmedusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteincompleteusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteoldlogs&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deletefiltercache&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|notifyloginfailures&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|metacourse syncing&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|createpasswordemails&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|tag cron&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|clean contexts&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|gc_cache_flags&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|build_context_path&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|scheduled backups&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|make rss feeds&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|keepalives&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|delete old sessions&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/ldap&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/cas&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/db&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|clears old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|notifies administrators of old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|process orders &amp;amp; email teachers&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/flatfile&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/imsenterprise&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/manual&lt;br /&gt;
|notify people of pending unenrolments&lt;br /&gt;
|daily&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|statistics&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|huge&lt;br /&gt;
|-&lt;br /&gt;
|grade/import&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/export&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|fetch blog entries&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|file gc&lt;br /&gt;
|&lt;br /&gt;
|(optional) daily, else every run?&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|local cron&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
* Audit all existing cronjobs (done)&lt;br /&gt;
* Implement the locking code, either Matt&#039;s or something similar and write robust tests for it (this will be hard to test perhaps - can we test race conditions using simpletest?)&lt;br /&gt;
* Write the black magic that hands out the next task to be run for a given cron process&lt;br /&gt;
* Rewrite cron.php to use the black magic&lt;br /&gt;
* Migrate all the existing cronjobs to the new system&lt;br /&gt;
* Write screens to allow administrators to reschedule tasks&lt;br /&gt;
* Write code to transfer between unix-cron-syntax and user-friendly syntax (and vice versa)&lt;br /&gt;
* Test thoroughly&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== TODO ==&lt;br /&gt;
&lt;br /&gt;
* This doesn&#039;t include a way to schedule new immediate tasks yet (something like scheduled_tasks_asap table)&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66912</id>
		<title>Development:Scheduled Tasks Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66912"/>
		<updated>2010-01-05T20:51:30Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Terminology */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This proposal is meant both to provide a replacement for the moodle cron job, and provide a means to schedule once off tasks to be run outside of the user&#039;s request lifecycle.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Subtask&#039;&#039;&#039; an individual piece of cron processing that should be run (equivalent to forum_cron now, or maybe even smaller)&lt;br /&gt;
* &#039;&#039;&#039;Moodle cron instance&#039;&#039;&#039; a cron.php process&lt;br /&gt;
&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The moodle cronjob currently delegates all scheduling to each subtask that is run - for example, the forum cron is responsible for checking when it last run, and making decisions about whether or not it should be run again.   This sort of decision process should be centralised, and individual cron subtasks should be called by the central controller.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is not any central locking of subtasks.  At the moment, some subtasks that expect that they might take a long time to run implement their own locking (for example statistics), but it&#039;s not centralised.  Each moodle cron instance runs to completion, no matter how long it takes, and it processes tasks in the order that they&#039;re programmed, regardless of if there are any other moodle cron instances running, that might be processing sub tasks in parallel&lt;br /&gt;
&lt;br /&gt;
Finally, we need to be able to run non-related tasks in parallel so that the entire moodle queue isn&#039;t held up by single long running jobs.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Centralised locking for &#039;&#039;&#039;all&#039;&#039;&#039; tasks&lt;br /&gt;
* A way consistent for &#039;&#039;&#039;all plugin types&#039;&#039;&#039; to register with Moodle (at installation/upgrade) when they want their jobs run&lt;br /&gt;
* More sophisticated scheduling rather than just intervals in seconds (eg every sunday at 11pm or similar) based on unix cron&lt;br /&gt;
* An administration screen in Moodle to allow site administrators to adjust the scheduling of individual tasks&lt;br /&gt;
&lt;br /&gt;
== Approach ==&lt;br /&gt;
&lt;br /&gt;
=== Plugin cron registration ===&lt;br /&gt;
&lt;br /&gt;
Each plugin will be able to provide a db/tasks.php (alongside access.php and events.php etc) that lists all the cronjobs that it wants to have run.  This will look something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$tasks = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;function&#039;    =&amp;gt; &#039;yourmodule_cron_somedescription&#039;,&lt;br /&gt;
        &#039;minute&#039;      =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;hour&#039;        =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;day&#039;         =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;month&#039;       =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;dayofweek&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;langstringkey&#039;, // this must correspond to get_string(&#039;langstringkey&#039;, &#039;yourmodule&#039;);&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields are the same as normal unix cron, with the exception that you cannot use 3 letter words for the month and day of week fields like you can for unix cron.  The following is straight from the unix manpage about cron:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
              field          allowed values&lt;br /&gt;
              -----          --------------&lt;br /&gt;
              minute         0-59&lt;br /&gt;
              hour           0-23&lt;br /&gt;
              day of month   1-31&lt;br /&gt;
              month          1-12 (or names, see below)&lt;br /&gt;
              day of week    0-7 (0 or 7 is Sun, or use names)&lt;br /&gt;
&lt;br /&gt;
       A field may be an asterisk (*), which always stands for ``first-last&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Ranges  of  numbers  are  allowed.  Ranges are two numbers separated with a hyphen.&lt;br /&gt;
       The specified range is inclusive.  For example, 8-11 for an ``hours&#039;&#039; entry specifies&lt;br /&gt;
       execution at hours 8, 9, 10 and 11.&lt;br /&gt;
&lt;br /&gt;
       Lists are allowed.  A list is a set of numbers (or ranges) separated by commas.&lt;br /&gt;
       Examples: ``1,2,5,9&#039;&#039;, ``0-4,8-12&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Step values can be used in conjunction with ranges.  Following a range with ``/&amp;lt;number&amp;gt;&#039;&#039;&lt;br /&gt;
       specifies  skips  of  the  number&#039;s  value  through  the  range.   For  example,&lt;br /&gt;
       ``0-23/2&#039;&#039; can be used in the hours field to specify command execution every other hour&lt;br /&gt;
       (the alternative in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22&#039;&#039;).  Steps&lt;br /&gt;
       are also permitted after an asterisk, so if you want to say ``every two hours&#039;&#039;, just use ``*/2&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|lastruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|-&lt;br /&gt;
|defaultminute&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaulthour&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaultday&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaultmonth&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaultdayofweek&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminminute&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminhour&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminday&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminmonth&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admindayofweek&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The difference between &amp;quot;admin&amp;quot; and &amp;quot;default&amp;quot; fields is that the default ones are what the code says, and the admin ones are the values that have been overridden by site administrators.  It may be cleaner to do this in a separate table and use a left join.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The original database specification had extra custom fields that the cronjobs could insert information into, called custom1 and custom2 and so on.  I&#039;ve removed these from this specification until such time as we have a solid use-case for them.  The original spec also had a priority field, but this has been removed after the conversation in Jizerka, which led to the proposal to just let some core jobs block all others, rather than prioritising individual tasks.&lt;br /&gt;
&lt;br /&gt;
=== Locking ===&lt;br /&gt;
&lt;br /&gt;
Penny and Tim originally thought that the best approach was to try and do something that would cause an exception to be thrown - for example, try to insert into a row that had a unique constraint on it, and catch the exception.  However, this will cause far too much noise in the logs.  Matt Oquist came up with a different approach in MDL-21110.  We could potentially change this slightly to allow alternative implementations, by means of an abstract class and factory method (this was suggested by Sam Marshall), but probaby isn&#039;t needed for the initial implementation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Black magic ===&lt;br /&gt;
&lt;br /&gt;
Cron.php will need to be rewritten to look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
while ($nexttask = cron_get_next_task()) {&lt;br /&gt;
    cron_call_function($nexttask);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some black magic to hand out the next task, which does:&lt;br /&gt;
&lt;br /&gt;
* Checks how long the existing process is allowed to run for&lt;br /&gt;
* Figures out if there&#039;s already a &amp;quot;blocking&amp;quot; task running&lt;br /&gt;
* Figures out the next task that&#039;s scheduled&lt;br /&gt;
* Tries to get a lock on it&lt;br /&gt;
* Returns that task&lt;br /&gt;
&lt;br /&gt;
== Unresolved issues/ideas ==&lt;br /&gt;
&lt;br /&gt;
* Do we need to allow for scheduling different subtasks on different servers?&lt;br /&gt;
* We need to find a way to separate subtasks by some logic so that subtasks that write to the same areas of the database never run at the same time.  We could do this by getting each cron job to say what areas of Moodle they write to, but this is problematic.&lt;br /&gt;
* We also have to deal with the order of some subtasks - we could maybe do this by introducing dependencies&lt;br /&gt;
* When the first cron in a long time is running, we should lock the entire cron and let it run to completeness, because the order is really important then.&lt;br /&gt;
&lt;br /&gt;
== Psuedo code proposal ==&lt;br /&gt;
Moved [[Development_talk:Scheduled_Tasks_Proposal|to the talk page]]&lt;br /&gt;
&lt;br /&gt;
== Audit of current cron ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Main section&lt;br /&gt;
! Subtask&lt;br /&gt;
! Frequency&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| session_gc&lt;br /&gt;
|&lt;br /&gt;
| every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|plugins (none)&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|message submissions&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update chat times&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update_events&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old chat_users and add quits&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old messages&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/data&lt;br /&gt;
|&lt;br /&gt;
|every minute&lt;br /&gt;
|no _cron function (includes file unnecessarily)&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|mail posts&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|digest processing&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|delete old read tracking&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/scorm&lt;br /&gt;
|reparse all scorms&lt;br /&gt;
|every five minutes&lt;br /&gt;
|does hourly checking&lt;br /&gt;
|-&lt;br /&gt;
|mod/wiki&lt;br /&gt;
|delete expired locks&lt;br /&gt;
|every hour&lt;br /&gt;
|-&lt;br /&gt;
|blocks/rss_client&lt;br /&gt;
|update feeds&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|quiz/report/statistics&lt;br /&gt;
|delete old statistics&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admin/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|language_cache&lt;br /&gt;
&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|remove expired enrolments&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|lock pending grades (*2)&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|clean old grade history&lt;br /&gt;
|every run&lt;br /&gt;
|has a TODO to not process as often&lt;br /&gt;
|-&lt;br /&gt;
|event queue&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|portfolio cron&lt;br /&gt;
|clean expired exports&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|longtimenosee&lt;br /&gt;
&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteunconfirmedusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteincompleteusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteoldlogs&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deletefiltercache&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|notifyloginfailures&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|metacourse syncing&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|createpasswordemails&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|tag cron&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|clean contexts&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|gc_cache_flags&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|build_context_path&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|scheduled backups&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|make rss feeds&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|keepalives&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|delete old sessions&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/ldap&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/cas&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/db&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|clears old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|notifies administrators of old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|process orders &amp;amp; email teachers&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/flatfile&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/imsenterprise&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/manual&lt;br /&gt;
|notify people of pending unenrolments&lt;br /&gt;
|daily&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|statistics&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|huge&lt;br /&gt;
|-&lt;br /&gt;
|grade/import&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/export&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|fetch blog entries&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|file gc&lt;br /&gt;
|&lt;br /&gt;
|(optional) daily, else every run?&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|local cron&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
* Audit all existing cronjobs (done)&lt;br /&gt;
* Implement the locking code, either Matt&#039;s or something similar and write robust tests for it (this will be hard to test perhaps - can we test race conditions using simpletest?)&lt;br /&gt;
* Write the black magic that hands out the next task to be run for a given cron process&lt;br /&gt;
* Rewrite cron.php to use the black magic&lt;br /&gt;
* Migrate all the existing cronjobs to the new system&lt;br /&gt;
* Write screens to allow administrators to reschedule tasks&lt;br /&gt;
* Write code to transfer between unix-cron-syntax and user-friendly syntax (and vice versa)&lt;br /&gt;
* Test thoroughly&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== TODO ==&lt;br /&gt;
&lt;br /&gt;
* This doesn&#039;t include a way to schedule new immediate tasks yet (something like scheduled_tasks_asap table)&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66876</id>
		<title>Development:Scheduled Tasks Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66876"/>
		<updated>2010-01-05T05:41:24Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This proposal is meant both to provide a replacement for the moodle cron job, and provide a means to schedule once off tasks to be run outside of the user&#039;s request lifecycle.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
&lt;br /&gt;
* *Subtask* an individual piece of cron processing that should be run (equivalent to forum_cron now, or maybe even smaller)&lt;br /&gt;
* *Moodle cron instance* a cron.php process&lt;br /&gt;
&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The moodle cronjob currently delegates all scheduling to each subtask that is run - for example, the forum cron is responsible for checking when it last run, and making decisions about whether or not it should be run again.   This sort of decision process should be centralised, and individual cron subtasks should be called by the central controller.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is not any central locking of subtasks.  At the moment, some subtasks that expect that they might take a long time to run implement their own locking (for example statistics), but it&#039;s not centralised.  Each moodle cron instance runs to completion, no matter how long it takes, and it processes tasks in the order that they&#039;re programmed, regardless of if there are any other moodle cron instances running, that might be processing sub tasks in parallel&lt;br /&gt;
&lt;br /&gt;
Finally, we need to be able to run non-related tasks in parallel so that the entire moodle queue isn&#039;t held up by single long running jobs.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Centralised locking for &#039;&#039;&#039;all&#039;&#039;&#039; tasks&lt;br /&gt;
* A way consistent for &#039;&#039;&#039;all plugin types&#039;&#039;&#039; to register with Moodle (at installation/upgrade) when they want their jobs run&lt;br /&gt;
* More sophisticated scheduling rather than just intervals in seconds (eg every sunday at 11pm or similar) based on unix cron&lt;br /&gt;
* An administration screen in Moodle to allow site administrators to adjust the scheduling of individual tasks&lt;br /&gt;
&lt;br /&gt;
== Approach ==&lt;br /&gt;
&lt;br /&gt;
=== Plugin cron registration ===&lt;br /&gt;
&lt;br /&gt;
Each plugin will be able to provide a db/tasks.php (alongside access.php and events.php etc) that lists all the cronjobs that it wants to have run.  This will look something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$tasks = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;function&#039;    =&amp;gt; &#039;yourmodule_cron_somedescription&#039;,&lt;br /&gt;
        &#039;minute&#039;      =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;hour&#039;        =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;day&#039;         =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;month&#039;       =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;dayofweek&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;langstringkey&#039;, // this must correspond to get_string(&#039;langstringkey&#039;, &#039;yourmodule&#039;);&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields are the same as normal unix cron, with the exception that you cannot use 3 letter words for the month and day of week fields like you can for unix cron.  The following is straight from the unix manpage about cron:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
              field          allowed values&lt;br /&gt;
              -----          --------------&lt;br /&gt;
              minute         0-59&lt;br /&gt;
              hour           0-23&lt;br /&gt;
              day of month   1-31&lt;br /&gt;
              month          1-12 (or names, see below)&lt;br /&gt;
              day of week    0-7 (0 or 7 is Sun, or use names)&lt;br /&gt;
&lt;br /&gt;
       A field may be an asterisk (*), which always stands for ``first-last&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Ranges  of  numbers  are  allowed.  Ranges are two numbers separated with a hyphen.&lt;br /&gt;
       The specified range is inclusive.  For example, 8-11 for an ``hours&#039;&#039; entry specifies&lt;br /&gt;
       execution at hours 8, 9, 10 and 11.&lt;br /&gt;
&lt;br /&gt;
       Lists are allowed.  A list is a set of numbers (or ranges) separated by commas.&lt;br /&gt;
       Examples: ``1,2,5,9&#039;&#039;, ``0-4,8-12&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Step values can be used in conjunction with ranges.  Following a range with ``/&amp;lt;number&amp;gt;&#039;&#039;&lt;br /&gt;
       specifies  skips  of  the  number&#039;s  value  through  the  range.   For  example,&lt;br /&gt;
       ``0-23/2&#039;&#039; can be used in the hours field to specify command execution every other hour&lt;br /&gt;
       (the alternative in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22&#039;&#039;).  Steps&lt;br /&gt;
       are also permitted after an asterisk, so if you want to say ``every two hours&#039;&#039;, just use ``*/2&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|lastruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|-&lt;br /&gt;
|defaultminute&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaulthour&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaultday&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaultmonth&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaultdayofweek&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminminute&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminhour&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminday&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminmonth&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admindayofweek&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The difference between &amp;quot;admin&amp;quot; and &amp;quot;default&amp;quot; fields is that the default ones are what the code says, and the admin ones are the values that have been overridden by site administrators.  It may be cleaner to do this in a separate table and use a left join.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The original database specification had extra custom fields that the cronjobs could insert information into, called custom1 and custom2 and so on.  I&#039;ve removed these from this specification until such time as we have a solid use-case for them.  The original spec also had a priority field, but this has been removed after the conversation in Jizerka, which led to the proposal to just let some core jobs block all others, rather than prioritising individual tasks.&lt;br /&gt;
&lt;br /&gt;
=== Locking ===&lt;br /&gt;
&lt;br /&gt;
Penny and Tim originally thought that the best approach was to try and do something that would cause an exception to be thrown - for example, try to insert into a row that had a unique constraint on it, and catch the exception.  However, this will cause far too much noise in the logs.  Matt Oquist came up with a different approach in MDL-21110.  We could potentially change this slightly to allow alternative implementations, by means of an abstract class and factory method (this was suggested by Sam Marshall), but probaby isn&#039;t needed for the initial implementation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Black magic ===&lt;br /&gt;
&lt;br /&gt;
Cron.php will need to be rewritten to look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
while ($nexttask = cron_get_next_task()) {&lt;br /&gt;
    cron_call_function($nexttask);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some black magic to hand out the next task, which does:&lt;br /&gt;
&lt;br /&gt;
* Checks how long the existing process is allowed to run for&lt;br /&gt;
* Figures out if there&#039;s already a &amp;quot;blocking&amp;quot; task running&lt;br /&gt;
* Figures out the next task that&#039;s scheduled&lt;br /&gt;
* Tries to get a lock on it&lt;br /&gt;
* Returns that task&lt;br /&gt;
&lt;br /&gt;
== Unresolved issues/ideas ==&lt;br /&gt;
&lt;br /&gt;
* Do we need to allow for scheduling different subtasks on different servers?&lt;br /&gt;
* We need to find a way to separate subtasks by some logic so that subtasks that write to the same areas of the database never run at the same time.  We could do this by getting each cron job to say what areas of Moodle they write to, but this is problematic.&lt;br /&gt;
* We also have to deal with the order of some subtasks - we could maybe do this by introducing dependencies&lt;br /&gt;
* When the first cron in a long time is running, we should lock the entire cron and let it run to completeness, because the order is really important then.&lt;br /&gt;
&lt;br /&gt;
== Psuedo code proposal ==&lt;br /&gt;
Moved [[Development_talk:Scheduled_Tasks_Proposal|to the talk page]]&lt;br /&gt;
&lt;br /&gt;
== Audit of current cron ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Main section&lt;br /&gt;
! Subtask&lt;br /&gt;
! Frequency&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| session_gc&lt;br /&gt;
|&lt;br /&gt;
| every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|plugins (none)&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|message submissions&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update chat times&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update_events&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old chat_users and add quits&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old messages&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/data&lt;br /&gt;
|&lt;br /&gt;
|every minute&lt;br /&gt;
|no _cron function (includes file unnecessarily)&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|mail posts&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|digest processing&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|delete old read tracking&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/scorm&lt;br /&gt;
|reparse all scorms&lt;br /&gt;
|every five minutes&lt;br /&gt;
|does hourly checking&lt;br /&gt;
|-&lt;br /&gt;
|mod/wiki&lt;br /&gt;
|delete expired locks&lt;br /&gt;
|every hour&lt;br /&gt;
|-&lt;br /&gt;
|blocks/rss_client&lt;br /&gt;
|update feeds&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|quiz/report/statistics&lt;br /&gt;
|delete old statistics&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admin/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|language_cache&lt;br /&gt;
&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|remove expired enrolments&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|lock pending grades (*2)&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|clean old grade history&lt;br /&gt;
|every run&lt;br /&gt;
|has a TODO to not process as often&lt;br /&gt;
|-&lt;br /&gt;
|event queue&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|portfolio cron&lt;br /&gt;
|clean expired exports&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|longtimenosee&lt;br /&gt;
&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteunconfirmedusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteincompleteusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteoldlogs&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deletefiltercache&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|notifyloginfailures&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|metacourse syncing&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|createpasswordemails&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|tag cron&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|clean contexts&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|gc_cache_flags&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|build_context_path&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|scheduled backups&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|make rss feeds&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|keepalives&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|delete old sessions&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/ldap&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/cas&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/db&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|clears old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|notifies administrators of old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|process orders &amp;amp; email teachers&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/flatfile&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/imsenterprise&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/manual&lt;br /&gt;
|notify people of pending unenrolments&lt;br /&gt;
|daily&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|statistics&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|huge&lt;br /&gt;
|-&lt;br /&gt;
|grade/import&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/export&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|fetch blog entries&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|file gc&lt;br /&gt;
|&lt;br /&gt;
|(optional) daily, else every run?&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|local cron&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
* Audit all existing cronjobs (done)&lt;br /&gt;
* Implement the locking code, either Matt&#039;s or something similar and write robust tests for it (this will be hard to test perhaps - can we test race conditions using simpletest?)&lt;br /&gt;
* Write the black magic that hands out the next task to be run for a given cron process&lt;br /&gt;
* Rewrite cron.php to use the black magic&lt;br /&gt;
* Migrate all the existing cronjobs to the new system&lt;br /&gt;
* Write screens to allow administrators to reschedule tasks&lt;br /&gt;
* Write code to transfer between unix-cron-syntax and user-friendly syntax (and vice versa)&lt;br /&gt;
* Test thoroughly&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== TODO ==&lt;br /&gt;
&lt;br /&gt;
* This doesn&#039;t include a way to schedule new immediate tasks yet (something like scheduled_tasks_asap table)&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66875</id>
		<title>Development:Scheduled Tasks Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66875"/>
		<updated>2010-01-05T05:28:54Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Database */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This proposal is meant both to provide a replacement for the moodle cron job, and provide a means to schedule once off tasks to be run outside of the user&#039;s request lifecycle.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
&lt;br /&gt;
* *Subtask* an individual piece of cron processing that should be run (equivalent to forum_cron now, or maybe even smaller)&lt;br /&gt;
* *Moodle cron instance* a cron.php process&lt;br /&gt;
&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The moodle cronjob currently delegates all scheduling to each subtask that is run - for example, the forum cron is responsible for checking when it last run, and making decisions about whether or not it should be run again.   This sort of decision process should be centralised, and individual cron subtasks should be called by the central controller.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is not any central locking of subtasks.  At the moment, some subtasks that expect that they might take a long time to run implement their own locking (for example statistics), but it&#039;s not centralised.  Each moodle cron instance runs to completion, no matter how long it takes, and it processes tasks in the order that they&#039;re programmed, regardless of if there are any other moodle cron instances running, that might be processing sub tasks in parallel&lt;br /&gt;
&lt;br /&gt;
Finally, we need to be able to run non-related tasks in parallel so that the entire moodle queue isn&#039;t held up by single long running jobs.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Centralised locking for &#039;&#039;&#039;all&#039;&#039;&#039; tasks&lt;br /&gt;
* A way consistent for &#039;&#039;&#039;all plugin types&#039;&#039;&#039; to register with Moodle (at installation/upgrade) when they want their jobs run&lt;br /&gt;
* More sophisticated scheduling rather than just intervals in seconds (eg every sunday at 11pm or similar) based on unix cron&lt;br /&gt;
* An administration screen in Moodle to allow site administrators to adjust the scheduling of individual tasks&lt;br /&gt;
&lt;br /&gt;
== Approach ==&lt;br /&gt;
&lt;br /&gt;
=== Plugin cron registration ===&lt;br /&gt;
&lt;br /&gt;
Each plugin will be able to provide a db/tasks.php (alongside access.php and events.php etc) that lists all the cronjobs that it wants to have run.  This will look something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$tasks = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;function&#039;    =&amp;gt; &#039;yourmodule_cron_somedescription&#039;,&lt;br /&gt;
        &#039;minute&#039;      =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;hour&#039;        =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;day&#039;         =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;month&#039;       =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;dayofweek&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;langstringkey&#039;, // this must correspond to get_string(&#039;langstringkey&#039;, &#039;yourmodule&#039;);&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields are the same as normal unix cron, with the exception that you cannot use 3 letter words for the month and day of week fields like you can for unix cron.  The following is straight from the unix manpage about cron:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
              field          allowed values&lt;br /&gt;
              -----          --------------&lt;br /&gt;
              minute         0-59&lt;br /&gt;
              hour           0-23&lt;br /&gt;
              day of month   1-31&lt;br /&gt;
              month          1-12 (or names, see below)&lt;br /&gt;
              day of week    0-7 (0 or 7 is Sun, or use names)&lt;br /&gt;
&lt;br /&gt;
       A field may be an asterisk (*), which always stands for ``first-last&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Ranges  of  numbers  are  allowed.  Ranges are two numbers separated with a hyphen.&lt;br /&gt;
       The specified range is inclusive.  For example, 8-11 for an ``hours&#039;&#039; entry specifies&lt;br /&gt;
       execution at hours 8, 9, 10 and 11.&lt;br /&gt;
&lt;br /&gt;
       Lists are allowed.  A list is a set of numbers (or ranges) separated by commas.&lt;br /&gt;
       Examples: ``1,2,5,9&#039;&#039;, ``0-4,8-12&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Step values can be used in conjunction with ranges.  Following a range with ``/&amp;lt;number&amp;gt;&#039;&#039;&lt;br /&gt;
       specifies  skips  of  the  number&#039;s  value  through  the  range.   For  example,&lt;br /&gt;
       ``0-23/2&#039;&#039; can be used in the hours field to specify command execution every other hour&lt;br /&gt;
       (the alternative in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22&#039;&#039;).  Steps&lt;br /&gt;
       are also permitted after an asterisk, so if you want to say ``every two hours&#039;&#039;, just use ``*/2&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|lastruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|-&lt;br /&gt;
|defaultminute&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaulthour&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaultday&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaultmonth&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaultdayofweek&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminminute&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminhour&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminday&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminmonth&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admindayofweek&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The difference between &amp;quot;admin&amp;quot; and &amp;quot;default&amp;quot; fields is that the default ones are what the code says, and the admin ones are the values that have been overridden by site administrators.  It may be cleaner to do this in a separate table and use a left join.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The original database specification had extra custom fields that the cronjobs could insert information into, called custom1 and custom2 and so on.  I&#039;ve removed these from this specification until such time as we have a solid use-case for them.  The original spec also had a priority field, but this has been removed after the conversation in Jizerka, which led to the proposal to just let some core jobs block all others, rather than prioritising individual tasks.&lt;br /&gt;
&lt;br /&gt;
=== Locking ===&lt;br /&gt;
&lt;br /&gt;
Penny and Tim originally thought that the best approach was to try and do something that would cause an exception to be thrown - for example, try to insert into a row that had a unique constraint on it, and catch the exception.  However, this will cause far too much noise in the logs.  Matt Oquist came up with a different approach in MDL-21110.  We could potentially change this slightly to allow alternative implementations, by means of an abstract class and factory method (this was suggested by Sam Marshall), but probaby isn&#039;t needed for the initial implementation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Black magic ===&lt;br /&gt;
&lt;br /&gt;
Cron.php will need to be rewritten to look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
while ($nexttask = cron_get_next_task()) {&lt;br /&gt;
    cron_call_function($nexttask);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some black magic to hand out the next task, which does:&lt;br /&gt;
&lt;br /&gt;
* Checks how long the existing process is allowed to run for&lt;br /&gt;
* Figures out if there&#039;s already a &amp;quot;blocking&amp;quot; task running&lt;br /&gt;
* Figures out the next task that&#039;s scheduled&lt;br /&gt;
* Tries to get a lock on it&lt;br /&gt;
* Returns that task&lt;br /&gt;
&lt;br /&gt;
== Unresolved issues/ideas ==&lt;br /&gt;
&lt;br /&gt;
* Do we need to allow for scheduling different subtasks on different servers?&lt;br /&gt;
* We need to find a way to separate subtasks by some logic so that subtasks that write to the same areas of the database never run at the same time.  We could do this by getting each cron job to say what areas of Moodle they write to, but this is problematic.&lt;br /&gt;
* We also have to deal with the order of some subtasks - we could maybe do this by introducing dependencies&lt;br /&gt;
* When the first cron in a long time is running, we should lock the entire cron and let it run to completeness, because the order is really important then.&lt;br /&gt;
&lt;br /&gt;
== Psuedo code proposal ==&lt;br /&gt;
Moved [[Development_talk:Scheduled_Tasks_Proposal|to the talk page]]&lt;br /&gt;
&lt;br /&gt;
== Audit of current cron ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Main section&lt;br /&gt;
! Subtask&lt;br /&gt;
! Frequency&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| session_gc&lt;br /&gt;
|&lt;br /&gt;
| every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|plugins (none)&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|message submissions&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update chat times&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update_events&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old chat_users and add quits&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old messages&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/data&lt;br /&gt;
|&lt;br /&gt;
|every minute&lt;br /&gt;
|no _cron function (includes file unnecessarily)&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|mail posts&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|digest processing&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|delete old read tracking&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/scorm&lt;br /&gt;
|reparse all scorms&lt;br /&gt;
|every five minutes&lt;br /&gt;
|does hourly checking&lt;br /&gt;
|-&lt;br /&gt;
|mod/wiki&lt;br /&gt;
|delete expired locks&lt;br /&gt;
|every hour&lt;br /&gt;
|-&lt;br /&gt;
|blocks/rss_client&lt;br /&gt;
|update feeds&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|quiz/report/statistics&lt;br /&gt;
|delete old statistics&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admin/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|language_cache&lt;br /&gt;
&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|remove expired enrolments&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|lock pending grades (*2)&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|clean old grade history&lt;br /&gt;
|every run&lt;br /&gt;
|has a TODO to not process as often&lt;br /&gt;
|-&lt;br /&gt;
|event queue&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|portfolio cron&lt;br /&gt;
|clean expired exports&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|longtimenosee&lt;br /&gt;
&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteunconfirmedusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteincompleteusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteoldlogs&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deletefiltercache&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|notifyloginfailures&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|metacourse syncing&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|createpasswordemails&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|tag cron&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|clean contexts&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|gc_cache_flags&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|build_context_path&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|scheduled backups&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|make rss feeds&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|keepalives&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|delete old sessions&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/ldap&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/cas&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/db&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|clears old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|notifies administrators of old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|process orders &amp;amp; email teachers&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/flatfile&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/imsenterprise&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/manual&lt;br /&gt;
|notify people of pending unenrolments&lt;br /&gt;
|daily&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|statistics&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|huge&lt;br /&gt;
|-&lt;br /&gt;
|grade/import&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/export&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|fetch blog entries&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|file gc&lt;br /&gt;
|&lt;br /&gt;
|(optional) daily, else every run?&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|local cron&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
* Audit all existing cronjobs (done)&lt;br /&gt;
* Implement the locking code, either Matt&#039;s or something similar and write robust tests for it (this will be hard to test perhaps - can we test race conditions using simpletest?)&lt;br /&gt;
* Write the black magic that hands out the next task to be run for a given cron process&lt;br /&gt;
* Rewrite cron.php to use the black magic&lt;br /&gt;
* Migrate all the existing cronjobs to the new system&lt;br /&gt;
* Write screens to allow administrators to reschedule tasks&lt;br /&gt;
* Write code to transfer between unix-cron-syntax and user-friendly syntax (and vice versa)&lt;br /&gt;
* Test thoroughly&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66874</id>
		<title>Development:Scheduled Tasks Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66874"/>
		<updated>2010-01-05T05:27:19Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Database */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This proposal is meant both to provide a replacement for the moodle cron job, and provide a means to schedule once off tasks to be run outside of the user&#039;s request lifecycle.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
&lt;br /&gt;
* *Subtask* an individual piece of cron processing that should be run (equivalent to forum_cron now, or maybe even smaller)&lt;br /&gt;
* *Moodle cron instance* a cron.php process&lt;br /&gt;
&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The moodle cronjob currently delegates all scheduling to each subtask that is run - for example, the forum cron is responsible for checking when it last run, and making decisions about whether or not it should be run again.   This sort of decision process should be centralised, and individual cron subtasks should be called by the central controller.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is not any central locking of subtasks.  At the moment, some subtasks that expect that they might take a long time to run implement their own locking (for example statistics), but it&#039;s not centralised.  Each moodle cron instance runs to completion, no matter how long it takes, and it processes tasks in the order that they&#039;re programmed, regardless of if there are any other moodle cron instances running, that might be processing sub tasks in parallel&lt;br /&gt;
&lt;br /&gt;
Finally, we need to be able to run non-related tasks in parallel so that the entire moodle queue isn&#039;t held up by single long running jobs.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Centralised locking for &#039;&#039;&#039;all&#039;&#039;&#039; tasks&lt;br /&gt;
* A way consistent for &#039;&#039;&#039;all plugin types&#039;&#039;&#039; to register with Moodle (at installation/upgrade) when they want their jobs run&lt;br /&gt;
* More sophisticated scheduling rather than just intervals in seconds (eg every sunday at 11pm or similar) based on unix cron&lt;br /&gt;
* An administration screen in Moodle to allow site administrators to adjust the scheduling of individual tasks&lt;br /&gt;
&lt;br /&gt;
== Approach ==&lt;br /&gt;
&lt;br /&gt;
=== Plugin cron registration ===&lt;br /&gt;
&lt;br /&gt;
Each plugin will be able to provide a db/tasks.php (alongside access.php and events.php etc) that lists all the cronjobs that it wants to have run.  This will look something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$tasks = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;function&#039;    =&amp;gt; &#039;yourmodule_cron_somedescription&#039;,&lt;br /&gt;
        &#039;minute&#039;      =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;hour&#039;        =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;day&#039;         =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;month&#039;       =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;dayofweek&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;langstringkey&#039;, // this must correspond to get_string(&#039;langstringkey&#039;, &#039;yourmodule&#039;);&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields are the same as normal unix cron, with the exception that you cannot use 3 letter words for the month and day of week fields like you can for unix cron.  The following is straight from the unix manpage about cron:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
              field          allowed values&lt;br /&gt;
              -----          --------------&lt;br /&gt;
              minute         0-59&lt;br /&gt;
              hour           0-23&lt;br /&gt;
              day of month   1-31&lt;br /&gt;
              month          1-12 (or names, see below)&lt;br /&gt;
              day of week    0-7 (0 or 7 is Sun, or use names)&lt;br /&gt;
&lt;br /&gt;
       A field may be an asterisk (*), which always stands for ``first-last&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Ranges  of  numbers  are  allowed.  Ranges are two numbers separated with a hyphen.&lt;br /&gt;
       The specified range is inclusive.  For example, 8-11 for an ``hours&#039;&#039; entry specifies&lt;br /&gt;
       execution at hours 8, 9, 10 and 11.&lt;br /&gt;
&lt;br /&gt;
       Lists are allowed.  A list is a set of numbers (or ranges) separated by commas.&lt;br /&gt;
       Examples: ``1,2,5,9&#039;&#039;, ``0-4,8-12&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Step values can be used in conjunction with ranges.  Following a range with ``/&amp;lt;number&amp;gt;&#039;&#039;&lt;br /&gt;
       specifies  skips  of  the  number&#039;s  value  through  the  range.   For  example,&lt;br /&gt;
       ``0-23/2&#039;&#039; can be used in the hours field to specify command execution every other hour&lt;br /&gt;
       (the alternative in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22&#039;&#039;).  Steps&lt;br /&gt;
       are also permitted after an asterisk, so if you want to say ``every two hours&#039;&#039;, just use ``*/2&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|lastruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|-&lt;br /&gt;
|defaultminute&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaulthour&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaultday&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaultmonth&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|defaultdayofweek&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminminute&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminhour&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminday&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|adminmonth&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admindayofweek&lt;br /&gt;
|varchar(25)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The original database specification had extra custom fields that the cronjobs could insert information into, called custom1 and custom2 and so on.  I&#039;ve removed these from this specification until such time as we have a solid use-case for them.  The original spec also had a priority field, but this has been removed after the conversation in Jizerka, which led to the proposal to just let some core jobs block all others, rather than prioritising individual tasks.&lt;br /&gt;
&lt;br /&gt;
=== Locking ===&lt;br /&gt;
&lt;br /&gt;
Penny and Tim originally thought that the best approach was to try and do something that would cause an exception to be thrown - for example, try to insert into a row that had a unique constraint on it, and catch the exception.  However, this will cause far too much noise in the logs.  Matt Oquist came up with a different approach in MDL-21110.  We could potentially change this slightly to allow alternative implementations, by means of an abstract class and factory method (this was suggested by Sam Marshall), but probaby isn&#039;t needed for the initial implementation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Black magic ===&lt;br /&gt;
&lt;br /&gt;
Cron.php will need to be rewritten to look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
while ($nexttask = cron_get_next_task()) {&lt;br /&gt;
    cron_call_function($nexttask);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some black magic to hand out the next task, which does:&lt;br /&gt;
&lt;br /&gt;
* Checks how long the existing process is allowed to run for&lt;br /&gt;
* Figures out if there&#039;s already a &amp;quot;blocking&amp;quot; task running&lt;br /&gt;
* Figures out the next task that&#039;s scheduled&lt;br /&gt;
* Tries to get a lock on it&lt;br /&gt;
* Returns that task&lt;br /&gt;
&lt;br /&gt;
== Unresolved issues/ideas ==&lt;br /&gt;
&lt;br /&gt;
* Do we need to allow for scheduling different subtasks on different servers?&lt;br /&gt;
* We need to find a way to separate subtasks by some logic so that subtasks that write to the same areas of the database never run at the same time.  We could do this by getting each cron job to say what areas of Moodle they write to, but this is problematic.&lt;br /&gt;
* We also have to deal with the order of some subtasks - we could maybe do this by introducing dependencies&lt;br /&gt;
* When the first cron in a long time is running, we should lock the entire cron and let it run to completeness, because the order is really important then.&lt;br /&gt;
&lt;br /&gt;
== Psuedo code proposal ==&lt;br /&gt;
Moved [[Development_talk:Scheduled_Tasks_Proposal|to the talk page]]&lt;br /&gt;
&lt;br /&gt;
== Audit of current cron ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Main section&lt;br /&gt;
! Subtask&lt;br /&gt;
! Frequency&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| session_gc&lt;br /&gt;
|&lt;br /&gt;
| every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|plugins (none)&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|message submissions&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update chat times&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update_events&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old chat_users and add quits&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old messages&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/data&lt;br /&gt;
|&lt;br /&gt;
|every minute&lt;br /&gt;
|no _cron function (includes file unnecessarily)&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|mail posts&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|digest processing&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|delete old read tracking&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/scorm&lt;br /&gt;
|reparse all scorms&lt;br /&gt;
|every five minutes&lt;br /&gt;
|does hourly checking&lt;br /&gt;
|-&lt;br /&gt;
|mod/wiki&lt;br /&gt;
|delete expired locks&lt;br /&gt;
|every hour&lt;br /&gt;
|-&lt;br /&gt;
|blocks/rss_client&lt;br /&gt;
|update feeds&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|quiz/report/statistics&lt;br /&gt;
|delete old statistics&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admin/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|language_cache&lt;br /&gt;
&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|remove expired enrolments&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|lock pending grades (*2)&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|clean old grade history&lt;br /&gt;
|every run&lt;br /&gt;
|has a TODO to not process as often&lt;br /&gt;
|-&lt;br /&gt;
|event queue&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|portfolio cron&lt;br /&gt;
|clean expired exports&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|longtimenosee&lt;br /&gt;
&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteunconfirmedusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteincompleteusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteoldlogs&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deletefiltercache&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|notifyloginfailures&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|metacourse syncing&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|createpasswordemails&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|tag cron&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|clean contexts&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|gc_cache_flags&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|build_context_path&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|scheduled backups&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|make rss feeds&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|keepalives&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|delete old sessions&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/ldap&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/cas&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/db&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|clears old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|notifies administrators of old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|process orders &amp;amp; email teachers&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/flatfile&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/imsenterprise&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/manual&lt;br /&gt;
|notify people of pending unenrolments&lt;br /&gt;
|daily&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|statistics&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|huge&lt;br /&gt;
|-&lt;br /&gt;
|grade/import&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/export&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|fetch blog entries&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|file gc&lt;br /&gt;
|&lt;br /&gt;
|(optional) daily, else every run?&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|local cron&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
* Audit all existing cronjobs (done)&lt;br /&gt;
* Implement the locking code, either Matt&#039;s or something similar and write robust tests for it (this will be hard to test perhaps - can we test race conditions using simpletest?)&lt;br /&gt;
* Write the black magic that hands out the next task to be run for a given cron process&lt;br /&gt;
* Rewrite cron.php to use the black magic&lt;br /&gt;
* Migrate all the existing cronjobs to the new system&lt;br /&gt;
* Write screens to allow administrators to reschedule tasks&lt;br /&gt;
* Write code to transfer between unix-cron-syntax and user-friendly syntax (and vice versa)&lt;br /&gt;
* Test thoroughly&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66872</id>
		<title>Development:Scheduled Tasks Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66872"/>
		<updated>2010-01-05T05:24:44Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Tasks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This proposal is meant both to provide a replacement for the moodle cron job, and provide a means to schedule once off tasks to be run outside of the user&#039;s request lifecycle.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
&lt;br /&gt;
* *Subtask* an individual piece of cron processing that should be run (equivalent to forum_cron now, or maybe even smaller)&lt;br /&gt;
* *Moodle cron instance* a cron.php process&lt;br /&gt;
&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The moodle cronjob currently delegates all scheduling to each subtask that is run - for example, the forum cron is responsible for checking when it last run, and making decisions about whether or not it should be run again.   This sort of decision process should be centralised, and individual cron subtasks should be called by the central controller.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is not any central locking of subtasks.  At the moment, some subtasks that expect that they might take a long time to run implement their own locking (for example statistics), but it&#039;s not centralised.  Each moodle cron instance runs to completion, no matter how long it takes, and it processes tasks in the order that they&#039;re programmed, regardless of if there are any other moodle cron instances running, that might be processing sub tasks in parallel&lt;br /&gt;
&lt;br /&gt;
Finally, we need to be able to run non-related tasks in parallel so that the entire moodle queue isn&#039;t held up by single long running jobs.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Centralised locking for &#039;&#039;&#039;all&#039;&#039;&#039; tasks&lt;br /&gt;
* A way consistent for &#039;&#039;&#039;all plugin types&#039;&#039;&#039; to register with Moodle (at installation/upgrade) when they want their jobs run&lt;br /&gt;
* More sophisticated scheduling rather than just intervals in seconds (eg every sunday at 11pm or similar) based on unix cron&lt;br /&gt;
* An administration screen in Moodle to allow site administrators to adjust the scheduling of individual tasks&lt;br /&gt;
&lt;br /&gt;
== Approach ==&lt;br /&gt;
&lt;br /&gt;
=== Plugin cron registration ===&lt;br /&gt;
&lt;br /&gt;
Each plugin will be able to provide a db/tasks.php (alongside access.php and events.php etc) that lists all the cronjobs that it wants to have run.  This will look something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$tasks = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;function&#039;    =&amp;gt; &#039;yourmodule_cron_somedescription&#039;,&lt;br /&gt;
        &#039;minute&#039;      =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;hour&#039;        =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;day&#039;         =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;month&#039;       =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;dayofweek&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;langstringkey&#039;, // this must correspond to get_string(&#039;langstringkey&#039;, &#039;yourmodule&#039;);&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields are the same as normal unix cron, with the exception that you cannot use 3 letter words for the month and day of week fields like you can for unix cron.  The following is straight from the unix manpage about cron:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
              field          allowed values&lt;br /&gt;
              -----          --------------&lt;br /&gt;
              minute         0-59&lt;br /&gt;
              hour           0-23&lt;br /&gt;
              day of month   1-31&lt;br /&gt;
              month          1-12 (or names, see below)&lt;br /&gt;
              day of week    0-7 (0 or 7 is Sun, or use names)&lt;br /&gt;
&lt;br /&gt;
       A field may be an asterisk (*), which always stands for ``first-last&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Ranges  of  numbers  are  allowed.  Ranges are two numbers separated with a hyphen.&lt;br /&gt;
       The specified range is inclusive.  For example, 8-11 for an ``hours&#039;&#039; entry specifies&lt;br /&gt;
       execution at hours 8, 9, 10 and 11.&lt;br /&gt;
&lt;br /&gt;
       Lists are allowed.  A list is a set of numbers (or ranges) separated by commas.&lt;br /&gt;
       Examples: ``1,2,5,9&#039;&#039;, ``0-4,8-12&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Step values can be used in conjunction with ranges.  Following a range with ``/&amp;lt;number&amp;gt;&#039;&#039;&lt;br /&gt;
       specifies  skips  of  the  number&#039;s  value  through  the  range.   For  example,&lt;br /&gt;
       ``0-23/2&#039;&#039; can be used in the hours field to specify command execution every other hour&lt;br /&gt;
       (the alternative in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22&#039;&#039;).  Steps&lt;br /&gt;
       are also permitted after an asterisk, so if you want to say ``every two hours&#039;&#039;, just use ``*/2&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|lastruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The original database specification had extra custom fields that the cronjobs could insert information into, called custom1 and custom2 and so on.  I&#039;ve removed these from this specification until such time as we have a solid use-case for them.  The original spec also had a priority field, but this has been removed after the conversation in Jizerka, which led to the proposal to just let some core jobs block all others, rather than prioritising individual tasks.&lt;br /&gt;
&lt;br /&gt;
=== Locking ===&lt;br /&gt;
&lt;br /&gt;
Penny and Tim originally thought that the best approach was to try and do something that would cause an exception to be thrown - for example, try to insert into a row that had a unique constraint on it, and catch the exception.  However, this will cause far too much noise in the logs.  Matt Oquist came up with a different approach in MDL-21110.  We could potentially change this slightly to allow alternative implementations, by means of an abstract class and factory method (this was suggested by Sam Marshall), but probaby isn&#039;t needed for the initial implementation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Black magic ===&lt;br /&gt;
&lt;br /&gt;
Cron.php will need to be rewritten to look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
while ($nexttask = cron_get_next_task()) {&lt;br /&gt;
    cron_call_function($nexttask);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some black magic to hand out the next task, which does:&lt;br /&gt;
&lt;br /&gt;
* Checks how long the existing process is allowed to run for&lt;br /&gt;
* Figures out if there&#039;s already a &amp;quot;blocking&amp;quot; task running&lt;br /&gt;
* Figures out the next task that&#039;s scheduled&lt;br /&gt;
* Tries to get a lock on it&lt;br /&gt;
* Returns that task&lt;br /&gt;
&lt;br /&gt;
== Unresolved issues/ideas ==&lt;br /&gt;
&lt;br /&gt;
* Do we need to allow for scheduling different subtasks on different servers?&lt;br /&gt;
* We need to find a way to separate subtasks by some logic so that subtasks that write to the same areas of the database never run at the same time.  We could do this by getting each cron job to say what areas of Moodle they write to, but this is problematic.&lt;br /&gt;
* We also have to deal with the order of some subtasks - we could maybe do this by introducing dependencies&lt;br /&gt;
* When the first cron in a long time is running, we should lock the entire cron and let it run to completeness, because the order is really important then.&lt;br /&gt;
&lt;br /&gt;
== Psuedo code proposal ==&lt;br /&gt;
Moved [[Development_talk:Scheduled_Tasks_Proposal|to the talk page]]&lt;br /&gt;
&lt;br /&gt;
== Audit of current cron ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Main section&lt;br /&gt;
! Subtask&lt;br /&gt;
! Frequency&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| session_gc&lt;br /&gt;
|&lt;br /&gt;
| every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|plugins (none)&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|message submissions&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update chat times&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update_events&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old chat_users and add quits&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old messages&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/data&lt;br /&gt;
|&lt;br /&gt;
|every minute&lt;br /&gt;
|no _cron function (includes file unnecessarily)&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|mail posts&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|digest processing&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|delete old read tracking&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/scorm&lt;br /&gt;
|reparse all scorms&lt;br /&gt;
|every five minutes&lt;br /&gt;
|does hourly checking&lt;br /&gt;
|-&lt;br /&gt;
|mod/wiki&lt;br /&gt;
|delete expired locks&lt;br /&gt;
|every hour&lt;br /&gt;
|-&lt;br /&gt;
|blocks/rss_client&lt;br /&gt;
|update feeds&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|quiz/report/statistics&lt;br /&gt;
|delete old statistics&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admin/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|language_cache&lt;br /&gt;
&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|remove expired enrolments&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|lock pending grades (*2)&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|clean old grade history&lt;br /&gt;
|every run&lt;br /&gt;
|has a TODO to not process as often&lt;br /&gt;
|-&lt;br /&gt;
|event queue&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|portfolio cron&lt;br /&gt;
|clean expired exports&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|longtimenosee&lt;br /&gt;
&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteunconfirmedusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteincompleteusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteoldlogs&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deletefiltercache&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|notifyloginfailures&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|metacourse syncing&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|createpasswordemails&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|tag cron&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|clean contexts&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|gc_cache_flags&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|build_context_path&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|scheduled backups&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|make rss feeds&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|keepalives&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|delete old sessions&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/ldap&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/cas&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/db&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|clears old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|notifies administrators of old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|process orders &amp;amp; email teachers&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/flatfile&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/imsenterprise&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/manual&lt;br /&gt;
|notify people of pending unenrolments&lt;br /&gt;
|daily&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|statistics&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|huge&lt;br /&gt;
|-&lt;br /&gt;
|grade/import&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/export&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|fetch blog entries&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|file gc&lt;br /&gt;
|&lt;br /&gt;
|(optional) daily, else every run?&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|local cron&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
* Audit all existing cronjobs (done)&lt;br /&gt;
* Implement the locking code, either Matt&#039;s or something similar and write robust tests for it (this will be hard to test perhaps - can we test race conditions using simpletest?)&lt;br /&gt;
* Write the black magic that hands out the next task to be run for a given cron process&lt;br /&gt;
* Rewrite cron.php to use the black magic&lt;br /&gt;
* Migrate all the existing cronjobs to the new system&lt;br /&gt;
* Write screens to allow administrators to reschedule tasks&lt;br /&gt;
* Write code to transfer between unix-cron-syntax and user-friendly syntax (and vice versa)&lt;br /&gt;
* Test thoroughly&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66871</id>
		<title>Development:Scheduled Tasks Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66871"/>
		<updated>2010-01-05T05:22:37Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Tasks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This proposal is meant both to provide a replacement for the moodle cron job, and provide a means to schedule once off tasks to be run outside of the user&#039;s request lifecycle.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
&lt;br /&gt;
* *Subtask* an individual piece of cron processing that should be run (equivalent to forum_cron now, or maybe even smaller)&lt;br /&gt;
* *Moodle cron instance* a cron.php process&lt;br /&gt;
&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The moodle cronjob currently delegates all scheduling to each subtask that is run - for example, the forum cron is responsible for checking when it last run, and making decisions about whether or not it should be run again.   This sort of decision process should be centralised, and individual cron subtasks should be called by the central controller.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is not any central locking of subtasks.  At the moment, some subtasks that expect that they might take a long time to run implement their own locking (for example statistics), but it&#039;s not centralised.  Each moodle cron instance runs to completion, no matter how long it takes, and it processes tasks in the order that they&#039;re programmed, regardless of if there are any other moodle cron instances running, that might be processing sub tasks in parallel&lt;br /&gt;
&lt;br /&gt;
Finally, we need to be able to run non-related tasks in parallel so that the entire moodle queue isn&#039;t held up by single long running jobs.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Centralised locking for &#039;&#039;&#039;all&#039;&#039;&#039; tasks&lt;br /&gt;
* A way consistent for &#039;&#039;&#039;all plugin types&#039;&#039;&#039; to register with Moodle (at installation/upgrade) when they want their jobs run&lt;br /&gt;
* More sophisticated scheduling rather than just intervals in seconds (eg every sunday at 11pm or similar) based on unix cron&lt;br /&gt;
* An administration screen in Moodle to allow site administrators to adjust the scheduling of individual tasks&lt;br /&gt;
&lt;br /&gt;
== Approach ==&lt;br /&gt;
&lt;br /&gt;
=== Plugin cron registration ===&lt;br /&gt;
&lt;br /&gt;
Each plugin will be able to provide a db/tasks.php (alongside access.php and events.php etc) that lists all the cronjobs that it wants to have run.  This will look something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$tasks = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;function&#039;    =&amp;gt; &#039;yourmodule_cron_somedescription&#039;,&lt;br /&gt;
        &#039;minute&#039;      =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;hour&#039;        =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;day&#039;         =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;month&#039;       =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;dayofweek&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;langstringkey&#039;, // this must correspond to get_string(&#039;langstringkey&#039;, &#039;yourmodule&#039;);&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields are the same as normal unix cron, with the exception that you cannot use 3 letter words for the month and day of week fields like you can for unix cron.  The following is straight from the unix manpage about cron:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
              field          allowed values&lt;br /&gt;
              -----          --------------&lt;br /&gt;
              minute         0-59&lt;br /&gt;
              hour           0-23&lt;br /&gt;
              day of month   1-31&lt;br /&gt;
              month          1-12 (or names, see below)&lt;br /&gt;
              day of week    0-7 (0 or 7 is Sun, or use names)&lt;br /&gt;
&lt;br /&gt;
       A field may be an asterisk (*), which always stands for ``first-last&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Ranges  of  numbers  are  allowed.  Ranges are two numbers separated with a hyphen.&lt;br /&gt;
       The specified range is inclusive.  For example, 8-11 for an ``hours&#039;&#039; entry specifies&lt;br /&gt;
       execution at hours 8, 9, 10 and 11.&lt;br /&gt;
&lt;br /&gt;
       Lists are allowed.  A list is a set of numbers (or ranges) separated by commas.&lt;br /&gt;
       Examples: ``1,2,5,9&#039;&#039;, ``0-4,8-12&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Step values can be used in conjunction with ranges.  Following a range with ``/&amp;lt;number&amp;gt;&#039;&#039;&lt;br /&gt;
       specifies  skips  of  the  number&#039;s  value  through  the  range.   For  example,&lt;br /&gt;
       ``0-23/2&#039;&#039; can be used in the hours field to specify command execution every other hour&lt;br /&gt;
       (the alternative in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22&#039;&#039;).  Steps&lt;br /&gt;
       are also permitted after an asterisk, so if you want to say ``every two hours&#039;&#039;, just use ``*/2&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|lastruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The original database specification had extra custom fields that the cronjobs could insert information into, called custom1 and custom2 and so on.  I&#039;ve removed these from this specification until such time as we have a solid use-case for them.  The original spec also had a priority field, but this has been removed after the conversation in Jizerka, which led to the proposal to just let some core jobs block all others, rather than prioritising individual tasks.&lt;br /&gt;
&lt;br /&gt;
=== Locking ===&lt;br /&gt;
&lt;br /&gt;
Penny and Tim originally thought that the best approach was to try and do something that would cause an exception to be thrown - for example, try to insert into a row that had a unique constraint on it, and catch the exception.  However, this will cause far too much noise in the logs.  Matt Oquist came up with a different approach in MDL-21110.  We could potentially change this slightly to allow alternative implementations, by means of an abstract class and factory method (this was suggested by Sam Marshall), but probaby isn&#039;t needed for the initial implementation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Black magic ===&lt;br /&gt;
&lt;br /&gt;
Cron.php will need to be rewritten to look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
while ($nexttask = cron_get_next_task()) {&lt;br /&gt;
    cron_call_function($nexttask);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some black magic to hand out the next task, which does:&lt;br /&gt;
&lt;br /&gt;
* Checks how long the existing process is allowed to run for&lt;br /&gt;
* Figures out if there&#039;s already a &amp;quot;blocking&amp;quot; task running&lt;br /&gt;
* Figures out the next task that&#039;s scheduled&lt;br /&gt;
* Tries to get a lock on it&lt;br /&gt;
* Returns that task&lt;br /&gt;
&lt;br /&gt;
== Unresolved issues/ideas ==&lt;br /&gt;
&lt;br /&gt;
* Do we need to allow for scheduling different subtasks on different servers?&lt;br /&gt;
* We need to find a way to separate subtasks by some logic so that subtasks that write to the same areas of the database never run at the same time.  We could do this by getting each cron job to say what areas of Moodle they write to, but this is problematic.&lt;br /&gt;
* We also have to deal with the order of some subtasks - we could maybe do this by introducing dependencies&lt;br /&gt;
* When the first cron in a long time is running, we should lock the entire cron and let it run to completeness, because the order is really important then.&lt;br /&gt;
&lt;br /&gt;
== Psuedo code proposal ==&lt;br /&gt;
Moved [[Development_talk:Scheduled_Tasks_Proposal|to the talk page]]&lt;br /&gt;
&lt;br /&gt;
== Audit of current cron ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Main section&lt;br /&gt;
! Subtask&lt;br /&gt;
! Frequency&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| session_gc&lt;br /&gt;
|&lt;br /&gt;
| every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|plugins (none)&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|message submissions&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update chat times&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update_events&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old chat_users and add quits&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old messages&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/data&lt;br /&gt;
|&lt;br /&gt;
|every minute&lt;br /&gt;
|no _cron function (includes file unnecessarily)&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|mail posts&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|digest processing&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|delete old read tracking&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/scorm&lt;br /&gt;
|reparse all scorms&lt;br /&gt;
|every five minutes&lt;br /&gt;
|does hourly checking&lt;br /&gt;
|-&lt;br /&gt;
|mod/wiki&lt;br /&gt;
|delete expired locks&lt;br /&gt;
|every hour&lt;br /&gt;
|-&lt;br /&gt;
|blocks/rss_client&lt;br /&gt;
|update feeds&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|quiz/report/statistics&lt;br /&gt;
|delete old statistics&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admin/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|language_cache&lt;br /&gt;
&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|remove expired enrolments&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|lock pending grades (*2)&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|clean old grade history&lt;br /&gt;
|every run&lt;br /&gt;
|has a TODO to not process as often&lt;br /&gt;
|-&lt;br /&gt;
|event queue&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|portfolio cron&lt;br /&gt;
|clean expired exports&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|longtimenosee&lt;br /&gt;
&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteunconfirmedusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteincompleteusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteoldlogs&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deletefiltercache&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|notifyloginfailures&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|metacourse syncing&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|createpasswordemails&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|tag cron&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|clean contexts&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|gc_cache_flags&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|build_context_path&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|scheduled backups&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|make rss feeds&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|keepalives&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|delete old sessions&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/ldap&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/cas&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/db&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|clears old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|notifies administrators of old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|process orders &amp;amp; email teachers&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/flatfile&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/imsenterprise&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/manual&lt;br /&gt;
|notify people of pending unenrolments&lt;br /&gt;
|daily&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|statistics&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|huge&lt;br /&gt;
|-&lt;br /&gt;
|grade/import&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/export&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|fetch blog entries&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|file gc&lt;br /&gt;
|&lt;br /&gt;
|(optional) daily, else every run?&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|local cron&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
* Audit all existing cronjobs (done)&lt;br /&gt;
* Implement the locking code, either Matt&#039;s or something similar and write robust tests for it (this will be hard to test perhaps - can we test race conditions using simpletest?)&lt;br /&gt;
* Write the black magic that hands out the next task to be run for a given cron process&lt;br /&gt;
* Rewrite cron.php to use the black magic&lt;br /&gt;
* Migrate all the existing cronjobs to the new system&lt;br /&gt;
* Test thoroughly&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66869</id>
		<title>Development:Scheduled Tasks Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66869"/>
		<updated>2010-01-05T05:16:45Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Approach */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This proposal is meant both to provide a replacement for the moodle cron job, and provide a means to schedule once off tasks to be run outside of the user&#039;s request lifecycle.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
&lt;br /&gt;
* *Subtask* an individual piece of cron processing that should be run (equivalent to forum_cron now, or maybe even smaller)&lt;br /&gt;
* *Moodle cron instance* a cron.php process&lt;br /&gt;
&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The moodle cronjob currently delegates all scheduling to each subtask that is run - for example, the forum cron is responsible for checking when it last run, and making decisions about whether or not it should be run again.   This sort of decision process should be centralised, and individual cron subtasks should be called by the central controller.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is not any central locking of subtasks.  At the moment, some subtasks that expect that they might take a long time to run implement their own locking (for example statistics), but it&#039;s not centralised.  Each moodle cron instance runs to completion, no matter how long it takes, and it processes tasks in the order that they&#039;re programmed, regardless of if there are any other moodle cron instances running, that might be processing sub tasks in parallel&lt;br /&gt;
&lt;br /&gt;
Finally, we need to be able to run non-related tasks in parallel so that the entire moodle queue isn&#039;t held up by single long running jobs.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Centralised locking for &#039;&#039;&#039;all&#039;&#039;&#039; tasks&lt;br /&gt;
* A way consistent for &#039;&#039;&#039;all plugin types&#039;&#039;&#039; to register with Moodle (at installation/upgrade) when they want their jobs run&lt;br /&gt;
* More sophisticated scheduling rather than just intervals in seconds (eg every sunday at 11pm or similar) based on unix cron&lt;br /&gt;
* An administration screen in Moodle to allow site administrators to adjust the scheduling of individual tasks&lt;br /&gt;
&lt;br /&gt;
== Approach ==&lt;br /&gt;
&lt;br /&gt;
=== Plugin cron registration ===&lt;br /&gt;
&lt;br /&gt;
Each plugin will be able to provide a db/tasks.php (alongside access.php and events.php etc) that lists all the cronjobs that it wants to have run.  This will look something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$tasks = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;function&#039;    =&amp;gt; &#039;yourmodule_cron_somedescription&#039;,&lt;br /&gt;
        &#039;minute&#039;      =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;hour&#039;        =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;day&#039;         =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;month&#039;       =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;dayofweek&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;langstringkey&#039;, // this must correspond to get_string(&#039;langstringkey&#039;, &#039;yourmodule&#039;);&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields are the same as normal unix cron, with the exception that you cannot use 3 letter words for the month and day of week fields like you can for unix cron.  The following is straight from the unix manpage about cron:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
              field          allowed values&lt;br /&gt;
              -----          --------------&lt;br /&gt;
              minute         0-59&lt;br /&gt;
              hour           0-23&lt;br /&gt;
              day of month   1-31&lt;br /&gt;
              month          1-12 (or names, see below)&lt;br /&gt;
              day of week    0-7 (0 or 7 is Sun, or use names)&lt;br /&gt;
&lt;br /&gt;
       A field may be an asterisk (*), which always stands for ``first-last&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Ranges  of  numbers  are  allowed.  Ranges are two numbers separated with a hyphen.&lt;br /&gt;
       The specified range is inclusive.  For example, 8-11 for an ``hours&#039;&#039; entry specifies&lt;br /&gt;
       execution at hours 8, 9, 10 and 11.&lt;br /&gt;
&lt;br /&gt;
       Lists are allowed.  A list is a set of numbers (or ranges) separated by commas.&lt;br /&gt;
       Examples: ``1,2,5,9&#039;&#039;, ``0-4,8-12&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Step values can be used in conjunction with ranges.  Following a range with ``/&amp;lt;number&amp;gt;&#039;&#039;&lt;br /&gt;
       specifies  skips  of  the  number&#039;s  value  through  the  range.   For  example,&lt;br /&gt;
       ``0-23/2&#039;&#039; can be used in the hours field to specify command execution every other hour&lt;br /&gt;
       (the alternative in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22&#039;&#039;).  Steps&lt;br /&gt;
       are also permitted after an asterisk, so if you want to say ``every two hours&#039;&#039;, just use ``*/2&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|lastruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The original database specification had extra custom fields that the cronjobs could insert information into, called custom1 and custom2 and so on.  I&#039;ve removed these from this specification until such time as we have a solid use-case for them.  The original spec also had a priority field, but this has been removed after the conversation in Jizerka, which led to the proposal to just let some core jobs block all others, rather than prioritising individual tasks.&lt;br /&gt;
&lt;br /&gt;
=== Locking ===&lt;br /&gt;
&lt;br /&gt;
Penny and Tim originally thought that the best approach was to try and do something that would cause an exception to be thrown - for example, try to insert into a row that had a unique constraint on it, and catch the exception.  However, this will cause far too much noise in the logs.  Matt Oquist came up with a different approach in MDL-21110.  We could potentially change this slightly to allow alternative implementations, by means of an abstract class and factory method (this was suggested by Sam Marshall), but probaby isn&#039;t needed for the initial implementation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Black magic ===&lt;br /&gt;
&lt;br /&gt;
Cron.php will need to be rewritten to look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
while ($nexttask = cron_get_next_task()) {&lt;br /&gt;
    cron_call_function($nexttask);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some black magic to hand out the next task, which does:&lt;br /&gt;
&lt;br /&gt;
* Checks how long the existing process is allowed to run for&lt;br /&gt;
* Figures out if there&#039;s already a &amp;quot;blocking&amp;quot; task running&lt;br /&gt;
* Figures out the next task that&#039;s scheduled&lt;br /&gt;
* Tries to get a lock on it&lt;br /&gt;
* Returns that task&lt;br /&gt;
&lt;br /&gt;
== Unresolved issues/ideas ==&lt;br /&gt;
&lt;br /&gt;
* Do we need to allow for scheduling different subtasks on different servers?&lt;br /&gt;
* We need to find a way to separate subtasks by some logic so that subtasks that write to the same areas of the database never run at the same time.  We could do this by getting each cron job to say what areas of Moodle they write to, but this is problematic.&lt;br /&gt;
* We also have to deal with the order of some subtasks - we could maybe do this by introducing dependencies&lt;br /&gt;
* When the first cron in a long time is running, we should lock the entire cron and let it run to completeness, because the order is really important then.&lt;br /&gt;
&lt;br /&gt;
== Psuedo code proposal ==&lt;br /&gt;
Moved [[Development_talk:Scheduled_Tasks_Proposal|to the talk page]]&lt;br /&gt;
&lt;br /&gt;
== Audit of current cron ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Main section&lt;br /&gt;
! Subtask&lt;br /&gt;
! Frequency&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| session_gc&lt;br /&gt;
|&lt;br /&gt;
| every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|plugins (none)&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|message submissions&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update chat times&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update_events&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old chat_users and add quits&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old messages&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/data&lt;br /&gt;
|&lt;br /&gt;
|every minute&lt;br /&gt;
|no _cron function (includes file unnecessarily)&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|mail posts&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|digest processing&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|delete old read tracking&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/scorm&lt;br /&gt;
|reparse all scorms&lt;br /&gt;
|every five minutes&lt;br /&gt;
|does hourly checking&lt;br /&gt;
|-&lt;br /&gt;
|mod/wiki&lt;br /&gt;
|delete expired locks&lt;br /&gt;
|every hour&lt;br /&gt;
|-&lt;br /&gt;
|blocks/rss_client&lt;br /&gt;
|update feeds&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|quiz/report/statistics&lt;br /&gt;
|delete old statistics&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admin/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|language_cache&lt;br /&gt;
&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|remove expired enrolments&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|lock pending grades (*2)&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|clean old grade history&lt;br /&gt;
|every run&lt;br /&gt;
|has a TODO to not process as often&lt;br /&gt;
|-&lt;br /&gt;
|event queue&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|portfolio cron&lt;br /&gt;
|clean expired exports&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|longtimenosee&lt;br /&gt;
&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteunconfirmedusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteincompleteusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteoldlogs&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deletefiltercache&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|notifyloginfailures&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|metacourse syncing&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|createpasswordemails&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|tag cron&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|clean contexts&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|gc_cache_flags&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|build_context_path&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|scheduled backups&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|make rss feeds&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|keepalives&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|delete old sessions&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/ldap&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/cas&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/db&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|clears old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|notifies administrators of old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|process orders &amp;amp; email teachers&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/flatfile&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/imsenterprise&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/manual&lt;br /&gt;
|notify people of pending unenrolments&lt;br /&gt;
|daily&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|statistics&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|huge&lt;br /&gt;
|-&lt;br /&gt;
|grade/import&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/export&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|fetch blog entries&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|file gc&lt;br /&gt;
|&lt;br /&gt;
|(optional) daily, else every run?&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|local cron&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
* Audit all existing cronjobs (done)&lt;br /&gt;
* Implement the locking code, either Matt&#039;s or something similar and write robust tests for it (this will be hard to test perhaps - can we test race conditions using simpletest?)&lt;br /&gt;
* Write the black magic that hands out the next task to be run for a given cronjob&lt;br /&gt;
* Rewrite cron.php to use the black magic&lt;br /&gt;
* Migrate all the existing cronjobs to the new system&lt;br /&gt;
* Test thoroughly&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66868</id>
		<title>Development:Scheduled Tasks Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66868"/>
		<updated>2010-01-05T05:06:32Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Tasks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This proposal is meant both to provide a replacement for the moodle cron job, and provide a means to schedule once off tasks to be run outside of the user&#039;s request lifecycle.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
&lt;br /&gt;
* *Subtask* an individual piece of cron processing that should be run (equivalent to forum_cron now, or maybe even smaller)&lt;br /&gt;
* *Moodle cron instance* a cron.php process&lt;br /&gt;
&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The moodle cronjob currently delegates all scheduling to each subtask that is run - for example, the forum cron is responsible for checking when it last run, and making decisions about whether or not it should be run again.   This sort of decision process should be centralised, and individual cron subtasks should be called by the central controller.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is not any central locking of subtasks.  At the moment, some subtasks that expect that they might take a long time to run implement their own locking (for example statistics), but it&#039;s not centralised.  Each moodle cron instance runs to completion, no matter how long it takes, and it processes tasks in the order that they&#039;re programmed, regardless of if there are any other moodle cron instances running, that might be processing sub tasks in parallel&lt;br /&gt;
&lt;br /&gt;
Finally, we need to be able to run non-related tasks in parallel so that the entire moodle queue isn&#039;t held up by single long running jobs.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Centralised locking for &#039;&#039;&#039;all&#039;&#039;&#039; tasks&lt;br /&gt;
* A way consistent for &#039;&#039;&#039;all plugin types&#039;&#039;&#039; to register with Moodle (at installation/upgrade) when they want their jobs run&lt;br /&gt;
* More sophisticated scheduling rather than just intervals in seconds (eg every sunday at 11pm or similar) based on unix cron&lt;br /&gt;
* An administration screen in Moodle to allow site administrators to adjust the scheduling of individual tasks&lt;br /&gt;
&lt;br /&gt;
== Approach ==&lt;br /&gt;
&lt;br /&gt;
=== Plugin cron registration ===&lt;br /&gt;
&lt;br /&gt;
Each plugin will be able to provide a db/tasks.php (alongside access.php and events.php etc) that lists all the cronjobs that it wants to have run.  This will look something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$tasks = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;function&#039;    =&amp;gt; &#039;yourmodule_cron_somedescription&#039;,&lt;br /&gt;
        &#039;minute&#039;      =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;hour&#039;        =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;day&#039;         =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;month&#039;       =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;dayofweek&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;langstringkey&#039;, // this must correspond to get_string(&#039;langstringkey&#039;, &#039;yourmodule&#039;);&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields are the same as normal unix cron, with the exception that you cannot use 3 letter words for the month and day of week fields like you can for unix cron.  The following is straight from the unix manpage about cron:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
              field          allowed values&lt;br /&gt;
              -----          --------------&lt;br /&gt;
              minute         0-59&lt;br /&gt;
              hour           0-23&lt;br /&gt;
              day of month   1-31&lt;br /&gt;
              month          1-12 (or names, see below)&lt;br /&gt;
              day of week    0-7 (0 or 7 is Sun, or use names)&lt;br /&gt;
&lt;br /&gt;
       A field may be an asterisk (*), which always stands for ``first-last&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Ranges  of  numbers  are  allowed.  Ranges are two numbers separated with a hyphen.&lt;br /&gt;
       The specified range is inclusive.  For example, 8-11 for an ``hours&#039;&#039; entry specifies&lt;br /&gt;
       execution at hours 8, 9, 10 and 11.&lt;br /&gt;
&lt;br /&gt;
       Lists are allowed.  A list is a set of numbers (or ranges) separated by commas.&lt;br /&gt;
       Examples: ``1,2,5,9&#039;&#039;, ``0-4,8-12&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Step values can be used in conjunction with ranges.  Following a range with ``/&amp;lt;number&amp;gt;&#039;&#039;&lt;br /&gt;
       specifies  skips  of  the  number&#039;s  value  through  the  range.   For  example,&lt;br /&gt;
       ``0-23/2&#039;&#039; can be used in the hours field to specify command execution every other hour&lt;br /&gt;
       (the alternative in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22&#039;&#039;).  Steps&lt;br /&gt;
       are also permitted after an asterisk, so if you want to say ``every two hours&#039;&#039;, just use ``*/2&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|lastruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The original database specification had extra custom fields that the cronjobs could insert information into, called custom1 and custom2 and so on.  I&#039;ve removed these from this specification until such time as we have a solid use-case for them.  The original spec also had a priority field, but this has been removed after the conversation in Jizerka, which led to the proposal to just let some core jobs block all others, rather than prioritising individual tasks.&lt;br /&gt;
&lt;br /&gt;
=== Locking ===&lt;br /&gt;
&lt;br /&gt;
Penny and Tim originally thought that the best approach was to try and do something that would cause an exception to be thrown - for example, try to insert into a row that had a unique constraint on it, and catch the exception.  However, this will cause far too much noise in the logs.  Matt Oquist came up with a different approach in MDL-21110.  We could potentially change this slightly to allow alternative implementations, by means of an abstract class and factory method (this was suggested by Sam Marshall), but probaby isn&#039;t needed for the initial implementation.&lt;br /&gt;
&lt;br /&gt;
== Unresolved issues/ideas ==&lt;br /&gt;
&lt;br /&gt;
* Do we need to allow for scheduling different subtasks on different servers?&lt;br /&gt;
* We need to find a way to separate subtasks by some logic so that subtasks that write to the same areas of the database never run at the same time.  We could do this by getting each cron job to say what areas of Moodle they write to, but this is problematic.&lt;br /&gt;
* We also have to deal with the order of some subtasks - we could maybe do this by introducing dependencies&lt;br /&gt;
* When the first cron in a long time is running, we should lock the entire cron and let it run to completeness, because the order is really important then.&lt;br /&gt;
&lt;br /&gt;
== Psuedo code proposal ==&lt;br /&gt;
Moved [[Development_talk:Scheduled_Tasks_Proposal|to the talk page]]&lt;br /&gt;
&lt;br /&gt;
== Audit of current cron ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Main section&lt;br /&gt;
! Subtask&lt;br /&gt;
! Frequency&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| session_gc&lt;br /&gt;
|&lt;br /&gt;
| every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|plugins (none)&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|message submissions&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update chat times&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update_events&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old chat_users and add quits&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old messages&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/data&lt;br /&gt;
|&lt;br /&gt;
|every minute&lt;br /&gt;
|no _cron function (includes file unnecessarily)&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|mail posts&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|digest processing&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|delete old read tracking&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/scorm&lt;br /&gt;
|reparse all scorms&lt;br /&gt;
|every five minutes&lt;br /&gt;
|does hourly checking&lt;br /&gt;
|-&lt;br /&gt;
|mod/wiki&lt;br /&gt;
|delete expired locks&lt;br /&gt;
|every hour&lt;br /&gt;
|-&lt;br /&gt;
|blocks/rss_client&lt;br /&gt;
|update feeds&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|quiz/report/statistics&lt;br /&gt;
|delete old statistics&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admin/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|language_cache&lt;br /&gt;
&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|remove expired enrolments&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|lock pending grades (*2)&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|clean old grade history&lt;br /&gt;
|every run&lt;br /&gt;
|has a TODO to not process as often&lt;br /&gt;
|-&lt;br /&gt;
|event queue&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|portfolio cron&lt;br /&gt;
|clean expired exports&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|longtimenosee&lt;br /&gt;
&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteunconfirmedusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteincompleteusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteoldlogs&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deletefiltercache&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|notifyloginfailures&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|metacourse syncing&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|createpasswordemails&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|tag cron&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|clean contexts&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|gc_cache_flags&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|build_context_path&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|scheduled backups&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|make rss feeds&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|keepalives&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|delete old sessions&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/ldap&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/cas&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/db&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|clears old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|notifies administrators of old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|process orders &amp;amp; email teachers&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/flatfile&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/imsenterprise&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/manual&lt;br /&gt;
|notify people of pending unenrolments&lt;br /&gt;
|daily&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|statistics&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|huge&lt;br /&gt;
|-&lt;br /&gt;
|grade/import&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/export&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|fetch blog entries&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|file gc&lt;br /&gt;
|&lt;br /&gt;
|(optional) daily, else every run?&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|local cron&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
* Audit all existing cronjobs (done)&lt;br /&gt;
* Implement the locking code, either Matt&#039;s or something similar and write robust tests for it (this will be hard to test perhaps - can we test race conditions using simpletest?)&lt;br /&gt;
* Write the black magic that hands out the next task to be run for a given cronjob&lt;br /&gt;
* Rewrite cron.php to use the black magic&lt;br /&gt;
* Migrate all the existing cronjobs to the new system&lt;br /&gt;
* Test thoroughly&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66867</id>
		<title>Development:Scheduled Tasks Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66867"/>
		<updated>2010-01-05T04:48:21Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Psuedo code proposal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This proposal is meant both to provide a replacement for the moodle cron job, and provide a means to schedule once off tasks to be run outside of the user&#039;s request lifecycle.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
&lt;br /&gt;
* *Subtask* an individual piece of cron processing that should be run (equivalent to forum_cron now, or maybe even smaller)&lt;br /&gt;
* *Moodle cron instance* a cron.php process&lt;br /&gt;
&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The moodle cronjob currently delegates all scheduling to each subtask that is run - for example, the forum cron is responsible for checking when it last run, and making decisions about whether or not it should be run again.   This sort of decision process should be centralised, and individual cron subtasks should be called by the central controller.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is not any central locking of subtasks.  At the moment, some subtasks that expect that they might take a long time to run implement their own locking (for example statistics), but it&#039;s not centralised.  Each moodle cron instance runs to completion, no matter how long it takes, and it processes tasks in the order that they&#039;re programmed, regardless of if there are any other moodle cron instances running, that might be processing sub tasks in parallel&lt;br /&gt;
&lt;br /&gt;
Finally, we need to be able to run non-related tasks in parallel so that the entire moodle queue isn&#039;t held up by single long running jobs.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Centralised locking for &#039;&#039;&#039;all&#039;&#039;&#039; tasks&lt;br /&gt;
* A way consistent for &#039;&#039;&#039;all plugin types&#039;&#039;&#039; to register with Moodle (at installation/upgrade) when they want their jobs run&lt;br /&gt;
* More sophisticated scheduling rather than just intervals in seconds (eg every sunday at 11pm or similar) based on unix cron&lt;br /&gt;
* An administration screen in Moodle to allow site administrators to adjust the scheduling of individual tasks&lt;br /&gt;
&lt;br /&gt;
== Approach ==&lt;br /&gt;
&lt;br /&gt;
=== Plugin cron registration ===&lt;br /&gt;
&lt;br /&gt;
Each plugin will be able to provide a db/tasks.php (alongside access.php and events.php etc) that lists all the cronjobs that it wants to have run.  This will look something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$tasks = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;function&#039;    =&amp;gt; &#039;yourmodule_cron_somedescription&#039;,&lt;br /&gt;
        &#039;minute&#039;      =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;hour&#039;        =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;day&#039;         =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;month&#039;       =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;dayofweek&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;langstringkey&#039;, // this must correspond to get_string(&#039;langstringkey&#039;, &#039;yourmodule&#039;);&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields are the same as normal unix cron, with the exception that you cannot use 3 letter words for the month and day of week fields like you can for unix cron.  The following is straight from the unix manpage about cron:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
              field          allowed values&lt;br /&gt;
              -----          --------------&lt;br /&gt;
              minute         0-59&lt;br /&gt;
              hour           0-23&lt;br /&gt;
              day of month   1-31&lt;br /&gt;
              month          1-12 (or names, see below)&lt;br /&gt;
              day of week    0-7 (0 or 7 is Sun, or use names)&lt;br /&gt;
&lt;br /&gt;
       A field may be an asterisk (*), which always stands for ``first-last&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Ranges  of  numbers  are  allowed.  Ranges are two numbers separated with a hyphen.&lt;br /&gt;
       The specified range is inclusive.  For example, 8-11 for an ``hours&#039;&#039; entry specifies&lt;br /&gt;
       execution at hours 8, 9, 10 and 11.&lt;br /&gt;
&lt;br /&gt;
       Lists are allowed.  A list is a set of numbers (or ranges) separated by commas.&lt;br /&gt;
       Examples: ``1,2,5,9&#039;&#039;, ``0-4,8-12&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Step values can be used in conjunction with ranges.  Following a range with ``/&amp;lt;number&amp;gt;&#039;&#039;&lt;br /&gt;
       specifies  skips  of  the  number&#039;s  value  through  the  range.   For  example,&lt;br /&gt;
       ``0-23/2&#039;&#039; can be used in the hours field to specify command execution every other hour&lt;br /&gt;
       (the alternative in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22&#039;&#039;).  Steps&lt;br /&gt;
       are also permitted after an asterisk, so if you want to say ``every two hours&#039;&#039;, just use ``*/2&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|lastruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The original database specification had extra custom fields that the cronjobs could insert information into, called custom1 and custom2 and so on.  I&#039;ve removed these from this specification until such time as we have a solid use-case for them.  The original spec also had a priority field, but this has been removed after the conversation in Jizerka, which led to the proposal to just let some core jobs block all others, rather than prioritising individual tasks.&lt;br /&gt;
&lt;br /&gt;
=== Locking ===&lt;br /&gt;
&lt;br /&gt;
Penny and Tim originally thought that the best approach was to try and do something that would cause an exception to be thrown - for example, try to insert into a row that had a unique constraint on it, and catch the exception.  However, this will cause far too much noise in the logs.  Matt Oquist came up with a different approach in MDL-21110.  We could potentially change this slightly to allow alternative implementations, by means of an abstract class and factory method (this was suggested by Sam Marshall), but probaby isn&#039;t needed for the initial implementation.&lt;br /&gt;
&lt;br /&gt;
== Unresolved issues/ideas ==&lt;br /&gt;
&lt;br /&gt;
* Do we need to allow for scheduling different subtasks on different servers?&lt;br /&gt;
* We need to find a way to separate subtasks by some logic so that subtasks that write to the same areas of the database never run at the same time.  We could do this by getting each cron job to say what areas of Moodle they write to, but this is problematic.&lt;br /&gt;
* We also have to deal with the order of some subtasks - we could maybe do this by introducing dependencies&lt;br /&gt;
* When the first cron in a long time is running, we should lock the entire cron and let it run to completeness, because the order is really important then.&lt;br /&gt;
&lt;br /&gt;
== Psuedo code proposal ==&lt;br /&gt;
Moved [[Development_talk:Scheduled_Tasks_Proposal|to the talk page]]&lt;br /&gt;
&lt;br /&gt;
== Audit of current cron ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Main section&lt;br /&gt;
! Subtask&lt;br /&gt;
! Frequency&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| session_gc&lt;br /&gt;
|&lt;br /&gt;
| every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|plugins (none)&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|message submissions&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update chat times&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update_events&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old chat_users and add quits&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old messages&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/data&lt;br /&gt;
|&lt;br /&gt;
|every minute&lt;br /&gt;
|no _cron function (includes file unnecessarily)&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|mail posts&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|digest processing&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|delete old read tracking&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/scorm&lt;br /&gt;
|reparse all scorms&lt;br /&gt;
|every five minutes&lt;br /&gt;
|does hourly checking&lt;br /&gt;
|-&lt;br /&gt;
|mod/wiki&lt;br /&gt;
|delete expired locks&lt;br /&gt;
|every hour&lt;br /&gt;
|-&lt;br /&gt;
|blocks/rss_client&lt;br /&gt;
|update feeds&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|quiz/report/statistics&lt;br /&gt;
|delete old statistics&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admin/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|language_cache&lt;br /&gt;
&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|remove expired enrolments&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|lock pending grades (*2)&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|clean old grade history&lt;br /&gt;
|every run&lt;br /&gt;
|has a TODO to not process as often&lt;br /&gt;
|-&lt;br /&gt;
|event queue&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|portfolio cron&lt;br /&gt;
|clean expired exports&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|longtimenosee&lt;br /&gt;
&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteunconfirmedusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteincompleteusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteoldlogs&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deletefiltercache&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|notifyloginfailures&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|metacourse syncing&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|createpasswordemails&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|tag cron&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|clean contexts&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|gc_cache_flags&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|build_context_path&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|scheduled backups&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|make rss feeds&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|keepalives&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|delete old sessions&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/ldap&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/cas&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/db&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|clears old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|notifies administrators of old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|process orders &amp;amp; email teachers&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/flatfile&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/imsenterprise&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/manual&lt;br /&gt;
|notify people of pending unenrolments&lt;br /&gt;
|daily&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|statistics&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|huge&lt;br /&gt;
|-&lt;br /&gt;
|grade/import&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/export&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|fetch blog entries&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|file gc&lt;br /&gt;
|&lt;br /&gt;
|(optional) daily, else every run?&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|local cron&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66866</id>
		<title>Development:Scheduled Tasks Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66866"/>
		<updated>2010-01-05T04:42:57Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Goals */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This proposal is meant both to provide a replacement for the moodle cron job, and provide a means to schedule once off tasks to be run outside of the user&#039;s request lifecycle.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
&lt;br /&gt;
* *Subtask* an individual piece of cron processing that should be run (equivalent to forum_cron now, or maybe even smaller)&lt;br /&gt;
* *Moodle cron instance* a cron.php process&lt;br /&gt;
&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The moodle cronjob currently delegates all scheduling to each subtask that is run - for example, the forum cron is responsible for checking when it last run, and making decisions about whether or not it should be run again.   This sort of decision process should be centralised, and individual cron subtasks should be called by the central controller.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is not any central locking of subtasks.  At the moment, some subtasks that expect that they might take a long time to run implement their own locking (for example statistics), but it&#039;s not centralised.  Each moodle cron instance runs to completion, no matter how long it takes, and it processes tasks in the order that they&#039;re programmed, regardless of if there are any other moodle cron instances running, that might be processing sub tasks in parallel&lt;br /&gt;
&lt;br /&gt;
Finally, we need to be able to run non-related tasks in parallel so that the entire moodle queue isn&#039;t held up by single long running jobs.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Centralised locking for &#039;&#039;&#039;all&#039;&#039;&#039; tasks&lt;br /&gt;
* A way consistent for &#039;&#039;&#039;all plugin types&#039;&#039;&#039; to register with Moodle (at installation/upgrade) when they want their jobs run&lt;br /&gt;
* More sophisticated scheduling rather than just intervals in seconds (eg every sunday at 11pm or similar) based on unix cron&lt;br /&gt;
* An administration screen in Moodle to allow site administrators to adjust the scheduling of individual tasks&lt;br /&gt;
&lt;br /&gt;
== Approach ==&lt;br /&gt;
&lt;br /&gt;
=== Plugin cron registration ===&lt;br /&gt;
&lt;br /&gt;
Each plugin will be able to provide a db/tasks.php (alongside access.php and events.php etc) that lists all the cronjobs that it wants to have run.  This will look something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$tasks = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;function&#039;    =&amp;gt; &#039;yourmodule_cron_somedescription&#039;,&lt;br /&gt;
        &#039;minute&#039;      =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;hour&#039;        =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;day&#039;         =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;month&#039;       =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;dayofweek&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;langstringkey&#039;, // this must correspond to get_string(&#039;langstringkey&#039;, &#039;yourmodule&#039;);&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields are the same as normal unix cron, with the exception that you cannot use 3 letter words for the month and day of week fields like you can for unix cron.  The following is straight from the unix manpage about cron:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
              field          allowed values&lt;br /&gt;
              -----          --------------&lt;br /&gt;
              minute         0-59&lt;br /&gt;
              hour           0-23&lt;br /&gt;
              day of month   1-31&lt;br /&gt;
              month          1-12 (or names, see below)&lt;br /&gt;
              day of week    0-7 (0 or 7 is Sun, or use names)&lt;br /&gt;
&lt;br /&gt;
       A field may be an asterisk (*), which always stands for ``first-last&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Ranges  of  numbers  are  allowed.  Ranges are two numbers separated with a hyphen.&lt;br /&gt;
       The specified range is inclusive.  For example, 8-11 for an ``hours&#039;&#039; entry specifies&lt;br /&gt;
       execution at hours 8, 9, 10 and 11.&lt;br /&gt;
&lt;br /&gt;
       Lists are allowed.  A list is a set of numbers (or ranges) separated by commas.&lt;br /&gt;
       Examples: ``1,2,5,9&#039;&#039;, ``0-4,8-12&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Step values can be used in conjunction with ranges.  Following a range with ``/&amp;lt;number&amp;gt;&#039;&#039;&lt;br /&gt;
       specifies  skips  of  the  number&#039;s  value  through  the  range.   For  example,&lt;br /&gt;
       ``0-23/2&#039;&#039; can be used in the hours field to specify command execution every other hour&lt;br /&gt;
       (the alternative in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22&#039;&#039;).  Steps&lt;br /&gt;
       are also permitted after an asterisk, so if you want to say ``every two hours&#039;&#039;, just use ``*/2&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|lastruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The original database specification had extra custom fields that the cronjobs could insert information into, called custom1 and custom2 and so on.  I&#039;ve removed these from this specification until such time as we have a solid use-case for them.  The original spec also had a priority field, but this has been removed after the conversation in Jizerka, which led to the proposal to just let some core jobs block all others, rather than prioritising individual tasks.&lt;br /&gt;
&lt;br /&gt;
=== Locking ===&lt;br /&gt;
&lt;br /&gt;
Penny and Tim originally thought that the best approach was to try and do something that would cause an exception to be thrown - for example, try to insert into a row that had a unique constraint on it, and catch the exception.  However, this will cause far too much noise in the logs.  Matt Oquist came up with a different approach in MDL-21110.  We could potentially change this slightly to allow alternative implementations, by means of an abstract class and factory method (this was suggested by Sam Marshall), but probaby isn&#039;t needed for the initial implementation.&lt;br /&gt;
&lt;br /&gt;
== Unresolved issues/ideas ==&lt;br /&gt;
&lt;br /&gt;
* Do we need to allow for scheduling different subtasks on different servers?&lt;br /&gt;
* We need to find a way to separate subtasks by some logic so that subtasks that write to the same areas of the database never run at the same time.  We could do this by getting each cron job to say what areas of Moodle they write to, but this is problematic.&lt;br /&gt;
* We also have to deal with the order of some subtasks - we could maybe do this by introducing dependencies&lt;br /&gt;
* When the first cron in a long time is running, we should lock the entire cron and let it run to completeness, because the order is really important then.&lt;br /&gt;
&lt;br /&gt;
== Psuedo code proposal ==&lt;br /&gt;
Moved to the talk page&lt;br /&gt;
&lt;br /&gt;
== Audit of current cron ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Main section&lt;br /&gt;
! Subtask&lt;br /&gt;
! Frequency&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| session_gc&lt;br /&gt;
|&lt;br /&gt;
| every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|plugins (none)&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|message submissions&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update chat times&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update_events&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old chat_users and add quits&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old messages&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/data&lt;br /&gt;
|&lt;br /&gt;
|every minute&lt;br /&gt;
|no _cron function (includes file unnecessarily)&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|mail posts&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|digest processing&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|delete old read tracking&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/scorm&lt;br /&gt;
|reparse all scorms&lt;br /&gt;
|every five minutes&lt;br /&gt;
|does hourly checking&lt;br /&gt;
|-&lt;br /&gt;
|mod/wiki&lt;br /&gt;
|delete expired locks&lt;br /&gt;
|every hour&lt;br /&gt;
|-&lt;br /&gt;
|blocks/rss_client&lt;br /&gt;
|update feeds&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|quiz/report/statistics&lt;br /&gt;
|delete old statistics&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admin/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|language_cache&lt;br /&gt;
&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|remove expired enrolments&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|lock pending grades (*2)&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|clean old grade history&lt;br /&gt;
|every run&lt;br /&gt;
|has a TODO to not process as often&lt;br /&gt;
|-&lt;br /&gt;
|event queue&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|portfolio cron&lt;br /&gt;
|clean expired exports&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|longtimenosee&lt;br /&gt;
&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteunconfirmedusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteincompleteusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteoldlogs&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deletefiltercache&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|notifyloginfailures&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|metacourse syncing&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|createpasswordemails&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|tag cron&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|clean contexts&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|gc_cache_flags&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|build_context_path&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|scheduled backups&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|make rss feeds&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|keepalives&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|delete old sessions&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/ldap&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/cas&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/db&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|clears old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|notifies administrators of old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|process orders &amp;amp; email teachers&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/flatfile&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/imsenterprise&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/manual&lt;br /&gt;
|notify people of pending unenrolments&lt;br /&gt;
|daily&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|statistics&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|huge&lt;br /&gt;
|-&lt;br /&gt;
|grade/import&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/export&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|fetch blog entries&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|file gc&lt;br /&gt;
|&lt;br /&gt;
|(optional) daily, else every run?&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|local cron&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66865</id>
		<title>Development:Scheduled Tasks Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66865"/>
		<updated>2010-01-05T04:39:14Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Approach */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This proposal is meant both to provide a replacement for the moodle cron job, and provide a means to schedule once off tasks to be run outside of the user&#039;s request lifecycle.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
&lt;br /&gt;
* *Subtask* an individual piece of cron processing that should be run (equivalent to forum_cron now, or maybe even smaller)&lt;br /&gt;
* *Moodle cron instance* a cron.php process&lt;br /&gt;
&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The moodle cronjob currently delegates all scheduling to each subtask that is run - for example, the forum cron is responsible for checking when it last run, and making decisions about whether or not it should be run again.   This sort of decision process should be centralised, and individual cron subtasks should be called by the central controller.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is not any central locking of subtasks.  At the moment, some subtasks that expect that they might take a long time to run implement their own locking (for example statistics), but it&#039;s not centralised.  Each moodle cron instance runs to completion, no matter how long it takes, and it processes tasks in the order that they&#039;re programmed, regardless of if there are any other moodle cron instances running, that might be processing sub tasks in parallel&lt;br /&gt;
&lt;br /&gt;
Finally, we need to be able to run non-related tasks in parallel so that the entire moodle queue isn&#039;t held up by single long running jobs.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Centralised locking for *all* tasks&lt;br /&gt;
* A way consistent for *all plugin types* to register with Moodle (at installation/upgrade) when they want their jobs run&lt;br /&gt;
* More sophisticated scheduling rather than just intervals in seconds (eg every sunday at 11pm or similar) based on unix cron&lt;br /&gt;
* An administration screen in Moodle to allow site administrators to adjust the scheduling of individual tasks&lt;br /&gt;
&lt;br /&gt;
== Approach ==&lt;br /&gt;
&lt;br /&gt;
=== Plugin cron registration ===&lt;br /&gt;
&lt;br /&gt;
Each plugin will be able to provide a db/tasks.php (alongside access.php and events.php etc) that lists all the cronjobs that it wants to have run.  This will look something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$tasks = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;function&#039;    =&amp;gt; &#039;yourmodule_cron_somedescription&#039;,&lt;br /&gt;
        &#039;minute&#039;      =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;hour&#039;        =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;day&#039;         =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;month&#039;       =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;dayofweek&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;langstringkey&#039;, // this must correspond to get_string(&#039;langstringkey&#039;, &#039;yourmodule&#039;);&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields are the same as normal unix cron, with the exception that you cannot use 3 letter words for the month and day of week fields like you can for unix cron.  The following is straight from the unix manpage about cron:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
              field          allowed values&lt;br /&gt;
              -----          --------------&lt;br /&gt;
              minute         0-59&lt;br /&gt;
              hour           0-23&lt;br /&gt;
              day of month   1-31&lt;br /&gt;
              month          1-12 (or names, see below)&lt;br /&gt;
              day of week    0-7 (0 or 7 is Sun, or use names)&lt;br /&gt;
&lt;br /&gt;
       A field may be an asterisk (*), which always stands for ``first-last&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Ranges  of  numbers  are  allowed.  Ranges are two numbers separated with a hyphen.&lt;br /&gt;
       The specified range is inclusive.  For example, 8-11 for an ``hours&#039;&#039; entry specifies&lt;br /&gt;
       execution at hours 8, 9, 10 and 11.&lt;br /&gt;
&lt;br /&gt;
       Lists are allowed.  A list is a set of numbers (or ranges) separated by commas.&lt;br /&gt;
       Examples: ``1,2,5,9&#039;&#039;, ``0-4,8-12&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Step values can be used in conjunction with ranges.  Following a range with ``/&amp;lt;number&amp;gt;&#039;&#039;&lt;br /&gt;
       specifies  skips  of  the  number&#039;s  value  through  the  range.   For  example,&lt;br /&gt;
       ``0-23/2&#039;&#039; can be used in the hours field to specify command execution every other hour&lt;br /&gt;
       (the alternative in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22&#039;&#039;).  Steps&lt;br /&gt;
       are also permitted after an asterisk, so if you want to say ``every two hours&#039;&#039;, just use ``*/2&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|lastruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The original database specification had extra custom fields that the cronjobs could insert information into, called custom1 and custom2 and so on.  I&#039;ve removed these from this specification until such time as we have a solid use-case for them.  The original spec also had a priority field, but this has been removed after the conversation in Jizerka, which led to the proposal to just let some core jobs block all others, rather than prioritising individual tasks.&lt;br /&gt;
&lt;br /&gt;
=== Locking ===&lt;br /&gt;
&lt;br /&gt;
Penny and Tim originally thought that the best approach was to try and do something that would cause an exception to be thrown - for example, try to insert into a row that had a unique constraint on it, and catch the exception.  However, this will cause far too much noise in the logs.  Matt Oquist came up with a different approach in MDL-21110.  We could potentially change this slightly to allow alternative implementations, by means of an abstract class and factory method (this was suggested by Sam Marshall), but probaby isn&#039;t needed for the initial implementation.&lt;br /&gt;
&lt;br /&gt;
== Unresolved issues/ideas ==&lt;br /&gt;
&lt;br /&gt;
* Do we need to allow for scheduling different subtasks on different servers?&lt;br /&gt;
* We need to find a way to separate subtasks by some logic so that subtasks that write to the same areas of the database never run at the same time.  We could do this by getting each cron job to say what areas of Moodle they write to, but this is problematic.&lt;br /&gt;
* We also have to deal with the order of some subtasks - we could maybe do this by introducing dependencies&lt;br /&gt;
* When the first cron in a long time is running, we should lock the entire cron and let it run to completeness, because the order is really important then.&lt;br /&gt;
&lt;br /&gt;
== Psuedo code proposal ==&lt;br /&gt;
Moved to the talk page&lt;br /&gt;
&lt;br /&gt;
== Audit of current cron ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Main section&lt;br /&gt;
! Subtask&lt;br /&gt;
! Frequency&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| session_gc&lt;br /&gt;
|&lt;br /&gt;
| every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|plugins (none)&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|message submissions&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update chat times&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update_events&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old chat_users and add quits&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old messages&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/data&lt;br /&gt;
|&lt;br /&gt;
|every minute&lt;br /&gt;
|no _cron function (includes file unnecessarily)&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|mail posts&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|digest processing&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|delete old read tracking&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/scorm&lt;br /&gt;
|reparse all scorms&lt;br /&gt;
|every five minutes&lt;br /&gt;
|does hourly checking&lt;br /&gt;
|-&lt;br /&gt;
|mod/wiki&lt;br /&gt;
|delete expired locks&lt;br /&gt;
|every hour&lt;br /&gt;
|-&lt;br /&gt;
|blocks/rss_client&lt;br /&gt;
|update feeds&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|quiz/report/statistics&lt;br /&gt;
|delete old statistics&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admin/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|language_cache&lt;br /&gt;
&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|remove expired enrolments&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|lock pending grades (*2)&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|clean old grade history&lt;br /&gt;
|every run&lt;br /&gt;
|has a TODO to not process as often&lt;br /&gt;
|-&lt;br /&gt;
|event queue&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|portfolio cron&lt;br /&gt;
|clean expired exports&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|longtimenosee&lt;br /&gt;
&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteunconfirmedusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteincompleteusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteoldlogs&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deletefiltercache&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|notifyloginfailures&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|metacourse syncing&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|createpasswordemails&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|tag cron&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|clean contexts&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|gc_cache_flags&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|build_context_path&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|scheduled backups&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|make rss feeds&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|keepalives&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|delete old sessions&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/ldap&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/cas&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/db&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|clears old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|notifies administrators of old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|process orders &amp;amp; email teachers&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/flatfile&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/imsenterprise&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/manual&lt;br /&gt;
|notify people of pending unenrolments&lt;br /&gt;
|daily&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|statistics&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|huge&lt;br /&gt;
|-&lt;br /&gt;
|grade/import&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/export&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|fetch blog entries&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|file gc&lt;br /&gt;
|&lt;br /&gt;
|(optional) daily, else every run?&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|local cron&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66864</id>
		<title>Development:Scheduled Tasks Proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/405/en/index.php?title=Development:Scheduled_Tasks_Proposal&amp;diff=66864"/>
		<updated>2010-01-05T04:24:05Z</updated>

		<summary type="html">&lt;p&gt;Mjollnir: /* Database */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This proposal is meant both to provide a replacement for the moodle cron job, and provide a means to schedule once off tasks to be run outside of the user&#039;s request lifecycle.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
&lt;br /&gt;
* *Subtask* an individual piece of cron processing that should be run (equivalent to forum_cron now, or maybe even smaller)&lt;br /&gt;
* *Moodle cron instance* a cron.php process&lt;br /&gt;
&lt;br /&gt;
== Rationale ==&lt;br /&gt;
&lt;br /&gt;
The moodle cronjob currently delegates all scheduling to each subtask that is run - for example, the forum cron is responsible for checking when it last run, and making decisions about whether or not it should be run again.   This sort of decision process should be centralised, and individual cron subtasks should be called by the central controller.&lt;br /&gt;
&lt;br /&gt;
Additionally, there is not any central locking of subtasks.  At the moment, some subtasks that expect that they might take a long time to run implement their own locking (for example statistics), but it&#039;s not centralised.  Each moodle cron instance runs to completion, no matter how long it takes, and it processes tasks in the order that they&#039;re programmed, regardless of if there are any other moodle cron instances running, that might be processing sub tasks in parallel&lt;br /&gt;
&lt;br /&gt;
Finally, we need to be able to run non-related tasks in parallel so that the entire moodle queue isn&#039;t held up by single long running jobs.&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Centralised locking for *all* tasks&lt;br /&gt;
* A way consistent for *all plugin types* to register with Moodle (at installation/upgrade) when they want their jobs run&lt;br /&gt;
* More sophisticated scheduling rather than just intervals in seconds (eg every sunday at 11pm or similar) based on unix cron&lt;br /&gt;
* An administration screen in Moodle to allow site administrators to adjust the scheduling of individual tasks&lt;br /&gt;
&lt;br /&gt;
== Approach ==&lt;br /&gt;
&lt;br /&gt;
=== Plugin cron registration ===&lt;br /&gt;
&lt;br /&gt;
Each plugin will be able to provide a db/tasks.php (alongside access.php and events.php etc) that lists all the cronjobs that it wants to have run.  This will look something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$tasks = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;function&#039;    =&amp;gt; &#039;yourmodule_cron_somedescription&#039;,&lt;br /&gt;
        &#039;minute&#039;      =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;hour&#039;        =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;day&#039;         =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;month&#039;       =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;dayofweek&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;description&#039; =&amp;gt; &#039;langstringkey&#039;, // this must correspond to get_string(&#039;langstringkey&#039;, &#039;yourmodule&#039;);&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields are the same as normal unix cron, with the exception that you cannot use 3 letter words for the month and day of week fields like you can for unix cron.  The following is straight from the unix manpage about cron:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
              field          allowed values&lt;br /&gt;
              -----          --------------&lt;br /&gt;
              minute         0-59&lt;br /&gt;
              hour           0-23&lt;br /&gt;
              day of month   1-31&lt;br /&gt;
              month          1-12 (or names, see below)&lt;br /&gt;
              day of week    0-7 (0 or 7 is Sun, or use names)&lt;br /&gt;
&lt;br /&gt;
       A field may be an asterisk (*), which always stands for ``first-last&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Ranges  of  numbers  are  allowed.  Ranges are two numbers separated with a hyphen.&lt;br /&gt;
       The specified range is inclusive.  For example, 8-11 for an ``hours&#039;&#039; entry specifies&lt;br /&gt;
       execution at hours 8, 9, 10 and 11.&lt;br /&gt;
&lt;br /&gt;
       Lists are allowed.  A list is a set of numbers (or ranges) separated by commas.&lt;br /&gt;
       Examples: ``1,2,5,9&#039;&#039;, ``0-4,8-12&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
       Step values can be used in conjunction with ranges.  Following a range with ``/&amp;lt;number&amp;gt;&#039;&#039;&lt;br /&gt;
       specifies  skips  of  the  number&#039;s  value  through  the  range.   For  example,&lt;br /&gt;
       ``0-23/2&#039;&#039; can be used in the hours field to specify command execution every other hour&lt;br /&gt;
       (the alternative in the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22&#039;&#039;).  Steps&lt;br /&gt;
       are also permitted after an asterisk, so if you want to say ``every two hours&#039;&#039;, just use ``*/2&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Database ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;scheduled_tasks:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Field&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Datatype&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Comment&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|id&lt;br /&gt;
|integer&lt;br /&gt;
|sequence&lt;br /&gt;
|-&lt;br /&gt;
|plugintype&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|plugintype - should match the path-style declarations in get_plugin_types (eg question/type, not qtype).  Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|pluginname&lt;br /&gt;
|varchar(50)&lt;br /&gt;
|name of the plugin. Will be null for core tasks.&lt;br /&gt;
|-&lt;br /&gt;
|callfunction&lt;br /&gt;
|varchar(200) (unique)&lt;br /&gt;
|the function to call. Must be unique, as it will be used for the locking.&lt;br /&gt;
|-&lt;br /&gt;
|lastruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|nextruntime&lt;br /&gt;
|int(10)&lt;br /&gt;
|unix timestamp&lt;br /&gt;
|-&lt;br /&gt;
|blocking&lt;br /&gt;
|int(1)&lt;br /&gt;
|0 or 1 - whether this task, when running, blocks everything else from running.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The original database specification had extra custom fields that the cronjobs could insert information into, called custom1 and custom2 and so on.  I&#039;ve removed these from this specification until such time as we have a solid use-case for them.  The original spec also had a priority field, but this has been removed after the conversation in Jizerka, which led to the proposal to just let some core jobs block all others, rather than prioritising individual tasks.&lt;br /&gt;
&lt;br /&gt;
=== Module cron registration ===&lt;br /&gt;
&lt;br /&gt;
=== Locking ===&lt;br /&gt;
&lt;br /&gt;
== Unresolved issues/ideas ==&lt;br /&gt;
&lt;br /&gt;
* Do we need to allow for scheduling different subtasks on different servers?&lt;br /&gt;
* We need to find a way to separate subtasks by some logic so that subtasks that write to the same areas of the database never run at the same time.  We could do this by getting each cron job to say what areas of Moodle they write to, but this is problematic.&lt;br /&gt;
* We also have to deal with the order of some subtasks - we could maybe do this by introducing dependencies&lt;br /&gt;
* When the first cron in a long time is running, we should lock the entire cron and let it run to completeness, because the order is really important then.&lt;br /&gt;
&lt;br /&gt;
== Psuedo code proposal ==&lt;br /&gt;
Moved to the talk page&lt;br /&gt;
&lt;br /&gt;
== Audit of current cron ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Main section&lt;br /&gt;
! Subtask&lt;br /&gt;
! Frequency&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| session_gc&lt;br /&gt;
|&lt;br /&gt;
| every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|plugins (none)&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/assignment&lt;br /&gt;
|message submissions&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update chat times&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|update_events&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old chat_users and add quits&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/chat&lt;br /&gt;
|delete old messages&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/data&lt;br /&gt;
|&lt;br /&gt;
|every minute&lt;br /&gt;
|no _cron function (includes file unnecessarily)&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|mail posts&lt;br /&gt;
|every minute&lt;br /&gt;
|checks last run time&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|digest processing&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/forum&lt;br /&gt;
|delete old read tracking&lt;br /&gt;
|every minute&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|mod/scorm&lt;br /&gt;
|reparse all scorms&lt;br /&gt;
|every five minutes&lt;br /&gt;
|does hourly checking&lt;br /&gt;
|-&lt;br /&gt;
|mod/wiki&lt;br /&gt;
|delete expired locks&lt;br /&gt;
|every hour&lt;br /&gt;
|-&lt;br /&gt;
|blocks/rss_client&lt;br /&gt;
|update feeds&lt;br /&gt;
|every five minutes&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|quiz/report/statistics&lt;br /&gt;
|delete old statistics&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|admin/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|language_cache&lt;br /&gt;
&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|remove expired enrolments&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|lock pending grades (*2)&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|main gradebook&lt;br /&gt;
|clean old grade history&lt;br /&gt;
|every run&lt;br /&gt;
|has a TODO to not process as often&lt;br /&gt;
|-&lt;br /&gt;
|event queue&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|portfolio cron&lt;br /&gt;
|clean expired exports&lt;br /&gt;
|every run&lt;br /&gt;
|potentially large&lt;br /&gt;
|-&lt;br /&gt;
|longtimenosee&lt;br /&gt;
&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteunconfirmedusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteincompleteusers&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deleteoldlogs&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|deletefiltercache&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|notifyloginfailures&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|metacourse syncing&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|createpasswordemails&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|tag cron&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|clean contexts&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|gc_cache_flags&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|build_context_path&lt;br /&gt;
|&lt;br /&gt;
|20%&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|scheduled backups&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|make rss feeds&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|keepalives&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/mnet&lt;br /&gt;
|delete old sessions&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|auth/ldap&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/cas&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|auth/db&lt;br /&gt;
|sync users&lt;br /&gt;
|custom&lt;br /&gt;
|not scheduled (external cronjob)&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|clears old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|notifies administrators of old data&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/authorize&lt;br /&gt;
|process orders &amp;amp; email teachers&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|enrol/flatfile&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/imsenterprise&lt;br /&gt;
|read file and sync users&lt;br /&gt;
|every run&lt;br /&gt;
|!?!?!&lt;br /&gt;
|-&lt;br /&gt;
|enrol/manual&lt;br /&gt;
|notify people of pending unenrolments&lt;br /&gt;
|daily&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|statistics&lt;br /&gt;
|&lt;br /&gt;
|daily (admin defined)&lt;br /&gt;
|huge&lt;br /&gt;
|-&lt;br /&gt;
|grade/import&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/export&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|grade/reports&lt;br /&gt;
|none&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|fetch blog entries&lt;br /&gt;
|&lt;br /&gt;
|every run&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|file gc&lt;br /&gt;
|&lt;br /&gt;
|(optional) daily, else every run?&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|local cron&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tasks ==&lt;/div&gt;</summary>
		<author><name>Mjollnir</name></author>
	</entry>
</feed>