Repository navigation
fix(laravel): don't cache metadata read from a missing table - #8586
Merged
Merged
Conversation
ModelMetadata already refused to keep the attributes of a missing table, but the three cache decorators above it stored whatever they got with rememberForever, in a file store in production. A worker booting during a migration then served the degraded metadata forever. ModelMetadata now counts the reads that found no table. The decorators compare that count around the inner call and skip both the persistent store and the in-memory cache when it moved, so the next call reads the table again. Fixes api-platform#8585
soyuka
reviewed
Sep 28, 2026
| } | ||
|
|
||
| $store->forever($key, $propertyMetadata); | ||
|
|
Member
There was a problem hiding this comment.
this code is duplicated in 3 classes maybe worth a trait ?
Contributor
Author
There was a problem hiding this comment.
Good call, done in 4401df1: MetadataCacheTrait::cached() now holds the lookup and the missing-table guard, and each factory only builds its key and the call to the decorated factory.
Member
|
Thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #8585
Summary
Follows the suggested fix: the three Laravel cache decorators get the guard
ModelMetadata::getAttributes()already has.The decorators cannot tell a degraded result from a legitimate one by looking at it (an empty property list or a property without a type is valid for some models), so the signal comes from where the degradation happens:
ModelMetadata(@internal) counts the attribute reads that found no table, in the existing guard branch.CachePropertyNameCollectionMetadataFactory,CachePropertyMetadataFactoryandCacheResourceCollectionMetadataFactorytake theModelMetadatasingleton as an optional last argument, read that count before and after the inner call, and when it moved they return the result without storing it, neither in the store nor in their in-memory cache. The next call, in this process or a new worker, reads the table again.A lookup served from the store does not touch the table, so there is no extra query once the metadata is cached, and nothing changes for a model whose table exists. With a metadata dump (
api-platform.metadata_dump), the dumped models are answered from the seeded attributes and never reach the guard.As the issue says, the routes registered by the boot that saw the missing table are still wrong for that process. The failure is now transient: the next worker start after the migration resolves the metadata correctly.
Test plan
src/Laravel/Tests/Metadata/CacheMetadataFactoriesMissingTableTest.phpsimulates two workers sharing the store (a new factory chain and a newModelMetadataeach): the first one boots while the table is missing, the table is created, the second one must see its columns.4.4(the second worker gets the degraded value from the store) and pass with the fix.CustomExceptionHandlerTestones, which fail the same way on4.4without this change.