Handling a ticket that contains MANY comments

Hello all,

Question: How should I best handle a ticket with multiple comments? By multiple, I mean 400+.

Here’s the background. Our helpdesk had to deal w/ a widespread outage. Tons upon tons of ppl were calling in for the entire day. They decided they needed to log all these calls, so they created on ticket, named for this example “outage”. Everytime someone called in, they would open the “outage” ticket and put a quick “advised user of outage” in the ticket. However, once the ticket started growing into the hundreds of comments, it would nearly lock the server up when someone would access it. The CPU would peg out while the page was loaded, which would take roughly 2 minutes… and with probably a new person trying to access the ticket every 15 seconds, you could see how this was a problem. It brought the entire ticketing system to something of a standstill.

My question to you guys is how do I avoid something like this moving forward in the future?

I hit the same problem a few months ago. I came up with a patch which helps with one slightly inefficient part of the code. Jesse has already taken the patch into 3.9/4.0, but it isn’t in 3.8.x. The mailing list post which details the patch is here:

http://lists.bestpractical.com/pipermail/rt-users/2010-September/066454.html

You should find it helps a lot with these large tickets. I had some tickets with more than 2000 transactions which were impossible to view before this patch was put in place.

Tim

The Wellcome Trust Sanger Institute is operated by Genome Research
Limited, a charity registered in England with number 1021457 and a
company registered in England with number 2742969, whose registered
office is 215 Euston Road, London, NW1 2BE.

Some time ago for this case I have gotten the following Perl optimization:
small ticket (1-3 comments) ~3-7% speed-up
large ticket ~38-39% speed-up
huge ticket ~45-47% speed-up

So, I got an average of 35% speed-up per ticket as they are usually large.
Main points - avoid needless iterations in grep/map cycles and avoid
needless $Transaction->Id() calls (it was done using hashes).

Perhaps it will be helpful for someone

Base RT version: 3.8.4
Modified ShowHistory file is attached and here is the diff:

diff -u /usr/local/rt3/share/html/Ticket/Elements/ShowHistory
/usr/local/rt3/local/html/Ticket/Elements/ShowHistory
— /usr/local/rt3/share/html/Ticket/Elements/ShowHistory 2010-09-06
10:31:37.000000000 +0300
+++ /usr/local/rt3/local/html/Ticket/Elements/ShowHistory 2011-04-12
15:28:44.000000000 +0300
@@ -82,10 +82,31 @@

<%perl> -my @attachments = @{$Attachments->ItemsArrayRef()}; -my @attachment_content = @{$AttachmentContent->ItemsArrayRef()}; +my $attachments = \@{ $Attachments->ItemsArrayRef() }; +my $attachment_content = \@{ $AttachmentContent->ItemsArrayRef() };

-while ( my $Transaction = $Transactions->Next ) {
+my %attachments_hash = ();
+my %attachment_content_hash = ();
+for (my $i = 0; $i <= scalar(@{$attachments}); $i++) {

  •   next unless ($attachments->[$i]);
    
  •   my $attach_transactionId = $attachments->[$i]->TransactionId();
    
  •   if ( $attachments_hash{ $attach_transactionId } ) {
    
  •           my $j = scalar( @{$attachments_hash{ 
    

$attach_transactionId }} );

  •           $attachments_hash{ $attach_transactionId }[$j] = 
    

$attachments->[$i];

  •   } else {
    
  •           $attachments_hash{ $attach_transactionId }[0] = 
    

$attachments->[$i];

  •   }
    

+}
+for (my $i = 0; $i <= scalar(@{$attachment_content}); $i++) {

  •   next unless ($attachment_content->[$i]);
    
  •   my $attach_cont_transactionId = 
    

$attachment_content->[$i]->TransactionId();

  •   $attachment_content_hash{ $attach_cont_transactionId }[0] = 
    

$attachment_content->[$i]->Id();

  •   $attachment_content_hash{ $attach_cont_transactionId }[1] = 
    

$attachment_content->[$i];
+}
+while ( my $Transaction = $Transactions->Next() ) {
my $skip = 0;
$m->callback(
%ARGS,
@@ -96,16 +117,17 @@
next if $skip;

   $i++;
  • my @trans_attachments = grep { $_->TransactionId ==
    $Transaction->Id } @attachments;
  • my $transaction_id = $Transaction->Id();
  •   my @trans_attachments = @{ $attachments_hash{ $transaction_id } 
    

} if ($attachments_hash{ $transaction_id });

   my $trans_content = {};
  • grep { ($->TransactionId == $Transaction->Id ) &&
    ($trans_content->{$
    ->Id} = $_) } @attachment_content;
  • $trans_content->{ $attachment_content_hash{ $transaction_id }[0] }
    = $attachment_content_hash{ $transaction_id }[1];

    my $IsLastTransaction = 0;
    if ( $OldestFirst ) {

  •    $IsLastTransaction = $Transactions->IsLast;
    
  •    $IsLastTransaction = $Transactions->IsLast();
     } else {
         $IsLastTransaction = 1 if ( $i == 1 );
     }
    

@@ -128,6 +150,8 @@
$m->flush_buffer();
}

+%attachments_hash = ();
+%attachment_content_hash = ();
</%perl>

% if ($ShowDisplayModes or $ShowTitle) { @@ -138,13 +162,29 @@ my $Transactions = new RT::Transactions($session{'CurrentUser'}); if ($Tickets) { while (my $t = $Tickets->Next) { - $Transactions->LimitToTicket($t->id); + if ( $t->id == $Ticket->id ) { + #$Transactions->LimitToTicket($t->id); + my $trs = RT::Transactions->new( $session{'CurrentUser'} ); + $trs->LimitToTicket( $t->id ); + $trs->LimitToTicket($t->id); + while ( my $tr = $trs->Next ) { + $Transactions->Limit( FIELD => 'id', VALUE => $tr->id, ENTRYAGGREGATOR => 'OR' ); + } + } else { + my $trs = RT::Transactions->new( $session{'CurrentUser'} ); + $trs->LimitToTicket( $t->id ); + $trs->Limit( FIELD => 'Type', VALUE => 'Create', ENTRYAGGREGATOR => 'OR' ); + $trs->Limit( FIELD => 'Type', VALUE => 'Correspond', ENTRYAGGREGATOR => 'OR' ); + #$trs->Limit( FIELD => 'Type', VALUE => 'EmailRecord', ENTRYAGGREGATOR => 'OR' ); + while ( my $tr = $trs->Next ) { + $Transactions->Limit( FIELD => 'id', VALUE => $tr->id, ENTRYAGGREGATOR => 'OR' ); + } + } } } else { $Transactions = $Ticket->Transactions; }

my $OldestFirst = RT->Config->Get( ‘OldestTransactionsFirst’,
$session{‘CurrentUser’} );
my $SortOrder = $OldestFirst? ‘ASC’: ‘DESC’;
$Transactions->OrderByCols( { FIELD => ‘Created’,

Yours sincerely,

Igor Melnichuk
PortaOne, Inc.

ShowHistory.zip (2.6 KB)