Skip to content

fix: handle concurrent mkdir race condition in FileSystemCache#787

Merged
romm merged 3 commits intoCuyZ:masterfrom
sidigi:fix/cache-directory-mkdir-race-condition
Mar 1, 2026
Merged

fix: handle concurrent mkdir race condition in FileSystemCache#787
romm merged 3 commits intoCuyZ:masterfrom
sidigi:fix/cache-directory-mkdir-race-condition

Conversation

@sidigi
Copy link
Contributor

@sidigi sidigi commented Feb 26, 2026

Problem

When multiple workers (e.g., Laravel Octane, queue workers) start simultaneously, FileSystemCache::set() throws CacheDirectoryNotWritable due to a race condition.

The current code:

if (! is_dir($tmpDir) && ! @mkdir($tmpDir, 0777, true)) {
    throw new CacheDirectoryNotWritable($this->cacheDir);
}

Race condition scenario:

  1. Worker 1: is_dir($tmpDir)false@mkdir()true ✅ (created)
  2. Worker 2: is_dir($tmpDir)false@mkdir()false (already exists) → CacheDirectoryNotWritable 💥

@mkdir() suppresses the PHP warning but still returns false when the directory already exists. Without a second is_dir() check, a concurrent process that lost the race throws an exception even though the directory was successfully created by another process.

This issue was previously reported in #401 and partially addressed in #407 (warmup pre-creation), but the race condition in set() itself remains.

Note: This is especially problematic with Laravel, which converts PHP warnings to exceptions via set_error_handler — making @mkdir() insufficient on its own (related: #328).

Fix

Add the standard triple-check pattern used throughout PHP ecosystem for atomic directory creation:

if (! is_dir($tmpDir) && ! @mkdir($tmpDir, 0777, true) && ! is_dir($tmpDir)) {
    throw new CacheDirectoryNotWritable($this->cacheDir);
}

The third is_dir() check confirms the directory truly doesn't exist after mkdir() failure — distinguishing a genuine error (permissions, disk full) from a concurrent creation by another process.

Related

@sidigi
Copy link
Contributor Author

sidigi commented Feb 26, 2026

Sorry for LLM)

@romm romm merged commit 13f06d2 into CuyZ:master Mar 1, 2026
16 checks passed
@romm
Copy link
Member

romm commented Mar 1, 2026

Thank you for the PR. 😊

I'd have preferred a description written by hand, but at least you had the honesty to tell it was written by an LLM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants