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

Command icon 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:

Comments

lisa.rae created an issue. See original summary.

lisa.rae’s picture

Status: Active » Needs review

ivnish changed the visibility of the branch 3617074-cron-leaves-dangling to hidden.

  • ivnish committed 7ed00c90 on 2.0.x authored by lisa.rae
    fix: #3617074 Cron leaves dangling message references when purging a...
ivnish’s picture

Status: Needs review » Fixed

Nice catch! Thanks!

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.