Problem/Motivation
PrivatemsgHooks::cron physically deletes messages that were marked deleted longer than the remove_after retention period. The deletion runs inside the loop over the threads that reference the message:
foreach ($threads as $thread) {
$thread->removeMessageFromThread($message->id());
$thread->save();
$message->delete(); // <-- deletes the entity on the FIRST iteration
}
A privatemsg_message is shared across all thread copies of a group. When the
message is referenced by more than one thread:
- The first iteration removes the reference and deletes the message entity.
- Every subsequent iteration still calls $thread->removeMessageFromThread($message->id()) and
$thread->save()on threads that reference a now-deleted entity, so those thread copies keep a dangling reference to the deleted message.
Result: after cron runs, some threads still reference a deleted message (orphaned privatemsg_thread__private_messages rows), which is a data-integrity problem.
Steps to reproduce
1. Create a group thread with 3 members (user1 sends to user2 and user3).
2. user2 replies; the reply message is shared across all three thread copies.
3. Mark that message deleted (e.g. via the delete link) and let remove_after pass, or set remove_after to a small value.
4. Run cron. The message entity is deleted, but two of the three thread copies still reference it (verified by loadByProperties(['private_messages' => $mid])).
Proposed resolution
Move $message->delete() outside the thread loop, so the message is
removed from every thread first and the entity is deleted only once afterwards:
foreach ($threads as $thread) {
$thread->removeMessageFromThread($message->id());
$thread->save();
}
// Delete the message only after it has been removed from every thread,
// otherwise the remaining threads keep referencing a deleted entity.
$message->delete();
This guarantees no thread retains a reference to the deleted message.
Remaining tasks
Patch with tests forthcoming.
Issue fork privatemsg-3617074
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
- Issue-3617074
changes, plain diff MR !68
- 3617074-cron-leaves-dangling
compare
Comments
Comment #3
lisa.rae commentedComment #6
ivnishNice catch! Thanks!