diff --git a/data/migratedPages.yml b/data/migratedPages.yml index c6bc993afe..da5541095f 100644 --- a/data/migratedPages.yml +++ b/data/migratedPages.yml @@ -168,6 +168,9 @@ List_of_locales_supported_on_Moodle_community_servers: Local_plugins: - filePath: "/docs/apis/plugintypes/local/index.mdx" slug: "/docs/apis/plugintypes/local" +Lock_API: +- filePath: "/docs/apis/core/lock/index.md" + slug: "/docs/apis/core/lock/" Machine_learning_backends: - filePath: "/docs/apis/plugintypes/mlbackend/index.md" slug: "/docs/apis/plugintypes/mlbackend/" diff --git a/docs/apis.md b/docs/apis.md index 5556f17972..635df75094 100644 --- a/docs/apis.md +++ b/docs/apis.md @@ -131,7 +131,7 @@ The [H5P API](https://docs.moodle.org/dev/H5P_API) allows plugins to make some d ### Lock API (lock) -The [Lock API](https://docs.moodle.org/dev/Lock_API) lets you synchronise processing between multiple requests, even for separate nodes in a cluster. +The [Lock API](./apis/core/lock/index.md) lets you synchronise processing between multiple requests, even for separate nodes in a cluster. ### Message API (message) diff --git a/docs/apis/core/lock/index.md b/docs/apis/core/lock/index.md new file mode 100644 index 0000000000..7b80a348f2 --- /dev/null +++ b/docs/apis/core/lock/index.md @@ -0,0 +1,73 @@ +--- +title: Lock API +tags: + - API + - Lock +--- + +Locking is required whenever you need to prevent two, or more, processes accessing the same resource at the same time. The prime candidate for locking in Moodle is cron. Locking allows multiple cron processes to work on different parts of cron at the same time with no risk that they will conflict (work on the same job at the same time). + +## When to use locking + +When you want to prevent multiple requests from accessing the same resource at the same time. Accessing a resource is a vague description, but it could be for example running a slow running task in the background, running different parts of cron etc. + +## Performance + +Locking is not meant to be fast. Do not use it in code that will be triggered many times in a single request (for example MUC). It is meant to be always correct - even for multiple nodes in a cluster. This implies that the locks are communicated among all the nodes in the cluster, and hence it will never be super quick. + +## Usage + +The locking API is used by getting an instance of a lock_factory, and then using it to retrieve locks, and eventually releasing them. You are required to release all your locks, even on the event of failures. + +```php +$timeout = 5; + +// A namespace for the locks. Must be prefixed with the component name to prevent conflicts. +$locktype = 'mod_assign_download_submissions'; + +// Resource key - needs to uniquely identify the resource that is to be locked. E.g. If you +// want to prevent a user from running multiple course backups - include the userid in the key. +$resource = 'user:' . $USER->id; + +// Get an instance of the currently configured lock_factory. +$lockfactory = \core\lock\lock_config::get_lock_factory($locktype); + +// Get a new lock for the resource, wait for it if needed. +if ($lock = $lockfactory->get_lock($resource, $timeout)) { + // We have exclusive access to the resource, do the slow zip file generation... + + if ($someerror) { + // Always release locks on failure. + $lock->release(); + print_error('blah'); + } + + // Release the lock once finished. + $lock->release(); + +} else { + // We did not get access to the resource in time, give up. + throw new moodle_exception('locktimeout'); +} +``` + +## Use a different lock type from the default + +Change the $CFG->lock_factory setting to one of the other lock types included with core. These are all documented in config-dist.php. + +## Implementing new lock types + +If you really want to do this you can. I probably wouldn't recommend it - because the core lock types should be very reliable - and the performance is not really a concern. + +Add a new local_XXX plugin with an autoloaded class that implements \core\lock\lock_factory. +Set the site configuration variable "lock_factory" to the full namespaced path to your class in the config.php for example + +```php +$CFG->lock_factory = '\local_redis\lock\redis_lock_factory'; +``` + +:::note + +See `lib/tests/lock_test.php` for an example of unit tests which can be run on a custom lock instance to verify it for correctness (run_on_lock_factory). + +::: diff --git a/general/releases/2.7.md b/general/releases/2.7.md index f659f05084..6347281d78 100644 --- a/general/releases/2.7.md +++ b/general/releases/2.7.md @@ -195,7 +195,7 @@ A result of this is that cron can be run much more often, which means (for examp - Logging and events: All plugins should convert their logging and triggering of events to the new API. See [Migrating logging calls in plugins](https://docs.moodle.org/dev/Migrating_logging_calls_in_plugins). - Reports: Reports that use log table should be updated to use the new logging framework. Old reports will continue to work as before as long as legacy logging is enabled in the site. See [Migrating log access in reports](https://docs.moodle.org/dev/Migrating_log_access_in_reports) for details. -- Developers can now use the [Lock API](https://docs.moodle.org/dev/Lock_API) to lock critical tasks (even across cluster nodes). +- Developers can now use the [Lock API](/docs/apis/core/lock/) to lock critical tasks (even across cluster nodes). - Plugins can now use the [Task API](https://docs.moodle.org/dev/Task_API) to schedule background tasks and developers are encouraged to convert to this API from legacy cron. - New plugin type for conditional availability. See [Availability conditions](https://docs.moodle.org/dev/Availability_conditions). - New plugin type for Atto editor. See [Atto](https://docs.moodle.org/dev/Atto) diff --git a/project-words.txt b/project-words.txt index ddabe5ffb6..efacbe54ce 100644 --- a/project-words.txt +++ b/project-words.txt @@ -220,6 +220,7 @@ pluginable plugininfo pluginname plugintype +plugintypes previewquestion privatefiles protectusernames @@ -251,6 +252,7 @@ splitview strftimedate strikethrough subplugin +subplugins tablespace tasklogs templatable