Skip to content

fix: Tolerate a directory removed by a parallel request in Dir - #8511

Open
distantnative wants to merge 2 commits into
develop-patchfrom
fix/dir-scandir-race
Open

distantnative wants to merge 2 commits into
develop-patchfrom
fix/dir-scandir-race

Conversation

@distantnative

Copy link
Copy Markdown
Member

Review

  • Rough pass

Description

Dir::read() and Dir::removeRecursive() both check that a directory exists and then scandir() it. A parallel request can remove it in between, and the warning surfaces as an ErrorException.

Both now treat a failed scan as "already empty".

Probably a bit esoteric, but came up in the pressure tests against #8469.

Changelog

🐛 Bug fixes

  • Deleting a page or its changes in two requests at the same time no longer causes an error.

For review team

  • Add changes & docs to release notes draft in Notion

@distantnative distantnative added this to the 5.6.1 milestone Sep 22, 2026
@distantnative distantnative self-assigned this Sep 22, 2026
@distantnative
distantnative marked this pull request as ready for review September 22, 2026 11:58
@distantnative
distantnative requested a review from a team September 22, 2026 11:58
afbora
afbora previously approved these changes Sep 22, 2026

@afbora afbora left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@scandir() works, but it suppresses every warning from that call, not just the missing directory. I tested it: permission, not-a-directory, open file limits, all silenced, and Whoops stays quiet too since it checks the error_reporting mask. So if the dir is still there and the scan fails for another reason, we silently return empty. Maybe throw instead:

if ($items === false) {
	if (is_dir($dir) === true) {
		throw new Exception('The directory "' . $dir . '" could not be read');
	}

	return [];
}

Fine to approve as is though 👍

@distantnative

Copy link
Copy Markdown
Member Author

@afbora Wouldn't those what you describe already fail on the is_dir($dir) above?

@afbora

afbora commented Sep 22, 2026

Copy link
Copy Markdown
Member

@distantnative Not all of them. Tested on Windows: removed the read permission from a directory and is_dir() was still true while scandir() returned false.

@distantnative

Copy link
Copy Markdown
Member Author

@afbora What do you think about using Helpers::handleErrors() like this?

@afbora

afbora commented Sep 22, 2026

Copy link
Copy Markdown
Member

@distantnative I know new cases popping up isn't great, but returning [] instead of throwing causes a regression when Whoops isn't there. If the directory still exists but can't be read, it counts as empty, isEmpty() returns true and _drafts, _changes or even the page folder itself gets removed. The first version of the PR had it too, even with Whoops on because of the @. If we make the fallback [] and throw on false, the content seems to be kept in both modes. Could you confirm?

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants