From cdcfda73e8e5d3269894b5e6815ed9e0465be507 Mon Sep 17 00:00:00 2001 From: Vishnu Narayanan Date: Thu, 3 Apr 2025 20:49:36 +0530 Subject: [PATCH] perf: improve contact delete performance --- app/models/contact.rb | 2 +- .../internal/remove_stale_contacts_service.rb | 27 ++++++++++++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/app/models/contact.rb b/app/models/contact.rb index 83920d9fc..62bdb96b5 100644 --- a/app/models/contact.rb +++ b/app/models/contact.rb @@ -137,7 +137,7 @@ class Contact < ApplicationRecord .where('contacts.phone_number IS NULL OR contacts.phone_number = ?', '') .where('contacts.identifier IS NULL OR contacts.identifier = ?', '') .where('contacts.created_at < ?', time_period) - .where.missing(:conversations) + .where('NOT EXISTS (SELECT 1 FROM conversations WHERE conversations.contact_id = contacts.id)') } def get_source_id(inbox_id) diff --git a/app/services/internal/remove_stale_contacts_service.rb b/app/services/internal/remove_stale_contacts_service.rb index 74e189068..31de9c5cb 100644 --- a/app/services/internal/remove_stale_contacts_service.rb +++ b/app/services/internal/remove_stale_contacts_service.rb @@ -2,18 +2,31 @@ class Internal::RemoveStaleContactsService pattr_initialize [:account!] def perform(batch_size = 1000) - contacts_to_remove = @account.contacts.stale_without_conversations(30.days.ago) - total_deleted = 0 - Rails.logger.info "[Internal::RemoveStaleContactsService] Starting removal of stale contacts for account #{@account.id}" - contacts_to_remove.find_in_batches(batch_size: batch_size) do |batch| - contact_ids = batch.map(&:id) + # Get the stale contacts query + stale_contacts = @account.contacts.stale_without_conversations(30.days.ago) + total_deleted = 0 + + # Get only IDs in batches without loading full records + stale_contacts.select(:id).in_batches(of: batch_size) do |relation| + # Use pluck to get only the IDs + contact_ids = relation.pluck(:id) + next if contact_ids.empty? + + # Delete associated contact_inboxes first ContactInbox.where(contact_id: contact_ids).delete_all + + # Then delete the contacts Contact.where(id: contact_ids).delete_all - total_deleted += batch.size - Rails.logger.info "[Internal::RemoveStaleContactsService] Deleted #{batch.size} contacts (#{total_deleted} total) for account #{@account.id}" + + total_deleted += contact_ids.size + Rails.logger.info "[Internal::RemoveStaleContactsService] Deleted #{contact_ids.size} contacts " \ + "(#{total_deleted} total) for account #{@account.id}" end + + Rails.logger.info "[Internal::RemoveStaleContactsService] Completed removal of #{total_deleted} stale contacts " \ + "for account #{@account.id}" end end