## Description Resolved conversations now preserve historical SLA misses without allowing their displayed duration to keep growing. Applied SLAs record a stable completion timestamp that is shared through REST and realtime payloads, and the dashboard freezes FRT, NRT, and RT misses at that point. Legacy completed SLAs without a reliable timestamp remain visible as a static missed state. Terminal SLAs remain frozen when a conversation is reopened; a reopen before finalization continues the same SLA without resetting its deadlines. ### Closes [CW-7597](https://linear.app/chatwoot/issue/CW-7597/freeze-sla-miss-durations-after-conversation-resolution) ## Type of change - [x] Bug fix (non-breaking change which fixes an issue) ## How to reproduce 1. Apply an SLA with a resolution-time threshold to a conversation. 2. Let the threshold breach, then resolve the conversation. 3. Observe that the recorded miss duration continues increasing every minute even though the conversation is resolved. ## What changed - Added nullable `applied_slas.completed_at` and exposed it as `sla_completed_at` in conversation, report, and websocket payloads. - Captured completion before broadcasting resolution and preserved it for terminal applied SLAs. - Frozen recorded FRT, NRT, and RT durations in classic and next-generation conversation labels, including a static fallback for legacy rows. - Added a dry-run-first, resumable Rails runner for account-scoped or explicitly global historical repair without enqueuing jobs or touching `updated_at`. Account-scoped production rollout starts with: ```sh ACCOUNT_ID=168154 bundle exec rails runner script/backfill_applied_sla_completed_at.rb ACCOUNT_ID=168154 APPLY=true bundle exec rails runner script/backfill_applied_sla_completed_at.rb ``` ## How Has This Been Tested? - Verified resolution stamping, nonterminal reopen clearing, and terminal reopen preservation. - Verified dry-run, apply, account/global scope, resume, skip, idempotency, and timestamp-preserving backfill behavior. - Verified all three miss types freeze and existing conversation-card behavior remains intact. - 71 focused RSpec examples and 37 focused Vitest examples pass. - RuboCop, ESLint, and diff checks pass. ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
31 lines
1.1 KiB
Ruby
31 lines
1.1 KiB
Ruby
# Backfill applied_slas.completed_at from conversation resolution reporting events.
|
|
#
|
|
# Account-scoped dry run:
|
|
# ACCOUNT_ID=168154 bundle exec rails runner script/backfill_applied_sla_completed_at.rb
|
|
#
|
|
# Account-scoped apply:
|
|
# ACCOUNT_ID=168154 APPLY=true bundle exec rails runner script/backfill_applied_sla_completed_at.rb
|
|
#
|
|
# Explicit global apply with resume controls:
|
|
# ALL_ACCOUNTS=true APPLY=true BATCH_SIZE=500 AFTER_ID=0 \
|
|
# bundle exec rails runner script/backfill_applied_sla_completed_at.rb
|
|
|
|
begin
|
|
account_id = Integer(ENV.fetch('ACCOUNT_ID'), 10) if ENV['ACCOUNT_ID'].present?
|
|
all_accounts = ENV['ALL_ACCOUNTS'] == 'true'
|
|
apply = ENV['APPLY'] == 'true'
|
|
batch_size = Integer(ENV.fetch('BATCH_SIZE', Sla::BackfillAppliedSlaCompletedAtService::DEFAULT_BATCH_SIZE.to_s), 10)
|
|
after_id = Integer(ENV.fetch('AFTER_ID', '0'), 10)
|
|
|
|
Sla::BackfillAppliedSlaCompletedAtService.new(
|
|
account_id: account_id,
|
|
all_accounts: all_accounts,
|
|
apply: apply,
|
|
batch_size: batch_size,
|
|
after_id: after_id
|
|
).perform
|
|
rescue ArgumentError, ActiveRecord::RecordNotFound => e
|
|
warn "Backfill aborted: #{e.message}"
|
|
exit 1
|
|
end
|