Open RuesimOfCode opened 2 months ago
Update:
After testing different szeanarios we came to the conclustion that only two ways to create a cache file would solve the issue in LocalFilesystemInteraction
's write method on our test environment:
LOCK_EX
flagAs workaround we managed to inject a modified LocalFilesystemInteractionInteface
to Filesystem
. We implemented the solution with random suffix in filename of a temporary file in the "non-blocking" code path.
advisory file locks do not work across all file systems and they are just that - advisory. It is still possible to read incomplete file.
Best approach would be to do atomic writes via file move
Bug Report
Summary
In our application multiple cron jobs running at the same time.
Circa every two hours (sporadically) we get an exception:
Serialized data must be a string containing serialized PHP code; received:
Current behavior
The exception occurs because
Laminas\Cache\Storage\Adapter\Filesystem::internalGetItem
returns an empty string which cannot be deserialized bylaminas/laminas-serializer/src/Adapter/PhpSerialize
later on.It turned out that cache files are created before filled and there is a short time slot where the file content is empty. (the time slot is in
Laminas\Cache\Storage\Adapter\Filesystem\LocalFilesystemInteraction::write
afterfopen
and beforeflock
) Some micro- or milliseconds later the file is filled.How to reproduce
serializer
is enabled.Laminas\Cache\Storage\Adapter\Filesystem\LocalFilesystemInteraction::write
beforeflock
is called the first time and afterchmod
is called (line 109 in 2.4.1).Serialized data must be a string containing serialized PHP code; received:
should occurI don't know if it would be possible to cover this case with a unit test (would require two asynchronous calls and a delay in
chmod
operation?)Expected behavior
Laminas\Cache\Storage\Adapter\Filesystem::internalGetItem
will always return with$success = false;
or with the file content and never with empty content as a consequence of the file beeing created but the content not written yet (byLaminas\Cache\Storage\Adapter\Filesystem\LocalFilesystemInteraction::write
).Notes
Laminas\Cache\Storage\Adapter\Filesystem::internalGetItem
before$success = true;
is called:$success = false;
if the file content is empty and theserialize
plugin is used (I don't know if an empty string is valid, if theserialize
plugin is not used). However, without theserialize
plugin an empty string could still be the result of a read/write bug.