laminas / laminas-cache-storage-adapter-filesystem

BSD 3-Clause "New" or "Revised" License
7 stars 15 forks source link

LocalFilesystemInteraction: Asynchronous read and write calls can cause reading an empty string from cache file #98

Open RuesimOfCode opened 2 months ago

RuesimOfCode commented 2 months ago

Bug Report

Q A
Version(s) 2.4.1

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 by laminas/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 after fopen and before flock) Some micro- or milliseconds later the file is filled.

How to reproduce

I 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 (by Laminas\Cache\Storage\Adapter\Filesystem\LocalFilesystemInteraction::write).

Notes

RuesimOfCode commented 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:

As 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.

Xerkus commented 2 months ago

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