A thread-safe configuration manager extension for TYPO3 CMS that extends the core ConfigurationManager with built-in locking mechanisms to prevent race conditions during configuration read/write operations.
In TYPO3, the ConfigurationManager is responsible for managing system configurations.
However, in multiprocess environments (like web servers), concurrent access to configuration files can lead to race conditions, file corruption, or lost updates if not properly synchronized. This is especially problematic when multiple processes attempt to read from or write to the same configuration file at the same time.
The most obvious problem then is this core exception you might encounter randomly:
Uncaught TYPO3 Exception: TYPO3\CMS\Core\Configuration\ConfigurationManager::getLocalConfiguration(): Return value must be of type array, int returned | TypeError thrown in file /var/www/html/vendor/typo3/cms-core/Classes/Configuration/ConfigurationManager.php in line 121.
- Thread-safe configuration access: Uses TYPO3's built-in locking API to prevent race conditions
- Shared locks for reading: Multiple processes can read configuration simultaneously
- Exclusive locks for writing: Ensures only one process can modify configuration at a time
- Atomic writes: Uses temporary files and atomic moves to prevent corruption
- Configurable timeouts: Adjustable lock timeout with exponential backoff
- Compatible with TYPO3 13 LTS: Built specifically for TYPO3 CMS 13 and later
- Drop-in replacement: Seamlessly replaces the core ConfigurationManager
Add the extension to your TYPO3 project:
composer require plan2net/safe-config-manager
As the ConfigurationManager
is directly instantiated by TYPO3 through the new
keyword, you have you patch the core Bootstrap class to use the SafeConfigurationManager
instead.
You need the "cweagans/composer-patches" plugin to apply the patch automatically during installation in your composer based TYPO3 project.
Here's the required patch:
--- a/Classes/Core/Bootstrap.php
+++ b/Classes/Core/Bootstrap.php
@@ -17,6 +17,7 @@
namespace TYPO3\CMS\Core\Core;
use Composer\Autoload\ClassLoader;
+use Plan2net\SafeConfigManager\Configuration\SafeConfigurationManager;
use Composer\InstalledVersions;
use Doctrine\Common\Annotations\AnnotationReader;
use Psr\Container\ContainerInterface;
@@ -310,7 +311,12 @@ class Bootstrap
*/
public static function createConfigurationManager(): ConfigurationManager
{
- return new ConfigurationManager();
+ // Use SafeConfigurationManager if available, fallback to standard ConfigurationManager
+ if (class_exists(SafeConfigurationManager::class)) {
+ return new SafeConfigurationManager();
+ }
+
+ return new ConfigurationManager();
}
/**
composer.json
"extra": {
"patches": {
"typo3/cms-core": {
"Use SafeConfigurationManager for thread-safe configuration handling": "patches/typo3-cms-core-bootstrap-safe-config-manager.patch"
}
},
The SafeConfigurationManager uses TYPO3's LockingStrategyInterface to provide:
- Shared locks (LOCK_CAPABILITY_SHARED): For read operations (
getLocalConfiguration()
) - Exclusive locks (LOCK_CAPABILITY_EXCLUSIVE): For write operations (
writeLocalConfiguration()
,updateLocalConfiguration()
, etc.) - Non-blocking locks with timeout: Prevents deadlocks with configurable retry logic
All write operations use atomic file operations:
- Write to a temporary file
- Perform atomic rename to final location
- Clear opcache for the configuration file
- Clean up temporary files on failure
Different operations use unique lock identifiers to allow concurrent operations where safe:
safe_config_manager_read_*
: Shared locks for readingsafe_config_manager_write_*
: Exclusive locks for writingsafe_config_manager_update_*
: Exclusive locks for updatessafe_config_manager_setValue_*
: Exclusive locks for single value updatessafe_config_manager_setValues_*
: Exclusive locks for bulk updatessafe_config_manager_removeKeys_*
: Exclusive locks for key removal
Configure the default lock timeout in ext_localconf.php
or AdditionalConfiguration.php
:
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['safe_config_manager']['lockTimeout'] = 15; // seconds
You can configure which locking strategy to prefer:
// Prefer FileLockStrategy (default: 75)
$GLOBALS['TYPO3_CONF_VARS']['SYS']['locking']['strategies'][\TYPO3\CMS\Core\Locking\FileLockStrategy::class]['priority'] = 100;
// Configure custom lock directory
$GLOBALS['TYPO3_CONF_VARS']['SYS']['locking']['strategies'][\TYPO3\CMS\Core\Locking\FileLockStrategy::class]['lockFileDir'] = 'safe_config_locks';
- TYPO3 Version: 13.0+ (LTS)
- PHP Version: 8.1+
- Locking Strategies: All TYPO3 core locking strategies supported
- File Systems: Compatible with local and network file systems
If you see LockAcquireException
errors:
-
Increase the lock timeout:
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['safe_config_manager']['lockTimeout'] = 30;
-
Check for deadlocks in your configuration update logic
-
Monitor lock file directory permissions and disk space
-
Use appropriate locking strategy for your environment:
- Local filesystems: FileLockStrategy (default)
- Network filesystems: SemaphoreLockStrategy or SimpleLockStrategy
-
Avoid frequent configuration updates in tight loops
-
Use bulk operations (
setLocalConfigurationValuesByPathValuePairs
) instead of multiple single updates
GPL-2.0-or-later
plan2net GmbH - https://www.plan2.net