Do nested Livewire components inherit the parent's #[Locked] attribute or acquire independent locks?
0 reputation · 06 Sept 2024, 16:03 UTC
0 reputation · 06 Sept 2024, 16:03 UTC
Livewire v3 introduced the #[Locked] attribute and withoutLock() method to control request serialization per component. However, the documentation does not specify the locking behavior when a parent component marked #[Locked] renders child components via @livewire('child', key($id)).
Each nested component generates its own lock key (livewire:component:{id}:lock) based on its component ID. The parent lock is acquired in HandleComponentRequests::ensureComponentIsNotAlreadyRunning() before the parent's update cycle, but it is unclear whether the framework automatically extends that lock to cover child updates triggered during the same request, or whether each child independently attempts to acquire its own mutex.
This matters for latency and correctness: if children acquire independent locks, concurrent updates to a parent and its children can interleave, potentially causing stale reads on public properties passed down as data attributes. If the parent lock is implicitly held for the entire render tree, then a slow child update serializes all siblings and the parent, increasing tail latency.
Does a parent component's #[Locked] attribute implicitly serialize updates to nested child components, or must each child explicitly declare #[Locked] to participate in the same critical section? Which approach does the current v3 implementation take, and is the behavior guaranteed or subject to change?
31775 reputation · 07 Sept 2024, 03:19 UTC
A parent's #[Locked] attribute does not implicitly serialize updates to its nested child components. Locking in Livewire v3 is scoped to the individual component instance: each component that declares #[Locked] acquires its own mutex, keyed off that component's ID, for the duration of its own update request. A child rendered via @livewire('child', key($id)) is an independent unit of state and execution; it must declare #[Locked] itself to ensure its own updates are serialized.
The architectural fact is that Livewire processes component updates as separate requests (or separately addressed updates), and the lock key is derived from the component's own identity—following the livewire:component:{id}:lock pattern. Because the key is per-ID, there is no mechanism for a parent's mutex to cover a child with a different ID. There is no evidence in the framework design of tree-wide lock inheritance.
The part to treat as likely but requiring version-specific verification is the exact acquisition point in HandleComponentRequests and whether any edge case (such as a child update bundled into a parent's request payload) shares the parent's critical section. Livewire v3 internals have evolved across minor releases; treat per-component locking as the current implementation rather than a permanent contractual guarantee.
#[Locked] to the child or avoid sharing mutable state across the boundary by treating the child as the owner of its internal state.#[Locked] to every component in a deep tree can increase tail latency, as concurrent child updates will serialize per component. Apply it only where concurrent mutation of the same component's state is possible.#[Locked], then fire two rapid updates at a child (e.g., double-click a button triggering a slow server-side action with an artificial sleep(2)).#[Locked] on the child. The second request should now queue behind the first.vendor/livewire/livewire source—search for mutex/cache-lock logic in the request-handling pipeline to confirm the key incorporates the component ID.One caveat: if child updates are triggered by events the child dispatches that the parent listens to, the parent's re-render is a separate concern. Event-driven re-renders do not transfer locks in either direction. To provide a more precise source-level reference, please provide your exact Livewire version (e.g., 3.x minor).
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.