use counter culture and move the optimisation under feature flag

This commit is contained in:
Tanmay Deep Sharma
2026-02-03 20:26:03 +05:30
parent 6a053e975e
commit 6e85dcbbce
10 changed files with 69 additions and 20 deletions
+1
View File
@@ -12,6 +12,7 @@ gem 'bootsnap', require: false
gem 'acts-as-taggable-on'
gem 'attr_extras'
gem 'browser'
gem 'counter_culture'
gem 'hashie'
gem 'jbuilder'
gem 'kaminari'
+4
View File
@@ -191,6 +191,9 @@ GEM
commonmarker (0.23.10)
concurrent-ruby (1.3.5)
connection_pool (2.5.3)
counter_culture (3.12.1)
activerecord (>= 4.2)
activesupport (>= 4.2)
crack (1.0.0)
bigdecimal
rexml
@@ -1039,6 +1042,7 @@ DEPENDENCIES
byebug
climate_control
commonmarker
counter_culture
csv-safe
database_cleaner
datadog (~> 2.0)
+19 -1
View File
@@ -2,6 +2,9 @@ class ConversationFinder
attr_reader :current_user, :current_account, :params
DEFAULT_STATUS = 'open'.freeze
# Filter params that affect conversation count
# NOTE: When adding a new filter, add it here to prevent incorrect cache usage
FILTER_PARAMS = %i[inbox_id team_id labels q source_id conversation_type].freeze
SORT_OPTIONS = {
'last_activity_at_asc' => %w[sort_on_last_activity_at asc],
'last_activity_at_desc' => %w[sort_on_last_activity_at desc],
@@ -167,10 +170,25 @@ class ConversationFinder
end
def set_count_for_all_conversations
# Check if filtering by status only (no other filters applied)
filtering_by_status_only = FILTER_PARAMS.none? { |key| params[key].present? }
# Use cache if feature is enabled, filtering by status only, and status is not 'all'
use_cache = current_account.feature_enabled?(:counter_cache_optimization) &&
filtering_by_status_only &&
params[:status] != 'all'
all_count = if use_cache
status = params[:status] || DEFAULT_STATUS
current_account.public_send("#{status}_conversations_count")
else
@conversations.count
end
[
@conversations.assigned_to(current_user).count,
@conversations.unassigned.count,
current_account.conversations_count
all_count
]
end
+3 -1
View File
@@ -97,7 +97,9 @@ class Conversation < ApplicationRecord
).sort_on_last_user_message_at
}
belongs_to :account, counter_cache: true
belongs_to :account
counter_culture :account,
column_name: proc { |model| "#{model.status}_conversations_count" }
belongs_to :inbox
belongs_to :assignee, class_name: 'User', optional: true, inverse_of: :assigned_conversations
belongs_to :assignee_agent_bot, class_name: 'AgentBot', optional: true
+4
View File
@@ -241,3 +241,7 @@
display_name: Required Conversation Attributes
enabled: false
premium: true
- name: counter_cache_optimization
display_name: Counter Cache Optimization
enabled: false
chatwoot_internal: true
@@ -1,5 +0,0 @@
class AddConversationsCountToAccounts < ActiveRecord::Migration[7.1]
def change
add_column :accounts, :conversations_count, :integer, default: 0, null: false
end
end
@@ -1,11 +0,0 @@
class BackfillConversationsCount < ActiveRecord::Migration[7.1]
def up
Account.find_each do |account|
Account.reset_counters(account.id, :conversations)
end
end
def down
# No-op
end
end
@@ -0,0 +1,8 @@
class AddStatusConversationCountersToAccounts < ActiveRecord::Migration[7.1]
def change
add_column :accounts, :open_conversations_count, :integer, default: 0, null: false
add_column :accounts, :resolved_conversations_count, :integer, default: 0, null: false
add_column :accounts, :pending_conversations_count, :integer, default: 0, null: false
add_column :accounts, :snoozed_conversations_count, :integer, default: 0, null: false
end
end
@@ -0,0 +1,25 @@
class BackfillStatusConversationCounters < ActiveRecord::Migration[7.1]
def up
Account.find_each do |account|
# Count conversations by status for this account
open_count = account.conversations.open.count
resolved_count = account.conversations.resolved.count
pending_count = account.conversations.pending.count
snoozed_count = account.conversations.snoozed.count
# Update the counter cache columns
# rubocop:disable Rails/SkipsModelValidations
account.update_columns(
open_conversations_count: open_count,
resolved_conversations_count: resolved_count,
pending_conversations_count: pending_count,
snoozed_conversations_count: snoozed_count
)
# rubocop:enable Rails/SkipsModelValidations
end
end
def down
# No-op
end
end
+5 -2
View File
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.1].define(version: 2026_02_03_062518) do
ActiveRecord::Schema[7.1].define(version: 2026_02_03_125200) do
# These extensions should be enabled to support this database
enable_extension "pg_stat_statements"
enable_extension "pg_trgm"
@@ -73,7 +73,10 @@ ActiveRecord::Schema[7.1].define(version: 2026_02_03_062518) do
t.integer "status", default: 0
t.jsonb "internal_attributes", default: {}, null: false
t.jsonb "settings", default: {}
t.integer "conversations_count", default: 0, null: false
t.integer "open_conversations_count", default: 0, null: false
t.integer "resolved_conversations_count", default: 0, null: false
t.integer "pending_conversations_count", default: 0, null: false
t.integer "snoozed_conversations_count", default: 0, null: false
t.index ["status"], name: "index_accounts_on_status"
end